intersectedSurface.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "intersectedSurface.H"
27 #include "surfaceIntersection.H"
28 #include "faceList.H"
29 #include "faceTriangulation.H"
30 #include "treeBoundBox.H"
31 #include "OFstream.H"
32 #include "error.H"
33 #include "meshTools.H"
34 #include "edgeSurface.H"
35 #include "DynamicList.H"
36 #include "transform.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(intersectedSurface, 0);
43 }
44 
45 
49 const Foam::label Foam::intersectedSurface::BOTH = STARTTOEND | ENDTOSTART;
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
54 // Write whole pointField and edges to stream
56 (
57  const pointField& points,
58  const edgeList& edges,
59  Ostream& os
60 )
61 {
62  forAll(points, pointI)
63  {
64  const point& pt = points[pointI];
65 
66  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
67  }
68  forAll(edges, edgeI)
69  {
70  const edge& e = edges[edgeI];
71 
72  os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
73  }
74 }
75 
76 
77 // Write whole pointField and selected edges to stream
79 (
80  const pointField& points,
81  const edgeList& edges,
82  const labelList& faceEdges,
83  Ostream& os
84 )
85 {
86  forAll(points, pointI)
87  {
88  const point& pt = points[pointI];
89 
90  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
91  }
92  forAll(faceEdges, i)
93  {
94  const edge& e = edges[faceEdges[i]];
95 
96  os << "l " << e.start()+1 << ' ' << e.end()+1 << nl;
97  }
98 }
99 
100 
101 // write local points and edges to stream
103 (
104  const pointField& points,
105  const edgeList& edges,
106  const labelList& faceEdges,
107  const fileName& fName
108 )
109 {
110  OFstream os(fName);
111 
112  labelList pointMap(points.size(), -1);
113 
114  label maxVertI = 0;
115 
116  forAll(faceEdges, i)
117  {
118  const edge& e = edges[faceEdges[i]];
119 
120  forAll(e, i)
121  {
122  label pointI = e[i];
123 
124  if (pointMap[pointI] == -1)
125  {
126  const point& pt = points[pointI];
127 
128  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
129 
130  pointMap[pointI] = maxVertI++;
131  }
132  }
133  }
134 
135  forAll(faceEdges, i)
136  {
137  const edge& e = edges[faceEdges[i]];
138 
139  os << "l " << pointMap[e.start()]+1 << ' ' << pointMap[e.end()]+1
140  << nl;
141  }
142 }
143 
144 
145 // Write whole pointField and face to stream
147 (
148  const pointField& points,
149  const face& f,
150  Ostream& os
151 )
152 {
153  forAll(points, pointI)
154  {
155  const point& pt = points[pointI];
156 
157  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
158  }
159 
160  os << 'f';
161 
162  forAll(f, fp)
163  {
164  os << ' ' << f[fp]+1;
165  }
166  os << nl;
167 }
168 
169 
170 // Print current visited state.
172 (
173  const edgeList& edges,
174  const labelList& edgeLabels,
175  const Map<label>& visited
176 )
177 {
178  Pout<< "Visited:" << nl;
179  forAll(edgeLabels, i)
180  {
181  label edgeI = edgeLabels[i];
182 
183  const edge& e = edges[edgeI];
184 
185  label stat = visited[edgeI];
186 
187  if (stat == UNVISITED)
188  {
189  Pout<< " edge:" << edgeI << " verts:" << e
190  << " unvisited" << nl;
191  }
192  else if (stat == STARTTOEND)
193  {
194  Pout<< " edge:" << edgeI << " from " << e[0]
195  << " to " << e[1] << nl;
196  }
197  else if (stat == ENDTOSTART)
198  {
199  Pout<< " edge:" << edgeI << " from " << e[1]
200  << " to " << e[0] << nl;
201  }
202  else
203  {
204  Pout<< " edge:" << edgeI << " both " << e
205  << nl;
206  }
207  }
208  Pout<< endl;
209 }
210 
211 
212 // Check if the two vertices that f0 and f1 share are in the same order on
213 // both faces.
215 (
216  const labelledTri& fA,
217  const labelledTri& fB
218 )
219 {
220  forAll(fA, fpA)
221  {
222  label fpB = findIndex(fB, fA[fpA]);
223 
224  if (fpB != -1)
225  {
226  // Get prev/next vertex on fA
227  label vA1 = fA[fA.fcIndex(fpA)];
228  label vAMin1 = fA[fA.rcIndex(fpA)];
229 
230  // Get prev/next vertex on fB
231  label vB1 = fB[fB.fcIndex(fpB)];
232  label vBMin1 = fB[fB.rcIndex(fpB)];
233 
234  if (vA1 == vB1 || vAMin1 == vBMin1)
235  {
236  return true;
237  }
238  else if (vA1 == vBMin1 || vAMin1 == vB1)
239  {
240  // shared vertices in opposite order.
241  return false;
242  }
243  else
244  {
246  << "Triangle:" << fA << " and triangle:" << fB
247  << " share a point but not an edge"
248  << abort(FatalError);
249  }
250  }
251  }
252 
254  << "Triangle:" << fA << " and triangle:" << fB
255  << " do not share an edge"
256  << abort(FatalError);
257 
258  return false;
259 }
260 
261 
263 (
264  Map<label>& visited,
265  const label key,
266  const label offset
267 )
268 {
269  Map<label>::iterator iter = visited.find(key);
270 
271  if (iter == visited.end())
272  {
273  visited.insert(key, offset);
274  }
275  else
276  {
277  iter() += offset;
278  }
279 }
280 
281 
282 // Calculate point to edge addressing for the face given by the edge
283 // subset faceEdges. Constructs facePointEdges which for every point
284 // gives a list of edge labels connected to it.
287 (
288  const edgeSurface& eSurf,
289  const label faceI
290 )
291 {
292  const pointField& points = eSurf.points();
293  const edgeList& edges = eSurf.edges();
294 
295  const labelList& fEdges = eSurf.faceEdges()[faceI];
296 
297  Map<DynamicList<label> > facePointEdges(4*fEdges.size());
298 
299  forAll(fEdges, i)
300  {
301  label edgeI = fEdges[i];
302 
303  const edge& e = edges[edgeI];
304 
305  // Add e.start to point-edges
306  Map<DynamicList<label> >::iterator iter =
307  facePointEdges.find(e.start());
308 
309  if (iter == facePointEdges.end())
310  {
311  DynamicList<label> oneEdge;
312  oneEdge.append(edgeI);
313  facePointEdges.insert(e.start(), oneEdge);
314  }
315  else
316  {
317  iter().append(edgeI);
318  }
319 
320  // Add e.end to point-edges
321  Map<DynamicList<label> >::iterator iter2 =
322  facePointEdges.find(e.end());
323 
324  if (iter2 == facePointEdges.end())
325  {
326  DynamicList<label> oneEdge;
327  oneEdge.append(edgeI);
328  facePointEdges.insert(e.end(), oneEdge);
329  }
330  else
331  {
332  iter2().append(edgeI);
333  }
334  }
335 
336  // Shrink it
337  forAllIter(Map< DynamicList<label> >, facePointEdges, iter)
338  {
339  iter().shrink();
340 
341  // Check on dangling points.
342  if (iter().empty())
343  {
345  << "Point:" << iter.key() << " used by too few edges:"
346  << iter() << abort(FatalError);
347  }
348  }
349 
350  if (debug & 2)
351  {
352  // Print facePointEdges
353  Pout<< "calcPointEdgeAddressing: face consisting of edges:" << endl;
354  forAll(fEdges, i)
355  {
356  label edgeI = fEdges[i];
357  const edge& e = edges[edgeI];
358  Pout<< " " << edgeI << ' ' << e
359  << points[e.start()]
360  << points[e.end()] << endl;
361  }
362 
363  Pout<< " Constructed point-edge adressing:" << endl;
364  forAllConstIter(Map< DynamicList<label> >, facePointEdges, iter)
365  {
366  Pout<< " vertex " << iter.key() << " is connected to edges "
367  << iter() << endl;
368  }
369  Pout<<endl;
370  }
371 
372  return facePointEdges;
373 }
374 
375 
376 // Find next (triangle or cut) edge label coming from point prevVertI on
377 // prevEdgeI doing a right handed walk (i.e. following right wall).
378 // Note: normal is provided externally. Could be deducted from angle between
379 // two triangle edges but these could be in line.
381 (
382  const edgeSurface& eSurf,
383  const Map<label>& visited,
384  const label faceI,
385  const vector& n,
386  const Map<DynamicList<label> >& facePointEdges,
387  const label prevEdgeI,
388  const label prevVertI
389 )
390 {
391  const pointField& points = eSurf.points();
392  const edgeList& edges = eSurf.edges();
393  const labelList& fEdges = eSurf.faceEdges()[faceI];
394 
395 
396  // Edges connected to prevVertI
397  const DynamicList<label>& connectedEdges = facePointEdges[prevVertI];
398 
399  if (connectedEdges.size() <= 1)
400  {
401  // Problem. Point not connected.
402  {
403  Pout<< "Writing face:" << faceI << " to face.obj" << endl;
404  OFstream str("face.obj");
405  writeOBJ(points, edges, fEdges, str);
406 
407  Pout<< "Writing connectedEdges edges to faceEdges.obj" << endl;
408  writeLocalOBJ(points, edges, connectedEdges, "faceEdges.obj");
409  }
410 
412  << "Problem: prevVertI:" << prevVertI << " on edge " << prevEdgeI
413  << " has less than 2 connected edges."
414  << " connectedEdges:" << connectedEdges << abort(FatalError);
415 
416  return -1;
417  }
418 
419  if (connectedEdges.size() == 2)
420  {
421  // Simple case. Take other edge
422  if (connectedEdges[0] == prevEdgeI)
423  {
424  if (debug & 2)
425  {
426  Pout<< "Stepped from edge:" << edges[prevEdgeI]
427  << " to edge:" << edges[connectedEdges[1]]
428  << " chosen from candidates:" << connectedEdges << endl;
429  }
430  return connectedEdges[1];
431  }
432  else
433  {
434  if (debug & 2)
435  {
436  Pout<< "Stepped from edge:" << edges[prevEdgeI]
437  << " to edge:" << edges[connectedEdges[0]]
438  << " chosen from candidates:" << connectedEdges << endl;
439  }
440  return connectedEdges[0];
441  }
442  }
443 
444 
445  // Multiple choices. Look at angle between edges.
446 
447  const edge& prevE = edges[prevEdgeI];
448 
449  // x-axis of coordinate system
450  vector e0 = n ^ (points[prevE.otherVertex(prevVertI)] - points[prevVertI]);
451  e0 /= mag(e0) + VSMALL;
452 
453  // Get y-axis of coordinate system
454  vector e1 = n ^ e0;
455 
456  if (mag(mag(e1) - 1) > SMALL)
457  {
458  {
459  Pout<< "Writing face:" << faceI << " to face.obj" << endl;
460  OFstream str("face.obj");
461  writeOBJ(points, edges, fEdges, str);
462 
463  Pout<< "Writing connectedEdges edges to faceEdges.obj" << endl;
464  writeLocalOBJ(points, edges, connectedEdges, "faceEdges.obj");
465  }
466 
468  << "Unnormalized normal e1:" << e1
469  << " formed from cross product of e0:" << e0 << " n:" << n
470  << abort(FatalError);
471  }
472 
473 
474  //
475  // Determine maximum angle over all connected (unvisited) edges.
476  //
477 
478  scalar maxAngle = -GREAT;
479  label maxEdgeI = -1;
480 
481  forAll(connectedEdges, connI)
482  {
483  label edgeI = connectedEdges[connI];
484 
485  if (edgeI != prevEdgeI)
486  {
487  label stat = visited[edgeI];
488 
489  const edge& e = edges[edgeI];
490 
491  // Find out whether walk of edge from prevVert would be acceptible.
492  if
493  (
494  stat == UNVISITED
495  || (
496  stat == STARTTOEND
497  && prevVertI == e[1]
498  )
499  || (
500  stat == ENDTOSTART
501  && prevVertI == e[0]
502  )
503  )
504  {
505  // Calculate angle of edge with respect to base e0, e1
506  vector vec =
507  n ^ (points[e.otherVertex(prevVertI)] - points[prevVertI]);
508 
509  vec /= mag(vec) + VSMALL;
510 
511  scalar angle = pseudoAngle(e0, e1, vec);
512 
513  if (angle > maxAngle)
514  {
515  maxAngle = angle;
516  maxEdgeI = edgeI;
517  }
518  }
519  }
520  }
521 
522 
523  if (maxEdgeI == -1)
524  {
525  // No unvisited edge found
526  {
527  Pout<< "Writing face:" << faceI << " to face.obj" << endl;
528  OFstream str("face.obj");
529  writeOBJ(points, edges, fEdges, str);
530 
531  Pout<< "Writing connectedEdges edges to faceEdges.obj" << endl;
532  writeLocalOBJ(points, edges, connectedEdges, "faceEdges.obj");
533  }
534 
536  << "Trying to step from edge " << edges[prevEdgeI]
537  << ", vertex " << prevVertI
538  << " but cannot find 'unvisited' edges among candidates:"
539  << connectedEdges
540  << abort(FatalError);
541  }
542 
543  if (debug & 2)
544  {
545  Pout<< "Stepped from edge:" << edges[prevEdgeI]
546  << " to edge:" << maxEdgeI << " angle:" << edges[maxEdgeI]
547  << " with angle:" << maxAngle
548  << endl;
549  }
550 
551  return maxEdgeI;
552 }
553 
554 
555 // Create (polygonal) face by walking full circle starting from startVertI on
556 // startEdgeI.
557 // Uses nextEdge(..) to do the walking. Returns face. Updates visited with
558 // the labels of visited edges.
560 (
561  const edgeSurface& eSurf,
562  const label faceI,
563  const vector& n,
564  const Map<DynamicList<label> >& facePointEdges,
565 
566  const label startEdgeI,
567  const label startVertI,
568 
569  Map<label>& visited
570 )
571 {
572  const pointField& points = eSurf.points();
573  const edgeList& edges = eSurf.edges();
574 
575  // Overestimate size of face
576  face f(eSurf.faceEdges()[faceI].size());
577 
578  label fp = 0;
579 
580  label vertI = startVertI;
581  label edgeI = startEdgeI;
582 
583  while (true)
584  {
585  const edge& e = edges[edgeI];
586 
587  if (debug & 2)
588  {
589  Pout<< "Now at:" << endl
590  << " edge:" << edgeI << " vertices:" << e
591  << " positions:" << points[e.start()] << ' ' << points[e.end()]
592  << " vertex:" << vertI << endl;
593  }
594 
595  // Mark edge as visited
596  if (e[0] == vertI)
597  {
598  visited[edgeI] |= STARTTOEND;
599  }
600  else
601  {
602  visited[edgeI] |= ENDTOSTART;
603  }
604 
605 
606  // Store face vertex
607  f[fp++] = vertI;
608 
609  // step to other vertex
610  vertI = e.otherVertex(vertI);
611 
612  if (vertI == startVertI)
613  {
614  break;
615  }
616 
617  // step from vertex to next edge
618  edgeI = nextEdge
619  (
620  eSurf,
621  visited,
622  faceI,
623  n,
624  facePointEdges,
625  edgeI,
626  vertI
627  );
628  }
629 
630  f.setSize(fp);
631 
632  return f;
633 }
634 
635 
637 (
638  const edgeSurface& eSurf,
639  const label faceI,
640  const Map<DynamicList<label> >& facePointEdges,
641  const Map<label>& pointVisited,
642  const point& pt,
643  const label excludePointI,
644 
645  label& minVertI,
646  scalar& minDist
647 )
648 {
649  minVertI = -1;
650  minDist = GREAT;
651 
652  forAllConstIter(Map<label>, pointVisited, iter)
653  {
654  label pointI = iter.key();
655 
656  if (pointI != excludePointI)
657  {
658  label nVisits = iter();
659 
660  if (nVisits == 2*facePointEdges[pointI].size())
661  {
662  // Fully visited (i.e. both sides of all edges)
663  scalar dist = mag(eSurf.points()[pointI] - pt);
664 
665  if (dist < minDist)
666  {
667  minDist = dist;
668  minVertI = pointI;
669  }
670  }
671  }
672  }
673 
674  if (minVertI == -1)
675  {
676  const labelList& fEdges = eSurf.faceEdges()[faceI];
677 
679  << "Dumping face edges to faceEdges.obj" << endl;
680 
681  writeLocalOBJ(eSurf.points(), eSurf.edges(), fEdges, "faceEdges.obj");
682 
684  << "No fully visited edge found for pt " << pt
685  << abort(FatalError);
686  }
687 }
688 
689 
690 // Sometimes there are bunches of edges that are not connected to the
691 // other edges in the face. This routine tries to connect the loose
692 // edges up to the 'proper' edges by adding two extra edges between a
693 // properly connected edge and an unconnected one. Since at this level the
694 // adressing is purely in form of points and a cloud of edges this can
695 // be easily done.
696 // (edges are to existing points. Don't want to introduce new vertices here
697 // since then also neighbouring face would have to be split)
699 (
700  const triSurface& surf,
701  const label faceI,
702  const Map<DynamicList<label> >& facePointEdges,
703  const Map<label>& visited,
704  edgeSurface& eSurf
705 )
706 {
707  // Count the number of times point has been visited so we
708  // can compare number to facePointEdges.
709  Map<label> pointVisited(2*facePointEdges.size());
710 
711  forAllConstIter(Map<label>, visited, iter)
712  {
713  label edgeI = iter.key();
714  const edge& e = eSurf.edges()[edgeI];
715  label stat = iter();
716 
717  if (stat == STARTTOEND || stat == ENDTOSTART)
718  {
719  incCount(pointVisited, e[0], 1);
720  incCount(pointVisited, e[1], 1);
721  }
722  else if (stat == BOTH)
723  {
724  incCount(pointVisited, e[0], 2);
725  incCount(pointVisited, e[1], 2);
726  }
727  else if (stat == UNVISITED)
728  {
729  incCount(pointVisited, e[0], 0);
730  incCount(pointVisited, e[1], 0);
731  }
732  }
733 
734 
735  if (debug)
736  {
737  forAllConstIter(Map<label>, pointVisited, iter)
738  {
739  label pointI = iter.key();
740 
741  label nVisits = iter();
742 
743  Pout<< "point:" << pointI << " nVisited:" << nVisits
744  << " pointEdges:" << facePointEdges[pointI].size() << endl;
745  }
746  }
747 
748 
749  // Find nearest point pair where one is not fully visited and
750  // the other is.
751 
752  label visitedVert0 = -1;
753  label unvisitedVert0 = -1;
754 
755  {
756  scalar minDist = GREAT;
757 
758  forAllConstIter(Map<DynamicList<label> >, facePointEdges, iter)
759  {
760  label pointI = iter.key();
761 
762  label nVisits = pointVisited[pointI];
763 
764  const DynamicList<label>& pEdges = iter();
765 
766  if (nVisits < 2*pEdges.size())
767  {
768  // Not fully visited. Find nearest fully visited.
769 
770  scalar nearDist;
771  label nearVertI;
772 
773  findNearestVisited
774  (
775  eSurf,
776  faceI,
777  facePointEdges,
778  pointVisited,
779  eSurf.points()[pointI],
780  -1, // Do not exclude vertex
781  nearVertI,
782  nearDist
783  );
784 
785 
786  if (nearDist < minDist)
787  {
788  minDist = nearDist;
789  visitedVert0 = nearVertI;
790  unvisitedVert0 = pointI;
791  }
792  }
793  }
794  }
795 
796 
797  // Find second intersection.
798  {
799  scalar minDist = GREAT;
800 
801  forAllConstIter(Map<DynamicList<label> >, facePointEdges, iter)
802  {
803  label pointI = iter.key();
804 
805  if (pointI != unvisitedVert0)
806  {
807  label nVisits = pointVisited[pointI];
808 
809  const DynamicList<label>& pEdges = iter();
810 
811  if (nVisits < 2*pEdges.size())
812  {
813  // Not fully visited. Find nearest fully visited.
814 
815  scalar nearDist;
816  label nearVertI;
817 
818  findNearestVisited
819  (
820  eSurf,
821  faceI,
822  facePointEdges,
823  pointVisited,
824  eSurf.points()[pointI],
825  visitedVert0, // vertex to exclude
826  nearVertI,
827  nearDist
828  );
829 
830 
831  if (nearDist < minDist)
832  {
833  minDist = nearDist;
834  }
835  }
836  }
837  }
838  }
839 
840 
841  // Add the new intersection edges to the edgeSurface
842  edgeList additionalEdges(1);
843  additionalEdges[0] = edge(visitedVert0, unvisitedVert0);
844 
845  eSurf.addIntersectionEdges(faceI, additionalEdges);
846 
847  if (debug)
848  {
849  fileName newFName("face_" + Foam::name(faceI) + "_newEdges.obj");
850  Pout<< "Dumping face:" << faceI << " to " << newFName << endl;
851  writeLocalOBJ
852  (
853  eSurf.points(),
854  eSurf.edges(),
855  eSurf.faceEdges()[faceI],
856  newFName
857  );
858  }
859 
860  // Retry splitFace. Use recursion since is rare situation.
861  return splitFace(surf, faceI, eSurf);
862 }
863 
864 
866 (
867  const triSurface& surf,
868  const label faceI,
869  edgeSurface& eSurf
870 )
871 {
872  // Alias
873  const pointField& points = eSurf.points();
874  const edgeList& edges = eSurf.edges();
875  const labelList& fEdges = eSurf.faceEdges()[faceI];
876 
877  // Create local (for the face only) point-edge connectivity.
878  Map<DynamicList<label> > facePointEdges
879  (
880  calcPointEdgeAddressing
881  (
882  eSurf,
883  faceI
884  )
885  );
886 
887  // Order in which edges have been walked. Initialize outside edges.
888  Map<label> visited(fEdges.size()*2);
889 
890  forAll(fEdges, i)
891  {
892  label edgeI = fEdges[i];
893 
894  if (eSurf.isSurfaceEdge(edgeI))
895  {
896  // Edge is edge from original surface so an outside edge for
897  // the current face.
898  label surfEdgeI = eSurf.parentEdge(edgeI);
899 
900  label owner = surf.edgeOwner()[surfEdgeI];
901 
902  if
903  (
904  owner == faceI
905  || sameEdgeOrder
906  (
907  surf.localFaces()[owner],
908  surf.localFaces()[faceI]
909  )
910  )
911  {
912  // Edge is in same order as current face.
913  // Mark off the opposite order.
914  visited.insert(edgeI, ENDTOSTART);
915  }
916  else
917  {
918  // Edge is in same order as current face.
919  // Mark off the opposite order.
920  visited.insert(edgeI, STARTTOEND);
921  }
922  }
923  else
924  {
925  visited.insert(edgeI, UNVISITED);
926  }
927  }
928 
929 
930 
931  // Storage for faces
932  DynamicList<face> faces(fEdges.size());
933 
934  while (true)
935  {
936  // Find starting edge:
937  // - unvisted triangle edge
938  // - once visited intersection edge
939  // Give priority to triangle edges.
940  label startEdgeI = -1;
941  label startVertI = -1;
942 
943  forAll(fEdges, i)
944  {
945  label edgeI = fEdges[i];
946 
947  const edge& e = edges[edgeI];
948 
949  label stat = visited[edgeI];
950 
951  if (stat == STARTTOEND)
952  {
953  startEdgeI = edgeI;
954  startVertI = e[1];
955 
956  if (eSurf.isSurfaceEdge(edgeI))
957  {
958  break;
959  }
960  }
961  else if (stat == ENDTOSTART)
962  {
963  startEdgeI = edgeI;
964  startVertI = e[0];
965 
966  if (eSurf.isSurfaceEdge(edgeI))
967  {
968  break;
969  }
970  }
971  }
972 
973  if (startEdgeI == -1)
974  {
975  break;
976  }
977 
978  //Pout<< "splitFace: starting walk from edge:" << startEdgeI
979  // << ' ' << edges[startEdgeI] << " vertex:" << startVertI << endl;
980 
982  //printVisit(eSurf.edges(), fEdges, visited);
983 
984  //{
985  // Pout<< "Writing face:" << faceI << " to face.obj" << endl;
986  // OFstream str("face.obj");
987  // writeOBJ(eSurf.points(), eSurf.edges(), fEdges, str);
988  //}
989 
990  faces.append
991  (
992  walkFace
993  (
994  eSurf,
995  faceI,
996  surf.faceNormals()[faceI],
997  facePointEdges,
998 
999  startEdgeI,
1000  startVertI,
1001 
1002  visited
1003  )
1004  );
1005  }
1006 
1007 
1008  // Check if any unvisited edges left.
1009  forAll(fEdges, i)
1010  {
1011  label edgeI = fEdges[i];
1012 
1013  label stat = visited[edgeI];
1014 
1015  if (eSurf.isSurfaceEdge(edgeI) && stat != BOTH)
1016  {
1018  << "Dumping face edges to faceEdges.obj" << endl;
1019 
1020  writeLocalOBJ(points, edges, fEdges, "faceEdges.obj");
1021 
1023  << "Problem: edge " << edgeI << " vertices "
1024  << edges[edgeI] << " on face " << faceI
1025  << " has visited status " << stat << " from a "
1026  << "righthanded walk along all"
1027  << " of the triangle edges. Are the original surfaces"
1028  << " closed and non-intersecting?"
1029  << abort(FatalError);
1030  }
1031  else if (stat != BOTH)
1032  {
1033  // Redo face after introducing extra edge. Edge introduced
1034  // should be one nearest to any fully visited edge.
1035  return resplitFace
1036  (
1037  surf,
1038  faceI,
1039  facePointEdges,
1040  visited,
1041  eSurf
1042  );
1043  }
1044  }
1045 
1046 
1047  // See if normal needs flipping.
1048  faces.shrink();
1049 
1050  vector n = faces[0].normal(eSurf.points());
1051 
1052  if ((n & surf.faceNormals()[faceI]) < 0)
1053  {
1054  forAll(faces, i)
1055  {
1056  reverse(faces[i]);
1057  }
1058  }
1059 
1060  return faces;
1061 }
1062 
1063 
1064 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1065 
1066 // Null constructor
1068 :
1069  triSurface(),
1070  intersectionEdges_(0),
1071  faceMap_(0),
1072  nSurfacePoints_(0)
1073 {}
1074 
1075 
1076 // Construct from components
1078 :
1079  triSurface(surf),
1080  intersectionEdges_(0),
1081  faceMap_(0),
1082  nSurfacePoints_(0)
1083 {}
1084 
1085 
1086 // Construct from surface and intersection
1089  const triSurface& surf,
1090  const bool isFirstSurface,
1091  const surfaceIntersection& inter
1092 )
1093 :
1094  triSurface(),
1095  intersectionEdges_(0),
1096  faceMap_(0),
1097  nSurfacePoints_(surf.nPoints())
1098 {
1099  if (inter.cutPoints().empty() && inter.cutEdges().empty())
1100  {
1101  // No intersection. Make straight copy.
1102  triSurface::operator=(surf);
1103 
1104  // Identity for face map
1105  faceMap_.setSize(size());
1106 
1107  forAll(faceMap_, faceI)
1108  {
1109  faceMap_[faceI] = faceI;
1110  }
1111  return;
1112  }
1113 
1114 
1115  // Calculate face-edge addressing for surface + intersection.
1116  edgeSurface eSurf(surf, isFirstSurface, inter);
1117 
1118  // Update point information for any removed points. (when are they removed?
1119  // - but better make sure)
1120  nSurfacePoints_ = eSurf.nSurfacePoints();
1121 
1122  // Now we have full points, edges and edge addressing for surf. Start
1123  // extracting faces and triangulate them.
1124 
1125  // Storage for new triangles of surface.
1126  DynamicList<labelledTri> newTris(eSurf.edges().size()/2);
1127 
1128  // Start in newTris for decomposed face.
1129  labelList startTriI(surf.size(), 0);
1130 
1131  forAll(surf, faceI)
1132  {
1133  startTriI[faceI] = newTris.size();
1134 
1135  if (eSurf.faceEdges()[faceI].size() != surf.faceEdges()[faceI].size())
1136  {
1137  // Face has been cut by intersection.
1138  // Cut face into multiple subfaces. Use faceEdge information
1139  // from edgeSurface only. (original triSurface 'surf' is used for
1140  // faceNormals and regionnumber only)
1141  faceList newFaces
1142  (
1143  splitFace
1144  (
1145  surf,
1146  faceI, // current triangle
1147  eSurf // face-edge description of surface
1148  // + intersection
1149  )
1150  );
1151  forAll(newFaces, newFaceI)
1152  {
1153  const face& newF = newFaces[newFaceI];
1154  const vector& n = surf.faceNormals()[faceI];
1155  const label region = surf[faceI].region();
1156 
1157  faceTriangulation tris(eSurf.points(), newF, n);
1158 
1159  forAll(tris, triI)
1160  {
1161  const triFace& t = tris[triI];
1162 
1163  forAll(t, i)
1164  {
1165  if (t[i] < 0 || t[i] >= eSurf.points().size())
1166  {
1168  << "Face triangulation of face " << faceI
1169  << " uses points outside range 0.."
1170  << eSurf.points().size()-1 << endl
1171  << "Triangulation:"
1172  << tris << abort(FatalError);
1173  }
1174  }
1175 
1176  newTris.append(labelledTri(t[0], t[1], t[2], region));
1177  }
1178  }
1179  }
1180  else
1181  {
1182  // Face has not been cut at all. No need to renumber vertices since
1183  // eSurf keeps surface vertices first.
1184  newTris.append(surf.localFaces()[faceI]);
1185  }
1186  }
1187 
1188  newTris.shrink();
1189 
1190 
1191  // Construct triSurface. Note that addressing will be compact since
1192  // edgeSurface is compact.
1193  triSurface::operator=
1194  (
1195  triSurface
1196  (
1197  newTris,
1198  surf.patches(),
1199  eSurf.points()
1200  )
1201  );
1202 
1203  // Construct mapping back into original surface
1204  faceMap_.setSize(size());
1205 
1206  for (label faceI = 0; faceI < surf.size()-1; faceI++)
1207  {
1208  for (label triI = startTriI[faceI]; triI < startTriI[faceI+1]; triI++)
1209  {
1210  faceMap_[triI] = faceI;
1211  }
1212  }
1213  for (label triI = startTriI[surf.size()-1]; triI < size(); triI++)
1214  {
1215  faceMap_[triI] = surf.size()-1;
1216  }
1217 
1218 
1219  // Find edges on *this which originate from 'cuts'. (i.e. newEdgeI >=
1220  // nSurfaceEdges) Renumber edges into local triSurface numbering.
1221 
1222  intersectionEdges_.setSize(eSurf.edges().size() - eSurf.nSurfaceEdges());
1223 
1224  label intersectionEdgeI = 0;
1225 
1226  for
1227  (
1228  label edgeI = eSurf.nSurfaceEdges();
1229  edgeI < eSurf.edges().size();
1230  edgeI++
1231  )
1232  {
1233  // Get edge vertices in triSurface local numbering
1234  const edge& e = eSurf.edges()[edgeI];
1235  label surfStartI = meshPointMap()[e.start()];
1236  label surfEndI = meshPointMap()[e.end()];
1237 
1238  // Find edge connected to surfStartI which also uses surfEndI.
1239  label surfEdgeI = -1;
1240 
1241  const labelList& pEdges = pointEdges()[surfStartI];
1242 
1243  forAll(pEdges, i)
1244  {
1245  const edge& surfE = edges()[pEdges[i]];
1246 
1247  // Edge already connected to surfStart for sure. See if also
1248  // connects to surfEnd
1249  if (surfE.start() == surfEndI || surfE.end() == surfEndI)
1250  {
1251  surfEdgeI = pEdges[i];
1252 
1253  break;
1254  }
1255  }
1256 
1257  if (surfEdgeI != -1)
1258  {
1259  intersectionEdges_[intersectionEdgeI++] = surfEdgeI;
1260  }
1261  else
1262  {
1264  << "Cannot find edge among candidates " << pEdges
1265  << " which uses points " << surfStartI
1266  << " and " << surfEndI
1267  << abort(FatalError);
1268  }
1269  }
1270 }
1271 
1272 
1273 // ************************************************************************* //
Foam::edgeSurface::addIntersectionEdges
void addIntersectionEdges(const label faceI, const edgeList &)
Add intersection edges to a face. Used for connecting.
Definition: edgeSurface.C:343
Foam::intersectedSurface::findNearestVisited
static void findNearestVisited(const edgeSurface &eSurf, const label faceI, const Map< DynamicList< label > > &facePointEdges, const Map< label > &pointVisited, const point &pt, const label excludeFaceI, label &minVertI, scalar &minDist)
For resplitFace: find nearest (to pt) fully visited point. Return.
Definition: intersectedSurface.C:637
meshTools.H
Foam::intersectedSurface::intersectedSurface
intersectedSurface()
Construct null.
Definition: intersectedSurface.C:1067
Foam::intersectedSurface::calcPointEdgeAddressing
static Map< DynamicList< label > > calcPointEdgeAddressing(const edgeSurface &, const label faceI)
Calculate point-edge addressing for single face only.
Definition: intersectedSurface.C:287
forAllIter
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:431
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::intersectedSurface::walkFace
static face walkFace(const edgeSurface &eSurf, const label faceI, const vector &n, const Map< DynamicList< label > > &facePointEdges, const label startEdgeI, const label startVertI, Map< label > &visited)
Walk path along edges in face. Used by splitFace.
Definition: intersectedSurface.C:560
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
writeOBJ
void writeOBJ(Ostream &os, label &vertI, const tetPoints &tet)
Definition: Test-tetTetOverlap.C:38
Foam::findIndex
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
Foam::DynamicList< label >
edgeSurface.H
Foam::intersectedSurface::writeLocalOBJ
static void writeLocalOBJ(const pointField &points, const edgeList &edges, const labelList &faceEdges, const fileName &)
Debug:Dump selected edges to stream. Renumbers vertices to.
Definition: intersectedSurface.C:103
Foam::intersectedSurface::sameEdgeOrder
static bool sameEdgeOrder(const labelledTri &fA, const labelledTri &fB)
Check if the two vertices that f0 and f1 share are in the same.
Definition: intersectedSurface.C:215
Foam::intersectedSurface::ENDTOSTART
static const label ENDTOSTART
Definition: intersectedSurface.H:89
Foam::edgeSurface::isSurfaceEdge
bool isSurfaceEdge(const label edgeI) const
Definition: edgeSurface.H:157
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
Foam::intersectedSurface::BOTH
static const label BOTH
Definition: intersectedSurface.H:90
Foam::Map< label >
Foam::intersectedSurface::incCount
static void incCount(Map< label > &visited, const label key, const label offset)
Increment data for key. (start from 0 if not found)
Definition: intersectedSurface.C:263
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::intersectedSurface::resplitFace
static faceList resplitFace(const triSurface &surf, const label faceI, const Map< DynamicList< label > > &facePointEdges, const Map< label > &visited, edgeSurface &eSurf)
Fallback for if splitFace fails to connect all.
Definition: intersectedSurface.C:699
Foam::PrimitivePatch::faceEdges
const labelListList & faceEdges() const
Return face-edge addressing.
Definition: PrimitivePatchTemplate.C:312
Foam::edgeSurface::points
const pointField & points() const
Definition: edgeSurface.H:137
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
faceList.H
Foam::triSurface::patches
const geometricSurfacePatchList & patches() const
Definition: triSurface.H:301
Foam::intersectedSurface::UNVISITED
static const label UNVISITED
Definition: intersectedSurface.H:87
Foam::FixedList::fcIndex
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: FixedListI.H:115
forAllConstIter
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
OFstream.H
surfaceIntersection.H
Foam::intersectedSurface::nextEdge
static label nextEdge(const edgeSurface &eSurf, const Map< label > &visited, const label faceI, const vector &n, const Map< DynamicList< label > > &facePointEdges, const label prevEdgeI, const label prevVertI)
Choose edge out of candidates (facePointEdges) according to.
Definition: intersectedSurface.C:381
Foam::edge::end
label end() const
Return end vertex label.
Definition: edgeI.H:92
faceTriangulation.H
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::surfaceIntersection
Basic surface-surface intersection description. Constructed from two surfaces it creates a descriptio...
Definition: surfaceIntersection.H:80
error.H
Foam::triSurface
Triangulated surface description with patch information.
Definition: triSurface.H:57
treeBoundBox.H
Foam::nl
static const char nl
Definition: Ostream.H:260
SeriousErrorInFunction
#define SeriousErrorInFunction
Report an error message using Foam::SeriousError.
Definition: messageStream.H:237
Foam::triSurface::operator=
void operator=(const triSurface &)
Definition: triSurface.C:1122
Foam::DynamicList::shrink
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
Foam::meshTools::walkFace
label walkFace(const primitiveMesh &, const label faceI, const label startEdgeI, const label startVertI, const label nEdges)
Returns label of edge nEdges away from startEdge (in the direction.
Definition: meshTools.C:580
Foam::edgeSurface::nSurfacePoints
label nSurfacePoints() const
Definition: edgeSurface.H:142
Foam::surfaceIntersection::cutPoints
const pointField & cutPoints() const
Definition: surfaceIntersection.C:1132
Foam::edgeSurface::edges
const edgeList & edges() const
Definition: edgeSurface.H:147
Foam::PrimitivePatch::nPoints
label nPoints() const
Return number of points supporting patch faces.
Definition: PrimitivePatchTemplate.H:293
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::FatalError
error FatalError
intersectedSurface.H
Foam::intersectedSurface::STARTTOEND
static const label STARTTOEND
Definition: intersectedSurface.H:88
Foam::pseudoAngle
scalar pseudoAngle(const vector &e0, const vector &e1, const vector &vec)
Estimate angle of vec in coordinate system (e0, e1, e0^e1).
Definition: transform.H:223
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::Vector::z
const Cmpt & z() const
Definition: VectorI.H:77
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Foam::intersectedSurface::splitFace
static faceList splitFace(const triSurface &surf, const label faceI, edgeSurface &eSurf)
Main face splitting routine. Gets overall points and edges and.
Definition: intersectedSurface.C:866
Foam::e
const double e
Elementary charge.
Definition: doubleFloat.H:94
Foam::surfaceIntersection::cutEdges
const edgeList & cutEdges() const
Definition: surfaceIntersection.C:1138
Foam::edgeSurface
Description of surface in form of 'cloud of edges'.
Definition: edgeSurface.H:73
Foam::triSurface::edgeOwner
const labelList & edgeOwner() const
If 2 face neighbours: label of face where ordering of edge.
Definition: triSurface.C:777
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::OFstream
Output to file stream.
Definition: OFstream.H:81
Foam::faceTriangulation
Triangulation of faces. Handles concave polygons as well (inefficiently)
Definition: faceTriangulation.H:65
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::edge::start
label start() const
Return start vertex label.
Definition: edgeI.H:81
Foam::triFace
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:68
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::PrimitivePatch::faceNormals
const Field< PointType > & faceNormals() const
Return face normals for patch.
Definition: PrimitivePatchTemplate.C:520
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
Foam::edgeSurface::faceEdges
const labelListList & faceEdges() const
From face to our edges_.
Definition: edgeSurface.H:181
Foam::edgeSurface::nSurfaceEdges
label nSurfaceEdges() const
Definition: edgeSurface.H:152
Foam::labelledTri
Triangle with additional region number.
Definition: labelledTri.H:49
Foam::PrimitivePatch::localFaces
const List< Face > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatchTemplate.C:372
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
DynamicList.H
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
transform.H
3D tensor transformation operations.
Foam::edgeSurface::parentEdge
label parentEdge(const label edgeI) const
Parent edge (original surface edge this edge came from).
Definition: edgeSurface.H:164
Foam::intersectedSurface::writeOBJ
static void writeOBJ(const pointField &points, const edgeList &edges, Ostream &os)
Debug:Dump edges to stream. Mantains vertex numbering.
Definition: intersectedSurface.C:56
Foam::FixedList::rcIndex
label rcIndex(const label i) const
Return the reverse circular index, i.e. the previous index.
Definition: FixedListI.H:122
Foam::edge::otherVertex
label otherVertex(const label a) const
Given one vertex, return the other.
Definition: edgeI.H:103
Foam::intersectedSurface::printVisit
static void printVisit(const edgeList &edges, const labelList &edgeLabels, const Map< label > &visited)
Debug:Print visited status.
Definition: intersectedSurface.C:172
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::reverse
void reverse(UList< T > &, const label n)
Definition: UListI.H:322