Skip to main content
Removed the Dijkstra algorithm from here which i have added as another answer
Source Link
Dunlop
  • 4.3k
  • 5
  • 29
  • 43

Graph Based Algorithm (Dijkstra)

One algorithm that already gives an approximation to the shortest path (which approximates a geodesic), is the algorithm already implemented in Mathematica for testing shortest paths in graphs (FindShortestPath[] see Documentation or the implementation by Quantum Oli here). By treating the mesh as a graph one can get an estimate for the shortest path confined to go along edges. This is ok for an estimate, however gives something akin to a “triangular-Manhattan” distance on the mesh rather than the minimal distance and the geodesic. This can be implemented as follows:

a = BoundaryDiscretizeRegion[Ball[{0, 0, 0}, 1], 
   MaxCellMeasure -> {"Length" -> 1}, PrecisionGoal -> 3];
pts = MeshCoordinates[a];
edges = MeshCells[a, 1] /. Line[p_] :> p ;
tri = MeshCells[a, 2] /. Polygon[p_] :> p;
g = Graph[edges, GraphHighlight -> {1, 20}, 
   EdgeWeight -> PropertyValue[{a, 1}, MeshCellMeasure]];
path = PathGraph@FindShortestPath[g, 1, 20];
HighlightGraph[g, path]
Show[{a, Graphics3D[{Thick, Red, Line[pts[[VertexList[path]]]]}], 
  Graphics3D[{Black, Ball[pts[[{1, 20}]], 0.01]}]}, Axes -> True]

and gives as an example path:

Graph based "geodesic"

Note the kink in the path, hinting at the approximate nature of this algorithm.

Exact Line of Sight algorithm

Graph Based Algorithm (Dijkstra)

One algorithm that already gives an approximation to the shortest path (which approximates a geodesic), is the algorithm already implemented in Mathematica for testing shortest paths in graphs (FindShortestPath[] see Documentation or the implementation by Quantum Oli here). By treating the mesh as a graph one can get an estimate for the shortest path confined to go along edges. This is ok for an estimate, however gives something akin to a “triangular-Manhattan” distance on the mesh rather than the minimal distance and the geodesic. This can be implemented as follows:

a = BoundaryDiscretizeRegion[Ball[{0, 0, 0}, 1], 
   MaxCellMeasure -> {"Length" -> 1}, PrecisionGoal -> 3];
pts = MeshCoordinates[a];
edges = MeshCells[a, 1] /. Line[p_] :> p ;
tri = MeshCells[a, 2] /. Polygon[p_] :> p;
g = Graph[edges, GraphHighlight -> {1, 20}, 
   EdgeWeight -> PropertyValue[{a, 1}, MeshCellMeasure]];
path = PathGraph@FindShortestPath[g, 1, 20];
HighlightGraph[g, path]
Show[{a, Graphics3D[{Thick, Red, Line[pts[[VertexList[path]]]]}], 
  Graphics3D[{Black, Ball[pts[[{1, 20}]], 0.01]}]}, Axes -> True]

and gives as an example path:

Graph based "geodesic"

Note the kink in the path, hinting at the approximate nature of this algorithm.

Exact Line of Sight algorithm

Exact Line of Sight algorithm

Edited to remove the Dijkstra algorithm to a separate answer
Source Link
Dunlop
  • 4.3k
  • 5
  • 29
  • 43

It took me quite a while, but now have something that seems to work albeit very slowly.

Indeed as @Szalbolcs says there are many such algorithms already implemented in other languages (e.g. in Matlab). However for my understanding and for combining this with other codes I would like to have the algorithm operating already written inside Mathematica. My guess is that in the long run, other programming languages could be much faster (and indeed there are other algorithms much faster but not necessarily as exact as this one) but still itHere is a fun exercise to try in Mathematica, and may be useful to others.

I have two algorithms "working" now, one rather trivial (Dijkstra style algorithm ) and the other an exact algorithm but heavier to implement and to optimise. I chose to implement the "Line of Sight Algorithm" from Balasubramanian, Polimeni and Schwartz (REF).

It took me quite a while, but now have something that seems to work albeit very slowly.

Indeed as @Szalbolcs says there are many such algorithms already implemented in other languages (e.g. in Matlab). However for my understanding and for combining this with other codes I would like to have the algorithm operating already written inside Mathematica. My guess is that in the long run, other programming languages could be much faster (and indeed there are other algorithms much faster but not necessarily as exact as this one) but still it is a fun exercise to try in Mathematica, and may be useful to others.

I have two algorithms "working" now, one rather trivial (Dijkstra style algorithm ) and the other an exact algorithm but heavier to implement and to optimise. I chose to implement the "Line of Sight Algorithm" from Balasubramanian, Polimeni and Schwartz (REF).

Here is an exact algorithm but heavier to implement and to optimise. I chose to implement the "Line of Sight Algorithm" from Balasubramanian, Polimeni and Schwartz (REF).

deleted 168 characters in body
Source Link
Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k
losAlgorithm[mesh_] := 
  Module[{mesh0 = mesh, pts, nvertices, edges, tri, va, edgelengths, 
    distMatrix, tchainlists, \[CapitalDelta]\[Theta]precΔθprec, vtrilist, 
    ntri, tl3dstore, tnum, eAB, vA, vB, vD, vS, e1, e2, el, 
    vertmeshlabels, vertex2Dcoords, trilist2D, trichain3Dlabels, 
    trilabel, trilabel0, coordsA, coordsB, coordsD, 
    ang, \[Theta]θ, \[Theta]minθmin, \[Theta]maxθmax, vnum2D, tchainstack, 
    doubletri, boundaryEdgeQ, tpop, trichainnum, vectAB, angAB, 
    angBAD, e3, el3, \[Delta]SDδSD, outMatrix, \[Theta]MatrixθMatrix, tMatrix, 
    distMatrixsym},
   (**************************)
   (*Numerical Parameters*)
   (**************************)      
   dthetaprec =  0.05; (*Precision in Theta max - Theta min , 
   perhaps can be removed at somestage but at the moment useful for testing*) 
   (**************************)
   (*Mesh Calculations*)
   (**************************)

   (*List of coordinates of all vertices on the mesh*)
   
   pts = MeshCoordinates[mesh];
   (*Number of vertices on the mesh*)
   nvertices = Length[pts];
   (*List of all edges on the mesh, 
   in terms of pairs of vertex indices*)
   
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   (*List of the "ordered" vertex index triples for all triangles on the mesh*)
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p; 
   (*List of edgelengths numbered by edge *)
   
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   (*List of the angles within each of the corners of all triangles on the mesh*)
   
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   (**************************)
   (*Preparation of data structures for storage*)
   (**************************)
   (*Matrix to store all distances between all pairs of vertices*)
   
   distMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all angles between pairs of vertices*)
   
   ThetaMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all triangle chains (in 3D labelling) between pairs of vertices*)
   
   tMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   
   (**************************)
   (*Start of Algorithm*)
   (**************************)

   (********)
   (*Step 1 - 
   Choose a vertex vS on the mesh (Here we map over all Vertices) *)
 
   (********)
   Do[
    (********)
    (*Step 2 - 
    Choose a triangle containing vS as a vertex*)
    (********)
    
   (*Create a list of triangles around the vertex vS*)
    
    vtrilist = Position[tri, vS];
    (*Number of triangles around vertex S*)
    
    ntri = Length[vtrilist];
    (*Choose the first triangle in the list*)
    tnum = 1;
    (*While Loop to be performed over all triangles around vertex S*)
    (**********************)
    (******
    while loop here******)
    (**********************)
    
    While[tnum < ntri,
     Label[step2];
     If[tnum == ntri + 1, Break[]];
     (*Calculate ordered list of vertices A and B assuming we have outward oriented facets*)
     
     eAB = tri[[
        vtrilist[[tnum]][[1]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
     vA = eAB[[1]]; (*Set vertex A*)
     vB = eAB[[2]]; (*Set vertex B*)
     (*Calculate labels of the vertices of first two edges*)
     e1 = {vA, vS};
     e2 = {vB, vS};
     (*Calculate edge lengths for the first triangle in the chain(s)*)

          el = edgelengths[[Join[Flatten[Position[edges, e1 | Reverse[e1]]],Flatten[Position[edges, e2 | Reverse[e2]]]]]];
     (*Store the edge length data in the distance matrix*)
     
     distMatrix[[vS, vA]] = el[[1]];
     distMatrix[[vS, vB]] = el[[2]];
     (*Create a set of (temporary) lists which will hold information about vertexlabels, 
     coordinates etc*)
     (*Lists will be stored (perhaps in tMatrix etc), 
     whenever a new triangle chain is created*)
     (*Probably this information is not needed in the final algorithm, 
     but will be needed for debugging*)
     
     (*List of the vertex labels from the original mesh in the triangle chain*)
     vertmeshlabels = {}; 
     (*List of the 2D transformed coordinates of the vertices*)
     
     vertex2Dcoords = {}; 
     (*List of the vertex triples that make up each flattened triangle chain in 2D*)
     trilist2D = {}; 
     (*List of 3D face triangle labels from the mesh in the triangle chain*)
     
     trichain3Dlabels = {};
     (*label of current triangle in the triangle chain *)
     
     trilabel = vtrilist[[tnum]][[1]]; 
     (*Set previous triangle label to the current one (used for later calculations) *)
     trilabel0 = trilabel;
     (*Add the first triangle label to the list of 3D triangle(face) labels in the chain*)
     
     trichain3Dlabels = {trichain3Dlabels, trilabel};
     (*Map first triangle in the chain to the plane*)
     (*Origin Vertex vS*)
     (*Add vS mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vS};
     (*Add vS 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, {0, 0}};
     (*Vertex vA *)
     (*Add vA mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vA};
     coordsA = {el[[1]], 0};  (*Calculate 2D flattened coordinates of vertex vA*)
     
     (*Add vA 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsA};
     (*Vertex vB *)
     (*Add vB mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vB};
     ang = va[[vtrilist[[tnum]][[1]], vtrilist[[tnum]][[2]]]];
     coordsB = {el[[2]]*Cos[ang], el[[2]]*Sin[ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
  
     (*Add vB 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsB};
     (*Add the ordered triple of vertices to the 2D triangle list*)
  
        trilist2D = {trilist2D, {1, 2, 3}};
     thetamin = 0; (*Set min angle to be 0*)
     thetamax = ang; (*Set max angle to be the angle <BSA*)
     
     (********)
     (*Step 3*)
     (********)
     (*Counter of number of 2D vertices in triangle chain, will be reset everytime we do a new chain? starts at vertex 4*)
 
     vnum2D = 4;
     (*Initialise chain stack to enable chain branching, this first starts off as being empty*)
     (*What we also want to do is to rebuild a new chain stack for each branch *)
     
     tchainstack = {};
     (********)
     (*Step 4*)
     (********)
     
     doubletri = 0; (*Label = 0 if triangles not repeated in chain, = 1 if repeated*)
     
     nextensions = 1; (*Max number of extensions of triangle chain within one chain*)
     While[nextensions < 10000,
      Label[step4];
      (*BoundaryQ - Returns False if edge NOT a boundary, 
      True only 1 tri is attached to  edge vA -> vB*)
      
      boundaryEdgeQ = Intersection[Position[tri, vA][[All, 1]], Position[tri, vB][[All, 1]]] != 2; 
      (*Calculate whether we are within machine precision or not \
thetamax-thetamin< dthetaprec*)
      
      If[(thetamax - thetamin < dthetaprec) || 
        boundaryEdgeQ || (doubletri == 1),
       If[(tchainstack == {}),
         tnum++;
         Goto[step2],(*picknewtriangle*)
         {tpop, tchainstack} = {#, {##2}} & @@ tchainstack;
         (*newstructure of tchainstack*)
         
         tchainstack = tchainstack[[1]];
         (*to reset values so that we go down other chains*)
         (*Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
         trilabel0 = tpop[[1]];
         vA = tpop[[2]];
         vB = tpop[[3]];
         coordsA = tpop[[4]];
         coordsB = tpop[[5]];
         thetamin = tpop[[6]];
         thetamax = tpop[[7]];
         vnum2D = tpop[[8]];
         (*here we store the previous tchainlist for plotting*)
      
         vertmeshlabels =  Flatten[vertmeshlabels]; (*Flatten the linked list created previously*)
         
         trichain3Dlabels = Flatten[trichain3Dlabels];(*Flatten the linked list created previously*)
         
         vertex2Dcoords = Partition[Flatten[vertex2Dcoords],2];(*Flatten the linked list created previously*)
         
         trilist2D = 
          Partition[Flatten[trilist2D], 3];(*Flatten the linked list created previously*)
         (*now we need to go back in the list and "restart" so to say the counters*)
         (*need to reset the storage, and also the vnum2D otherwise we wont have diff chains, mainly important for plotting, but probably stops labelling effects*)
         
         trichainnum = Position[trichain3Dlabels, trilabel0][[1, 1]];
         trichain3Dlabels = Take[trichain3Dlabels, trichainnum];
         vertmeshlabels = Take[vertmeshlabels, vnum2D - 1];
         trilist2D = Take[trilist2D, trichainnum];
         vertex2Dcoords = Take[vertex2Dcoords, vnum2D - 1];
         (*Reset doubled triangle label to zero *)
         
         doubletri = 0; 
         ];
       ];
      
      (*Find triangle label on the other side of the edge AB on the previous triangle in the chain*)
      
      trilabel = Select[Intersection[Position[tri, vA][[All, 1]],Position[tri, vB][[All, 1]]], # != trilabel0 &][[1]];
      (*Check to see if triangle has been visited before in the chain if yes, go to new chainstack,*)
      
      If[MemberQ[trichain3Dlabels, trilabel], doubletri = 1; 
       Goto[step4];];
      trilabel0 = trilabel;
      (********)
      (*Step 5*)
      (********)
      (*Add the 3D triangle label to the triangle chain list*)
      
      trichain3Dlabels = {trichain3Dlabels, trilabel};
      (*Calculate the label of the next vertex*)
      
      vD = Select[tri[[trilabel]], False == MemberQ[{vA, vB}, #] &][[1]];
      vertmeshlabels = {vertmeshlabels, vD};
      (*Calculate angle, in 2D, of edge A-B, wrt x-axis*)
      
      vectAB = coordsB - coordsA;
      angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
      (*Calculate angle <BAD*)
      
      angBAD = va[[trilabel, Position[tri[[trilabel]], vA][[1, 1]]]];
      e3 = {vA, vD};
      el3 = edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
      (*Calculation of 2D flattened coordinates of vertex D*)
      
      coordsD = (coordsA + {el3*Cos[angAB - angBAD], el3*Sin[angAB - angBAD]});
      vertex2Dcoords = {vertex2Dcoords, coordsD};
      (*Add ordered triple of vertices to triangle list*)
      
      trilist2D = {trilist2D, Flatten[Map[Position[vertmeshlabels, #] &,tri[[trilabel]]]]};
      (*Increment  vnum2D*)
      vnum2D = vnum2D + 1;
      (*Calculate the angle that SD makes with the x-axis*)
      theta = ArcTan[coordsD[[1]], coordsD[[2]]]; 
      (********)
      (*Step 6 - If theta<thetamin set A = D and return to step 4*)
      (********)
      
      If[theta < thetamin,
       vA = vD;
       coordsA = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 7 - If theta>thetamax set B =  D and return to step 4*)
      (********)
      
      If[theta > thetamax,
       vB = vD;
       coordsB = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 8 - 
      If theta is an element (thetamin,thetamax)*)
      (********)
      (*Compute Euclidean distance between planar representations of S and D*)
      deltaSD = Sqrt[Total[coordsD^2]];
      (*Update distance matrix and angle matrix if the calculated distance is smaller than what was previously stored*)
      
      If[distMatrix[[vS, vD]] == Null,
       distMatrix[[vS, vD]] = deltaSD;
       thetaMatrix[[vS, vD]] = theta;
       tMatrix[[vS, vD]] = Flatten[trichain3Dlabels],
       If[distMatrix[[vS, vD]] > deltaSD,
        distMatrix[[vS, vD]] = deltaSD;
        thetaMatrix[[vS, vD]] = theta;
        tMatrix[[vS, vD]] = Flatten[trichain3Dlabels]
        ]];
      (*Store information needed to extend triangle over AD onto stack: Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
      
      tchainstack = {{trilabel, vA, vD, coordsA, coordsD, thetamin, thetamax, vnum2D}, tchainstack};
      (*Extend triangle chain over edge BD, set A = D and set thetamin = theta*)
      vA = vD;
      coordsA = coordsD;
      thetamin = theta;
      nextensions++;
      ];
     ], {vS, nvertices}
    ];
   (*Now make sure distance matrix is symmetric and replace Null by large number, Infinity in this case *)
   
   distMatrixsym = Table[Min[{distMatrix[[i, j]] /. Null -> Infinity, 
       distMatrix[[j, i]] /. Null -> Infinity}], {i, 1, nvertices}, {j, 1, nvertices}];
   distMatrix = distMatrix /. Null -> Infinity;
   (*Implement shortest distance *)
   
   outMatrix =  GraphDistanceMatrix[WeightedAdjacencyGraph[distMatrixsym],Method -> "FloydWarshall"];
   {outMatrix, tri, thetaMatrix, tMatrix, distMatrixsym, distMatrix}
   ];
pathCalc[vS_, vF_, trilist3D_, \[Theta]SD_θSD_, mesh_] := 
  Module[{pts, tri, va, edges, edgelengths, ntri, i, path3D, vA, vB, 
    eAB, e1, e2, el, coordsA, ang, coordsB, mAB, cAB, xI, 
    yI, \[Alpha]AIαAI, coordsI, vD, vectAB, angAB, angBAD, e3, el3, 
    coordsD, \[Theta]θ, vtrilist, posvtrilist},
   ntri = Length[trilist3D];
   pts = MeshCoordinates[mesh];
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p;
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   i = 1;
   (**)
   path3D = {};
   (*Add starting vertex coordinates to path list*)
   
   AppendTo[path3D, pts[[vS]]];
   (*Now calculate first intersection with edge (Maybe to check if \
vertices are adjacent ?) *) 
   eAB = tri[[
      trilist3D[[
       i]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
   vA = eAB[[1]]; (*Set vertex A*)
   vB = eAB[[2]]; (*Set vertex B*)

      e1 = {vA, vS};
   e2 = {vB, vS};
   (*Calculate edge lengths for the first triangle in the chain(s)*)
 
     el = edgelengths[[
     Join[Flatten[Position[edges, e1 | Reverse[e1]]], 
      Flatten[Position[edges, e2 | Reverse[e2]]]]]];
   coordsA = {el[[1]], 
     0};  (*Calculate 2D flattened coordinates of vertex vA*)
   
   vtrilist = Position[tri, vS];
   posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
   ang = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
   coordsB = {el[[2]]*Cos[ang], 
     el[[2]]*Sin[
       ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
   
   mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
       coordsA[[1]]); (*problem if perfectly vertical!*)
   
   cAB = coordsA[[2]] - mAB*coordsA[[1]];
   xI = cAB/(Tan[\[Theta]SD]Tan[θSD] - mAB);
   yI = Tan[\[Theta]SD]*xI;Tan[θSD]*xI;
   \[Alpha]AIαAI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
   coordsI = pts[[vA]] + \[Alpha]AI*αAI*(pts[[vB]] - pts[[vA]]);
   AppendTo[path3D, coordsI];
   i = 2;
   While[i < ntri + 1,
    vD = Select[tri[[trilist3D[[i]]]], 
       False == MemberQ[{vA, vB}, #] &][[1]];
    vectAB = coordsB - coordsA;
    angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
    (*Calculate angle <BAD*)
    vtrilist = Position[tri, vA];
    posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
    angBAD = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
    e3 = {vA, vD};
    el3 = 
     edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
    (*Calculation of 2D flattened coordinates of vertex D*)
    
    coordsD = (coordsA + {el3*Cos[angAB - angBAD], 
        el3*Sin[angAB - angBAD]});
    (*Calculate the angle that SD makes with the x-
    axis*)
    \[Theta]θ = ArcTan[coordsD[[1]], coordsD[[2]]]; 
    If[\[Theta]If[θ < \[Theta]SDθSD,
     vA = vD;
     coordsA = coordsD;
     ];
    If[\[Theta]If[θ > \[Theta]SDθSD,
     vB = vD;
     coordsB = coordsD;
     ];
    mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
        coordsA[[1]]); (*problem if perfectly vertical!*)
    
    cAB = coordsA[[2]] - mAB*coordsA[[1]];
    xI = cAB/(Tan[\[Theta]SD]Tan[θSD] - mAB);
    yI = Tan[\[Theta]SD]*xI;Tan[θSD]*xI;
    \[Alpha]AIαAI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
    coordsI = pts[[vA]] + \[Alpha]AI*αAI*(pts[[vB]] - pts[[vA]]);
    AppendTo[path3D, coordsI];
    i++
    ];
   AppendTo[path3D, pts[[vF]]];
   {path3D}
   ];
losAlgorithm[mesh_] := 
  Module[{mesh0 = mesh, pts, nvertices, edges, tri, va, edgelengths, 
    distMatrix, tchainlists, \[CapitalDelta]\[Theta]prec, vtrilist, 
    ntri, tl3dstore, tnum, eAB, vA, vB, vD, vS, e1, e2, el, 
    vertmeshlabels, vertex2Dcoords, trilist2D, trichain3Dlabels, 
    trilabel, trilabel0, coordsA, coordsB, coordsD, 
    ang, \[Theta], \[Theta]min, \[Theta]max, vnum2D, tchainstack, 
    doubletri, boundaryEdgeQ, tpop, trichainnum, vectAB, angAB, 
    angBAD, e3, el3, \[Delta]SD, outMatrix, \[Theta]Matrix, tMatrix, 
    distMatrixsym},
   (**************************)
   (*Numerical Parameters*)
   (**************************)      
   dthetaprec =  0.05; (*Precision in Theta max - Theta min , 
   perhaps can be removed at somestage but at the moment useful for testing*) 
   (**************************)
   (*Mesh Calculations*)
   (**************************)

   (*List of coordinates of all vertices on the mesh*)
   
   pts = MeshCoordinates[mesh];
   (*Number of vertices on the mesh*)
   nvertices = Length[pts];
   (*List of all edges on the mesh, 
   in terms of pairs of vertex indices*)
   
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   (*List of the "ordered" vertex index triples for all triangles on the mesh*)
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p; 
   (*List of edgelengths numbered by edge *)
   
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   (*List of the angles within each of the corners of all triangles on the mesh*)
   
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   (**************************)
   (*Preparation of data structures for storage*)
   (**************************)
   (*Matrix to store all distances between all pairs of vertices*)
   
   distMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all angles between pairs of vertices*)
   
   ThetaMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all triangle chains (in 3D labelling) between pairs of vertices*)
   
   tMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   
   (**************************)
   (*Start of Algorithm*)
   (**************************)

   (********)
   (*Step 1 - 
   Choose a vertex vS on the mesh (Here we map over all Vertices) *)
 
   (********)
   Do[
    (********)
    (*Step 2 - 
    Choose a triangle containing vS as a vertex*)
    (********)
    
   (*Create a list of triangles around the vertex vS*)
    
    vtrilist = Position[tri, vS];
    (*Number of triangles around vertex S*)
    
    ntri = Length[vtrilist];
    (*Choose the first triangle in the list*)
    tnum = 1;
    (*While Loop to be performed over all triangles around vertex S*)
    (**********************)
    (******
    while loop here******)
    (**********************)
    
    While[tnum < ntri,
     Label[step2];
     If[tnum == ntri + 1, Break[]];
     (*Calculate ordered list of vertices A and B assuming we have outward oriented facets*)
     
     eAB = tri[[
        vtrilist[[tnum]][[1]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
     vA = eAB[[1]]; (*Set vertex A*)
     vB = eAB[[2]]; (*Set vertex B*)
     (*Calculate labels of the vertices of first two edges*)
     e1 = {vA, vS};
     e2 = {vB, vS};
     (*Calculate edge lengths for the first triangle in the chain(s)*)

          el = edgelengths[[Join[Flatten[Position[edges, e1 | Reverse[e1]]],Flatten[Position[edges, e2 | Reverse[e2]]]]]];
     (*Store the edge length data in the distance matrix*)
     
     distMatrix[[vS, vA]] = el[[1]];
     distMatrix[[vS, vB]] = el[[2]];
     (*Create a set of (temporary) lists which will hold information about vertexlabels, 
     coordinates etc*)
     (*Lists will be stored (perhaps in tMatrix etc), 
     whenever a new triangle chain is created*)
     (*Probably this information is not needed in the final algorithm, 
     but will be needed for debugging*)
     
     (*List of the vertex labels from the original mesh in the triangle chain*)
     vertmeshlabels = {}; 
     (*List of the 2D transformed coordinates of the vertices*)
     
     vertex2Dcoords = {}; 
     (*List of the vertex triples that make up each flattened triangle chain in 2D*)
     trilist2D = {}; 
     (*List of 3D face triangle labels from the mesh in the triangle chain*)
     
     trichain3Dlabels = {};
     (*label of current triangle in the triangle chain *)
     
     trilabel = vtrilist[[tnum]][[1]]; 
     (*Set previous triangle label to the current one (used for later calculations) *)
     trilabel0 = trilabel;
     (*Add the first triangle label to the list of 3D triangle(face) labels in the chain*)
     
     trichain3Dlabels = {trichain3Dlabels, trilabel};
     (*Map first triangle in the chain to the plane*)
     (*Origin Vertex vS*)
     (*Add vS mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vS};
     (*Add vS 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, {0, 0}};
     (*Vertex vA *)
     (*Add vA mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vA};
     coordsA = {el[[1]], 0};  (*Calculate 2D flattened coordinates of vertex vA*)
     
     (*Add vA 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsA};
     (*Vertex vB *)
     (*Add vB mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vB};
     ang = va[[vtrilist[[tnum]][[1]], vtrilist[[tnum]][[2]]]];
     coordsB = {el[[2]]*Cos[ang], el[[2]]*Sin[ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
  
     (*Add vB 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsB};
     (*Add the ordered triple of vertices to the 2D triangle list*)
  
        trilist2D = {trilist2D, {1, 2, 3}};
     thetamin = 0; (*Set min angle to be 0*)
     thetamax = ang; (*Set max angle to be the angle <BSA*)
     
     (********)
     (*Step 3*)
     (********)
     (*Counter of number of 2D vertices in triangle chain, will be reset everytime we do a new chain? starts at vertex 4*)
 
     vnum2D = 4;
     (*Initialise chain stack to enable chain branching, this first starts off as being empty*)
     (*What we also want to do is to rebuild a new chain stack for each branch *)
     
     tchainstack = {};
     (********)
     (*Step 4*)
     (********)
     
     doubletri = 0; (*Label = 0 if triangles not repeated in chain, = 1 if repeated*)
     
     nextensions = 1; (*Max number of extensions of triangle chain within one chain*)
     While[nextensions < 10000,
      Label[step4];
      (*BoundaryQ - Returns False if edge NOT a boundary, 
      True only 1 tri is attached to  edge vA -> vB*)
      
      boundaryEdgeQ = Intersection[Position[tri, vA][[All, 1]], Position[tri, vB][[All, 1]]] != 2; 
      (*Calculate whether we are within machine precision or not \
thetamax-thetamin< dthetaprec*)
      
      If[(thetamax - thetamin < dthetaprec) || 
        boundaryEdgeQ || (doubletri == 1),
       If[(tchainstack == {}),
         tnum++;
         Goto[step2],(*picknewtriangle*)
         {tpop, tchainstack} = {#, {##2}} & @@ tchainstack;
         (*newstructure of tchainstack*)
         
         tchainstack = tchainstack[[1]];
         (*to reset values so that we go down other chains*)
         (*Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
         trilabel0 = tpop[[1]];
         vA = tpop[[2]];
         vB = tpop[[3]];
         coordsA = tpop[[4]];
         coordsB = tpop[[5]];
         thetamin = tpop[[6]];
         thetamax = tpop[[7]];
         vnum2D = tpop[[8]];
         (*here we store the previous tchainlist for plotting*)
      
         vertmeshlabels =  Flatten[vertmeshlabels]; (*Flatten the linked list created previously*)
         
         trichain3Dlabels = Flatten[trichain3Dlabels];(*Flatten the linked list created previously*)
         
         vertex2Dcoords = Partition[Flatten[vertex2Dcoords],2];(*Flatten the linked list created previously*)
         
         trilist2D = 
          Partition[Flatten[trilist2D], 3];(*Flatten the linked list created previously*)
         (*now we need to go back in the list and "restart" so to say the counters*)
         (*need to reset the storage, and also the vnum2D otherwise we wont have diff chains, mainly important for plotting, but probably stops labelling effects*)
         
         trichainnum = Position[trichain3Dlabels, trilabel0][[1, 1]];
         trichain3Dlabels = Take[trichain3Dlabels, trichainnum];
         vertmeshlabels = Take[vertmeshlabels, vnum2D - 1];
         trilist2D = Take[trilist2D, trichainnum];
         vertex2Dcoords = Take[vertex2Dcoords, vnum2D - 1];
         (*Reset doubled triangle label to zero *)
         
         doubletri = 0; 
         ];
       ];
      
      (*Find triangle label on the other side of the edge AB on the previous triangle in the chain*)
      
      trilabel = Select[Intersection[Position[tri, vA][[All, 1]],Position[tri, vB][[All, 1]]], # != trilabel0 &][[1]];
      (*Check to see if triangle has been visited before in the chain if yes, go to new chainstack,*)
      
      If[MemberQ[trichain3Dlabels, trilabel], doubletri = 1; 
       Goto[step4];];
      trilabel0 = trilabel;
      (********)
      (*Step 5*)
      (********)
      (*Add the 3D triangle label to the triangle chain list*)
      
      trichain3Dlabels = {trichain3Dlabels, trilabel};
      (*Calculate the label of the next vertex*)
      
      vD = Select[tri[[trilabel]], False == MemberQ[{vA, vB}, #] &][[1]];
      vertmeshlabels = {vertmeshlabels, vD};
      (*Calculate angle, in 2D, of edge A-B, wrt x-axis*)
      
      vectAB = coordsB - coordsA;
      angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
      (*Calculate angle <BAD*)
      
      angBAD = va[[trilabel, Position[tri[[trilabel]], vA][[1, 1]]]];
      e3 = {vA, vD};
      el3 = edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
      (*Calculation of 2D flattened coordinates of vertex D*)
      
      coordsD = (coordsA + {el3*Cos[angAB - angBAD], el3*Sin[angAB - angBAD]});
      vertex2Dcoords = {vertex2Dcoords, coordsD};
      (*Add ordered triple of vertices to triangle list*)
      
      trilist2D = {trilist2D, Flatten[Map[Position[vertmeshlabels, #] &,tri[[trilabel]]]]};
      (*Increment  vnum2D*)
      vnum2D = vnum2D + 1;
      (*Calculate the angle that SD makes with the x-axis*)
      theta = ArcTan[coordsD[[1]], coordsD[[2]]]; 
      (********)
      (*Step 6 - If theta<thetamin set A = D and return to step 4*)
      (********)
      
      If[theta < thetamin,
       vA = vD;
       coordsA = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 7 - If theta>thetamax set B =  D and return to step 4*)
      (********)
      
      If[theta > thetamax,
       vB = vD;
       coordsB = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 8 - 
      If theta is an element (thetamin,thetamax)*)
      (********)
      (*Compute Euclidean distance between planar representations of S and D*)
      deltaSD = Sqrt[Total[coordsD^2]];
      (*Update distance matrix and angle matrix if the calculated distance is smaller than what was previously stored*)
      
      If[distMatrix[[vS, vD]] == Null,
       distMatrix[[vS, vD]] = deltaSD;
       thetaMatrix[[vS, vD]] = theta;
       tMatrix[[vS, vD]] = Flatten[trichain3Dlabels],
       If[distMatrix[[vS, vD]] > deltaSD,
        distMatrix[[vS, vD]] = deltaSD;
        thetaMatrix[[vS, vD]] = theta;
        tMatrix[[vS, vD]] = Flatten[trichain3Dlabels]
        ]];
      (*Store information needed to extend triangle over AD onto stack: Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
      
      tchainstack = {{trilabel, vA, vD, coordsA, coordsD, thetamin, thetamax, vnum2D}, tchainstack};
      (*Extend triangle chain over edge BD, set A = D and set thetamin = theta*)
      vA = vD;
      coordsA = coordsD;
      thetamin = theta;
      nextensions++;
      ];
     ], {vS, nvertices}
    ];
   (*Now make sure distance matrix is symmetric and replace Null by large number, Infinity in this case *)
   
   distMatrixsym = Table[Min[{distMatrix[[i, j]] /. Null -> Infinity, 
       distMatrix[[j, i]] /. Null -> Infinity}], {i, 1, nvertices}, {j, 1, nvertices}];
   distMatrix = distMatrix /. Null -> Infinity;
   (*Implement shortest distance *)
   
   outMatrix =  GraphDistanceMatrix[WeightedAdjacencyGraph[distMatrixsym],Method -> "FloydWarshall"];
   {outMatrix, tri, thetaMatrix, tMatrix, distMatrixsym, distMatrix}
   ];
pathCalc[vS_, vF_, trilist3D_, \[Theta]SD_, mesh_] := 
  Module[{pts, tri, va, edges, edgelengths, ntri, i, path3D, vA, vB, 
    eAB, e1, e2, el, coordsA, ang, coordsB, mAB, cAB, xI, 
    yI, \[Alpha]AI, coordsI, vD, vectAB, angAB, angBAD, e3, el3, 
    coordsD, \[Theta], vtrilist, posvtrilist},
   ntri = Length[trilist3D];
   pts = MeshCoordinates[mesh];
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p;
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   i = 1;
   (**)
   path3D = {};
   (*Add starting vertex coordinates to path list*)
   
   AppendTo[path3D, pts[[vS]]];
   (*Now calculate first intersection with edge (Maybe to check if \
vertices are adjacent ?) *) 
   eAB = tri[[
      trilist3D[[
       i]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
   vA = eAB[[1]]; (*Set vertex A*)
   vB = eAB[[2]]; (*Set vertex B*)

      e1 = {vA, vS};
   e2 = {vB, vS};
   (*Calculate edge lengths for the first triangle in the chain(s)*)
 
     el = edgelengths[[
     Join[Flatten[Position[edges, e1 | Reverse[e1]]], 
      Flatten[Position[edges, e2 | Reverse[e2]]]]]];
   coordsA = {el[[1]], 
     0};  (*Calculate 2D flattened coordinates of vertex vA*)
   
   vtrilist = Position[tri, vS];
   posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
   ang = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
   coordsB = {el[[2]]*Cos[ang], 
     el[[2]]*Sin[
       ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
   
   mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
       coordsA[[1]]); (*problem if perfectly vertical!*)
   
   cAB = coordsA[[2]] - mAB*coordsA[[1]];
   xI = cAB/(Tan[\[Theta]SD] - mAB);
   yI = Tan[\[Theta]SD]*xI;
   \[Alpha]AI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
   coordsI = pts[[vA]] + \[Alpha]AI*(pts[[vB]] - pts[[vA]]);
   AppendTo[path3D, coordsI];
   i = 2;
   While[i < ntri + 1,
    vD = Select[tri[[trilist3D[[i]]]], 
       False == MemberQ[{vA, vB}, #] &][[1]];
    vectAB = coordsB - coordsA;
    angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
    (*Calculate angle <BAD*)
    vtrilist = Position[tri, vA];
    posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
    angBAD = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
    e3 = {vA, vD};
    el3 = 
     edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
    (*Calculation of 2D flattened coordinates of vertex D*)
    
    coordsD = (coordsA + {el3*Cos[angAB - angBAD], 
        el3*Sin[angAB - angBAD]});
    (*Calculate the angle that SD makes with the x-
    axis*)
    \[Theta] = ArcTan[coordsD[[1]], coordsD[[2]]]; 
    If[\[Theta] < \[Theta]SD,
     vA = vD;
     coordsA = coordsD;
     ];
    If[\[Theta] > \[Theta]SD,
     vB = vD;
     coordsB = coordsD;
     ];
    mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
        coordsA[[1]]); (*problem if perfectly vertical!*)
    
    cAB = coordsA[[2]] - mAB*coordsA[[1]];
    xI = cAB/(Tan[\[Theta]SD] - mAB);
    yI = Tan[\[Theta]SD]*xI;
    \[Alpha]AI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
    coordsI = pts[[vA]] + \[Alpha]AI*(pts[[vB]] - pts[[vA]]);
    AppendTo[path3D, coordsI];
    i++
    ];
   AppendTo[path3D, pts[[vF]]];
   {path3D}
   ];
losAlgorithm[mesh_] := 
  Module[{mesh0 = mesh, pts, nvertices, edges, tri, va, edgelengths, 
    distMatrix, tchainlists, Δθprec, vtrilist, 
    ntri, tl3dstore, tnum, eAB, vA, vB, vD, vS, e1, e2, el, 
    vertmeshlabels, vertex2Dcoords, trilist2D, trichain3Dlabels, 
    trilabel, trilabel0, coordsA, coordsB, coordsD, 
    ang, θ, θmin, θmax, vnum2D, tchainstack, 
    doubletri, boundaryEdgeQ, tpop, trichainnum, vectAB, angAB, 
    angBAD, e3, el3, δSD, outMatrix, θMatrix, tMatrix, 
    distMatrixsym},
   (**************************)
   (*Numerical Parameters*)
   (**************************)      
   dthetaprec =  0.05; (*Precision in Theta max - Theta min , 
   perhaps can be removed at somestage but at the moment useful for testing*) 
   (**************************)
   (*Mesh Calculations*)
   (**************************)

   (*List of coordinates of all vertices on the mesh*)
   
   pts = MeshCoordinates[mesh];
   (*Number of vertices on the mesh*)
   nvertices = Length[pts];
   (*List of all edges on the mesh, 
   in terms of pairs of vertex indices*)
   
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   (*List of the "ordered" vertex index triples for all triangles on the mesh*)
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p; 
   (*List of edgelengths numbered by edge *)
   
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   (*List of the angles within each of the corners of all triangles on the mesh*)
   
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   (**************************)
   (*Preparation of data structures for storage*)
   (**************************)
   (*Matrix to store all distances between all pairs of vertices*)
   
   distMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all angles between pairs of vertices*)
   
   ThetaMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   (*Matrix to store all triangle chains (in 3D labelling) between pairs of vertices*)
   
   tMatrix = 
    Table[If[i == j, 0], {i, 1, nvertices}, {j, 1, nvertices}];
   
   (**************************)
   (*Start of Algorithm*)
   (**************************)

   (********)
   (*Step 1 - 
   Choose a vertex vS on the mesh (Here we map over all Vertices) *)
 
   (********)
   Do[
    (********)
    (*Step 2 - 
    Choose a triangle containing vS as a vertex*)
    (********)
    
   (*Create a list of triangles around the vertex vS*)
    
    vtrilist = Position[tri, vS];
    (*Number of triangles around vertex S*)
    
    ntri = Length[vtrilist];
    (*Choose the first triangle in the list*)
    tnum = 1;
    (*While Loop to be performed over all triangles around vertex S*)
    (**********************)
    (******
    while loop here******)
    (**********************)
    
    While[tnum < ntri,
     Label[step2];
     If[tnum == ntri + 1, Break[]];
     (*Calculate ordered list of vertices A and B assuming we have outward oriented facets*)
     
     eAB = tri[[
        vtrilist[[tnum]][[1]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
     vA = eAB[[1]]; (*Set vertex A*)
     vB = eAB[[2]]; (*Set vertex B*)
     (*Calculate labels of the vertices of first two edges*)
     e1 = {vA, vS};
     e2 = {vB, vS};
     (*Calculate edge lengths for the first triangle in the chain(s)*)

          el = edgelengths[[Join[Flatten[Position[edges, e1 | Reverse[e1]]],Flatten[Position[edges, e2 | Reverse[e2]]]]]];
     (*Store the edge length data in the distance matrix*)
     
     distMatrix[[vS, vA]] = el[[1]];
     distMatrix[[vS, vB]] = el[[2]];
     (*Create a set of (temporary) lists which will hold information about vertexlabels, 
     coordinates etc*)
     (*Lists will be stored (perhaps in tMatrix etc), 
     whenever a new triangle chain is created*)
     (*Probably this information is not needed in the final algorithm, 
     but will be needed for debugging*)
     
     (*List of the vertex labels from the original mesh in the triangle chain*)
     vertmeshlabels = {}; 
     (*List of the 2D transformed coordinates of the vertices*)
     
     vertex2Dcoords = {}; 
     (*List of the vertex triples that make up each flattened triangle chain in 2D*)
     trilist2D = {}; 
     (*List of 3D face triangle labels from the mesh in the triangle chain*)
     
     trichain3Dlabels = {};
     (*label of current triangle in the triangle chain *)
     
     trilabel = vtrilist[[tnum]][[1]]; 
     (*Set previous triangle label to the current one (used for later calculations) *)
     trilabel0 = trilabel;
     (*Add the first triangle label to the list of 3D triangle(face) labels in the chain*)
     
     trichain3Dlabels = {trichain3Dlabels, trilabel};
     (*Map first triangle in the chain to the plane*)
     (*Origin Vertex vS*)
     (*Add vS mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vS};
     (*Add vS 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, {0, 0}};
     (*Vertex vA *)
     (*Add vA mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vA};
     coordsA = {el[[1]], 0};  (*Calculate 2D flattened coordinates of vertex vA*)
     
     (*Add vA 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsA};
     (*Vertex vB *)
     (*Add vB mesh label to list*)
     
     vertmeshlabels = {vertmeshlabels, vB};
     ang = va[[vtrilist[[tnum]][[1]], vtrilist[[tnum]][[2]]]];
     coordsB = {el[[2]]*Cos[ang], el[[2]]*Sin[ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
  
     (*Add vB 2D coordinate pair to 2D coordinate list*)
     
     vertex2Dcoords = {vertex2Dcoords, coordsB};
     (*Add the ordered triple of vertices to the 2D triangle list*)
  
        trilist2D = {trilist2D, {1, 2, 3}};
     thetamin = 0; (*Set min angle to be 0*)
     thetamax = ang; (*Set max angle to be the angle <BSA*)
     
     (********)
     (*Step 3*)
     (********)
     (*Counter of number of 2D vertices in triangle chain, will be reset everytime we do a new chain? starts at vertex 4*)
 
     vnum2D = 4;
     (*Initialise chain stack to enable chain branching, this first starts off as being empty*)
     (*What we also want to do is to rebuild a new chain stack for each branch *)
     
     tchainstack = {};
     (********)
     (*Step 4*)
     (********)
     
     doubletri = 0; (*Label = 0 if triangles not repeated in chain, = 1 if repeated*)
     
     nextensions = 1; (*Max number of extensions of triangle chain within one chain*)
     While[nextensions < 10000,
      Label[step4];
      (*BoundaryQ - Returns False if edge NOT a boundary, 
      True only 1 tri is attached to  edge vA -> vB*)
      
      boundaryEdgeQ = Intersection[Position[tri, vA][[All, 1]], Position[tri, vB][[All, 1]]] != 2; 
      (*Calculate whether we are within machine precision or not \
thetamax-thetamin< dthetaprec*)
      
      If[(thetamax - thetamin < dthetaprec) || 
        boundaryEdgeQ || (doubletri == 1),
       If[(tchainstack == {}),
         tnum++;
         Goto[step2],(*picknewtriangle*)
         {tpop, tchainstack} = {#, {##2}} & @@ tchainstack;
         (*newstructure of tchainstack*)
         
         tchainstack = tchainstack[[1]];
         (*to reset values so that we go down other chains*)
         (*Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
         trilabel0 = tpop[[1]];
         vA = tpop[[2]];
         vB = tpop[[3]];
         coordsA = tpop[[4]];
         coordsB = tpop[[5]];
         thetamin = tpop[[6]];
         thetamax = tpop[[7]];
         vnum2D = tpop[[8]];
         (*here we store the previous tchainlist for plotting*)
      
         vertmeshlabels =  Flatten[vertmeshlabels]; (*Flatten the linked list created previously*)
         
         trichain3Dlabels = Flatten[trichain3Dlabels];(*Flatten the linked list created previously*)
         
         vertex2Dcoords = Partition[Flatten[vertex2Dcoords],2];(*Flatten the linked list created previously*)
         
         trilist2D = 
          Partition[Flatten[trilist2D], 3];(*Flatten the linked list created previously*)
         (*now we need to go back in the list and "restart" so to say the counters*)
         (*need to reset the storage, and also the vnum2D otherwise we wont have diff chains, mainly important for plotting, but probably stops labelling effects*)
         
         trichainnum = Position[trichain3Dlabels, trilabel0][[1, 1]];
         trichain3Dlabels = Take[trichain3Dlabels, trichainnum];
         vertmeshlabels = Take[vertmeshlabels, vnum2D - 1];
         trilist2D = Take[trilist2D, trichainnum];
         vertex2Dcoords = Take[vertex2Dcoords, vnum2D - 1];
         (*Reset doubled triangle label to zero *)
         
         doubletri = 0; 
         ];
       ];
      
      (*Find triangle label on the other side of the edge AB on the previous triangle in the chain*)
      
      trilabel = Select[Intersection[Position[tri, vA][[All, 1]],Position[tri, vB][[All, 1]]], # != trilabel0 &][[1]];
      (*Check to see if triangle has been visited before in the chain if yes, go to new chainstack,*)
      
      If[MemberQ[trichain3Dlabels, trilabel], doubletri = 1; 
       Goto[step4];];
      trilabel0 = trilabel;
      (********)
      (*Step 5*)
      (********)
      (*Add the 3D triangle label to the triangle chain list*)
      
      trichain3Dlabels = {trichain3Dlabels, trilabel};
      (*Calculate the label of the next vertex*)
      
      vD = Select[tri[[trilabel]], False == MemberQ[{vA, vB}, #] &][[1]];
      vertmeshlabels = {vertmeshlabels, vD};
      (*Calculate angle, in 2D, of edge A-B, wrt x-axis*)
      
      vectAB = coordsB - coordsA;
      angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
      (*Calculate angle <BAD*)
      
      angBAD = va[[trilabel, Position[tri[[trilabel]], vA][[1, 1]]]];
      e3 = {vA, vD};
      el3 = edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
      (*Calculation of 2D flattened coordinates of vertex D*)
      
      coordsD = (coordsA + {el3*Cos[angAB - angBAD], el3*Sin[angAB - angBAD]});
      vertex2Dcoords = {vertex2Dcoords, coordsD};
      (*Add ordered triple of vertices to triangle list*)
      
      trilist2D = {trilist2D, Flatten[Map[Position[vertmeshlabels, #] &,tri[[trilabel]]]]};
      (*Increment  vnum2D*)
      vnum2D = vnum2D + 1;
      (*Calculate the angle that SD makes with the x-axis*)
      theta = ArcTan[coordsD[[1]], coordsD[[2]]]; 
      (********)
      (*Step 6 - If theta<thetamin set A = D and return to step 4*)
      (********)
      
      If[theta < thetamin,
       vA = vD;
       coordsA = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 7 - If theta>thetamax set B =  D and return to step 4*)
      (********)
      
      If[theta > thetamax,
       vB = vD;
       coordsB = coordsD;
       Goto[step4];
       ];
      (********)
      (*Step 8 - 
      If theta is an element (thetamin,thetamax)*)
      (********)
      (*Compute Euclidean distance between planar representations of S and D*)
      deltaSD = Sqrt[Total[coordsD^2]];
      (*Update distance matrix and angle matrix if the calculated distance is smaller than what was previously stored*)
      
      If[distMatrix[[vS, vD]] == Null,
       distMatrix[[vS, vD]] = deltaSD;
       thetaMatrix[[vS, vD]] = theta;
       tMatrix[[vS, vD]] = Flatten[trichain3Dlabels],
       If[distMatrix[[vS, vD]] > deltaSD,
        distMatrix[[vS, vD]] = deltaSD;
        thetaMatrix[[vS, vD]] = theta;
        tMatrix[[vS, vD]] = Flatten[trichain3Dlabels]
        ]];
      (*Store information needed to extend triangle over AD onto stack: Tlabel, Alabel, Blabel, coordsA2D,coordsB2D,thetamin,thetamax*)
      
      tchainstack = {{trilabel, vA, vD, coordsA, coordsD, thetamin, thetamax, vnum2D}, tchainstack};
      (*Extend triangle chain over edge BD, set A = D and set thetamin = theta*)
      vA = vD;
      coordsA = coordsD;
      thetamin = theta;
      nextensions++;
      ];
     ], {vS, nvertices}
    ];
   (*Now make sure distance matrix is symmetric and replace Null by large number, Infinity in this case *)
   
   distMatrixsym = Table[Min[{distMatrix[[i, j]] /. Null -> Infinity, 
       distMatrix[[j, i]] /. Null -> Infinity}], {i, 1, nvertices}, {j, 1, nvertices}];
   distMatrix = distMatrix /. Null -> Infinity;
   (*Implement shortest distance *)
   
   outMatrix =  GraphDistanceMatrix[WeightedAdjacencyGraph[distMatrixsym],Method -> "FloydWarshall"];
   {outMatrix, tri, thetaMatrix, tMatrix, distMatrixsym, distMatrix}
   ];
pathCalc[vS_, vF_, trilist3D_, θSD_, mesh_] := 
  Module[{pts, tri, va, edges, edgelengths, ntri, i, path3D, vA, vB, 
    eAB, e1, e2, el, coordsA, ang, coordsB, mAB, cAB, xI, 
    yI, αAI, coordsI, vD, vectAB, angAB, angBAD, e3, el3, 
    coordsD, θ, vtrilist, posvtrilist},
   ntri = Length[trilist3D];
   pts = MeshCoordinates[mesh];
   tri = MeshCells[mesh, 2] /. Polygon[p_] :> p;
   edges = MeshCells[mesh, 1] /. Line[p_] :> p ;
   edgelengths = PropertyValue[{mesh, 1}, MeshCellMeasure];
   va = VectorAngle[#1 - #2, #3 - #2] & @@@ 
       Partition[#, 3, 1, {2, -2}] & /@ 
     MeshPrimitives[mesh, {2}][[All, 1]];
   
   i = 1;
   (**)
   path3D = {};
   (*Add starting vertex coordinates to path list*)
   
   AppendTo[path3D, pts[[vS]]];
   (*Now calculate first intersection with edge (Maybe to check if \
vertices are adjacent ?) *) 
   eAB = tri[[
      trilist3D[[
       i]]]] /. {vS, a_, b_} | {b_, vS, a_} | {a_, b_, vS} :> {a, b};
   vA = eAB[[1]]; (*Set vertex A*)
   vB = eAB[[2]]; (*Set vertex B*)

      e1 = {vA, vS};
   e2 = {vB, vS};
   (*Calculate edge lengths for the first triangle in the chain(s)*)
 
     el = edgelengths[[
     Join[Flatten[Position[edges, e1 | Reverse[e1]]], 
      Flatten[Position[edges, e2 | Reverse[e2]]]]]];
   coordsA = {el[[1]], 
     0};  (*Calculate 2D flattened coordinates of vertex vA*)
   
   vtrilist = Position[tri, vS];
   posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
   ang = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
   coordsB = {el[[2]]*Cos[ang], 
     el[[2]]*Sin[
       ang]}; (*Calculate 2D flattened coordinates of vertex vB*)
   
   mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
       coordsA[[1]]); (*problem if perfectly vertical!*)
   
   cAB = coordsA[[2]] - mAB*coordsA[[1]];
   xI = cAB/(Tan[θSD] - mAB);
   yI = Tan[θSD]*xI;
   αAI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
   coordsI = pts[[vA]] + αAI*(pts[[vB]] - pts[[vA]]);
   AppendTo[path3D, coordsI];
   i = 2;
   While[i < ntri + 1,
    vD = Select[tri[[trilist3D[[i]]]], 
       False == MemberQ[{vA, vB}, #] &][[1]];
    vectAB = coordsB - coordsA;
    angAB = ArcTan[vectAB[[1]], vectAB[[2]]];
    (*Calculate angle <BAD*)
    vtrilist = Position[tri, vA];
    posvtrilist = Position[vtrilist, trilist3D[[i]]][[1, 1]];
    angBAD = va[[trilist3D[[i]], vtrilist[[posvtrilist, 2]]]];
    e3 = {vA, vD};
    el3 = 
     edgelengths[[Flatten[Position[edges, e3 | Reverse[e3]]]]][[1]];
    (*Calculation of 2D flattened coordinates of vertex D*)
    
    coordsD = (coordsA + {el3*Cos[angAB - angBAD], 
        el3*Sin[angAB - angBAD]});
    (*Calculate the angle that SD makes with the x-
    axis*)
    θ = ArcTan[coordsD[[1]], coordsD[[2]]]; 
    If[θ < θSD,
     vA = vD;
     coordsA = coordsD;
     ];
    If[θ > θSD,
     vB = vD;
     coordsB = coordsD;
     ];
    mAB = (coordsB[[2]] - coordsA[[2]])/(coordsB[[1]] - 
        coordsA[[1]]); (*problem if perfectly vertical!*)
    
    cAB = coordsA[[2]] - mAB*coordsA[[1]];
    xI = cAB/(Tan[θSD] - mAB);
    yI = Tan[θSD]*xI;
    αAI = Norm[{xI, yI} - coordsA]/Norm[coordsB - coordsA];
    coordsI = pts[[vA]] + αAI*(pts[[vB]] - pts[[vA]]);
    AppendTo[path3D, coordsI];
    i++
    ];
   AppendTo[path3D, pts[[vF]]];
   {path3D}
   ];
Source Link
Dunlop
  • 4.3k
  • 5
  • 29
  • 43
Loading