surfaceIntersection.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "surfaceIntersection.H"
30 #include "triSurfaceSearch.H"
31 #include "OBJstream.H"
32 #include "labelPairHashes.H"
33 #include "bitSet.H"
34 #include "triSurface.H"
35 #include "pointIndexHit.H"
36 #include "mergePoints.H"
37 #include "plane.H"
38 #include "edgeIntersections.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44  defineTypeNameAndDebug(surfaceIntersection, 0);
45 }
46 
47 const Foam::Enum
48 <
50 >
52 ({
53  { intersectionType::SELF, "self" },
54  { intersectionType::SELF_REGION, "region" },
55  { intersectionType::NONE, "none" },
56 });
57 
58 
59 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
60 
61 void Foam::surfaceIntersection::setOptions(const dictionary& dict)
62 {
63  dict.readIfPresent("tolerance", tolerance_);
64  dict.readIfPresent("allowEdgeHits", allowEdgeHits_);
65  dict.readIfPresent("snap", snapToEnd_);
66  dict.readIfPresent("warnDegenerate", warnDegenerate_);
67 }
68 
69 
70 void Foam::surfaceIntersection::storeIntersection
71 (
72  const enum intersectionType cutFrom,
73  const labelList& facesA,
74  const label faceB,
75  const UList<point>& allCutPoints,
76  const label cutPointId,
77  DynamicList<edge>& allCutEdges
78 )
79 {
80  // Our lookup for two faces - populate with faceB (invariant)
81  // Normally always have face from the first surface as first element
82  labelPair twoFaces(faceB, faceB);
83 
84  forAll(facesA, facesAI)
85  {
86  const label faceA = facesA[facesAI];
87 
88  switch (cutFrom)
89  {
91  {
92  // faceA from 1st, faceB from 2nd
93  twoFaces.first() = faceA;
94  break;
95  }
97  {
98  // faceA from 2nd, faceB from 1st
99  twoFaces.second() = faceA;
100  break;
101  }
104  {
105  // Lookup should be commutativity - use sorted order
106  if (faceA < faceB)
107  {
108  twoFaces.first() = faceA;
109  twoFaces.second() = faceB;
110  }
111  else
112  {
113  twoFaces.first() = faceB;
114  twoFaces.second() = faceA;
115  }
116  break;
117  }
118 
120  return;
121  break;
122  }
123 
124 
125  // Get existing edge, or create a null edge (with -1)
126  edge& thisEdge = facePairToEdge_(twoFaces);
127  const label pointCount = thisEdge.count();
128 
129  if (pointCount == 0)
130  {
131  // First intersection of the faces - record it.
132  thisEdge.insert(cutPointId);
133 
134  if (debug & 4)
135  {
136  Pout<< "intersect faces " << twoFaces
137  << " point-1: " << cutPointId << " = "
138  << allCutPoints[cutPointId] << endl;
139  }
140  continue;
141  }
142  else if (pointCount == 2)
143  {
144  // This occurs for ugly surfaces with shards that result in multiple
145  // cuts very near a snapped end point.
146  if (debug & 4)
147  {
148  Pout<< "suppressed double intersection " << twoFaces
149  << thisEdge << endl;
150  }
151  continue;
152  }
153 
154  if (thisEdge.insert(cutPointId))
155  {
156  // Second intersection of the faces - this is an edge,
157  // with special treatment:
158  // - avoid duplicate points: addressed by the insert() above
159  // - avoid degenerate lengths
160  // - avoid duplicate edges - can occur with really dirty geometry
161 
162  if (edgeToId_.found(thisEdge))
163  {
164  // Already have this edgeId, but not for this intersection.
165  thisEdge.sort();
166  if (facePairToEdge_.insert(twoFaces, thisEdge))
167  {
168  if (debug & 4)
169  {
170  Pout<< "reuse edge - faces " << twoFaces << " edge#"
171  << edgeToId_[thisEdge] << " edge " << thisEdge
172  << " = " << thisEdge.line(allCutPoints)
173  << endl;
174  }
175  }
176  }
177  else if (thisEdge.mag(allCutPoints) < SMALL)
178  {
179  // Degenerate length
180  // - eg, end snapping was disabled or somehow failed.
181 
182  // Don't normally emit warnings, since these also arise for
183  // manifold connections. For example,
184  //
185  // e1| /e2
186  // | /
187  // |/
188  // ----.---- plane
189  //
190  // The plane is correctly pierced at the '.' by both edge-1
191  // and edge-2, which belong to the same originating face.
192 
193  // Filter/merge away the extraneous points later.
194  if (warnDegenerate_ > 0)
195  {
196  --warnDegenerate_;
198  << "Degenerate edge between faces " << twoFaces
199  << " on 1st/2nd surface with points "
200  << thisEdge.line(allCutPoints)
201  << endl;
202  }
203  else if (debug & 4)
204  {
205  Pout<< "degenerate edge face-pair " << twoFaces << " "
206  << thisEdge[0] << " point " << allCutPoints[thisEdge[0]]
207  << endl;
208  }
209 
210  // This is a failed edge - undo this second interaction
211  thisEdge.erase(cutPointId);
212  }
213  else
214  {
215  // This is a new edge.
216  const label edgeId = allCutEdges.size();
217 
218  if (facePairToEdgeId_.insert(twoFaces, edgeId))
219  {
220  // Record complete (line) intersection of two faces
221  thisEdge.sort();
222  edgeToId_.insert(thisEdge, edgeId);
223  allCutEdges.append(thisEdge);
224 
225  if (debug & 4)
226  {
227  Pout<< "create edge - faces " << twoFaces << " edge#"
228  << edgeId << " edge " << thisEdge
229  << " = " << thisEdge.line(allCutPoints)
230  << endl;
231  }
232  }
233  else
234  {
235  // Faces already had an intersection
236  // This should not fail, but for safety.
237  Info<<"WARN " << twoFaces
238  << " already intersected= " << thisEdge << endl;
239  thisEdge.erase(cutPointId);
240  }
241  }
242  }
243  else
244  {
245  // Duplicate point - usually zero-length edge from snapping
246  // - can discard this face/face interaction entirely
247  facePairToEdge_.erase(twoFaces);
248  }
249  }
250 }
251 
252 
253 // Classify cut of edge of surface1 with surface2:
254 // 1- point of edge hits point on surface2
255 // 2- edge pierces point on surface2
256 // 3- point of edge hits edge on surface2
257 // 4- edge pierces edge on surface2
258 // 5- point of edge hits face on surface2
259 // 6- edge pierces face on surface2
260 //
261 // Note that handling of 2 and 4 should be the same but with surface1 and
262 // surface2 reversed.
263 void Foam::surfaceIntersection::classifyHit
264 (
265  const triSurface& surf1,
266  const scalarField& surf1PointTol,
267  const triSurface& surf2,
268  const enum intersectionType cutFrom,
269  const label edgeI,
270  const pointIndexHit& pHit,
271 
272  DynamicList<point>& allCutPoints,
273  DynamicList<edge>& allCutEdges,
274  List<DynamicList<label>>& surfEdgeCuts
275 )
276 {
277  const edge& e1 = surf1.edges()[edgeI];
278 
279  const labelList& facesA = surf1.edgeFaces()[edgeI];
280 
281  // Label of face on surface2 edgeI intersected
282  label surf2Facei = pHit.index();
283 
284  // Classify point on surface2
285 
286  const triSurface::face_type& f2 = surf2.localFaces()[surf2Facei];
287  const pointField& surf1Pts = surf1.localPoints();
288  const pointField& surf2Pts = surf2.localPoints();
289 
290  label nearType, nearLabel;
291 
292  f2.nearestPointClassify(pHit.hitPoint(), surf2Pts, nearType, nearLabel);
293 
294  // Classify points on edge of surface1
295  const label edgeEnd =
296  classify
297  (
298  surf1PointTol[e1.start()],
299  surf1PointTol[e1.end()],
300  pHit.hitPoint(),
301  e1,
302  surf1Pts
303  );
304 
305  if (nearType == triPointRef::POINT)
306  {
307  if (edgeEnd >= 0)
308  {
309  // 1. Point hits point. Do nothing.
310  if (debug & 2)
311  {
312  Pout<< "hit-type[1] " << pHit.hitPoint() << " is surf1:"
313  << " end point of edge[" << edgeI << "] " << e1
314  << "==" << e1.line(surf1Pts)
315  << " surf2: vertex " << f2[nearLabel]
316  << " coord:" << surf2Pts[f2[nearLabel]]
317  << " - suppressed" << endl;
318  }
319  }
320  else
321  {
322  // 2. Edge hits point. Cut edge with new point.
323  label cutPointId = -1;
324  const label nearVert = f2[nearLabel];
325 
326  // For self-intersection, we have tolerances for each point
327  // (surf2 is actually surf1) so we shift the hit to coincide
328  // identically.
329  if
330  (
331  cutFrom == surfaceIntersection::SELF
333  )
334  {
335  const point& nearPt = surf1Pts[nearVert];
336 
337  if
338  (
339  mag(pHit.hitPoint() - nearPt)
340  < surf1PointTol[nearVert]
341  )
342  {
343  cutPointId = allCutPoints.size();
344 
345  if (snapToEnd_)
346  {
347  if (snappedEnds_.insert(nearVert, cutPointId))
348  {
349  // Initial snap
350  allCutPoints.append(nearPt);
351  }
352  else
353  {
354  // Already snapped this point.
355  cutPointId = snappedEnds_[nearVert];
356  }
357  }
358  else
359  {
360  allCutPoints.append(nearPt);
361  }
362  }
363  }
364 
365  if (debug & 2)
366  {
367  Pout<< "hit-type[2] " << pHit.hitPoint() << " is surf1:"
368  << " from edge[" << edgeI << "] " << e1
369  << " surf2: vertex " << f2[nearLabel]
370  << " coord:" << surf2Pts[f2[nearLabel]]
371  << " - "
372  << (cutPointId >= 0 ? "snapped" : "stored") << endl;
373  }
374 
375  if (cutPointId == -1)
376  {
377  cutPointId = allCutPoints.size();
378  allCutPoints.append(pHit.hitPoint());
379  }
380  surfEdgeCuts[edgeI].append(cutPointId);
381 
382  const labelList& facesB = surf2.pointFaces()[f2[nearLabel]];
383  forAll(facesB, faceBI)
384  {
385  storeIntersection
386  (
387  cutFrom,
388  facesA,
389  facesB[faceBI],
390  allCutPoints,
391  cutPointId,
392  allCutEdges
393  );
394  }
395  }
396  }
397  else if (nearType == triPointRef::EDGE)
398  {
399  if (edgeEnd >= 0)
400  {
401  // 3. Point hits edge.
402  // Normally do nothing on this side since the reverse
403  // (edge hits point) is handled by 2.
404  // However, if the surfaces are separated by a minor gap,
405  // the end-point of a tolerance-extended edge can intersect another
406  // edge without itself being intersected by an edge.
407 
408  const label edge2I = getEdge(surf2, surf2Facei, nearLabel);
409  const edge& e2 = surf2.edges()[edge2I];
410  const label nearVert = e1[edgeEnd];
411 
412  label cutPointId = -1;
413 
414  // Storage treatment
415  // =0: nothing/ignore
416  // >0: store point/edge-cut. Attempt to create new edge.
417  // <0: store point/edge-cut only
418  int handling = (allowEdgeHits_ ? 1 : 0);
419  if
420  (
421  allowEdgeHits_
422  &&
423  (
424  cutFrom == surfaceIntersection::SELF
426  )
427  )
428  {
429  // The edge-edge intersection is hashed as an 'edge' to
430  // exploit the commutative lookup.
431  // Ie, only do the cut once
432  const edge intersect(edgeI, edge2I);
433 
434  if (e2.found(nearVert))
435  {
436  // Actually the same as #1 above, but missed due to
437  // tolerancing
438  handling = 0; // suppress
439  }
440  else if (edgeEdgeIntersection_.insert(intersect))
441  {
442  const point& nearPt = surf1Pts[nearVert];
443 
444  if
445  (
446  mag(pHit.hitPoint() - nearPt)
447  < surf1PointTol[nearVert]
448  )
449  {
450  cutPointId = allCutPoints.size();
451 
452  if (snapToEnd_)
453  {
454  if (snappedEnds_.insert(nearVert, cutPointId))
455  {
456  // Initial snap
457  allCutPoints.append(nearPt);
458  }
459  else
460  {
461  // Already snapped this point.
462  cutPointId = snappedEnds_[nearVert];
463  handling = 2; // cached
464  }
465  }
466  else
467  {
468  allCutPoints.append(nearPt);
469  }
470  }
471  }
472  else
473  {
474  handling = 0; // ignore - already did this interaction
475  }
476  }
477 
478  if (debug & 2)
479  {
480  Pout<< "hit-type[3] " << pHit.hitPoint() << " is surf1:"
481  << " end point of edge[" << edgeI << "] " << e1
482  << "==" << e1.line(surf1Pts)
483  << " surf2: edge[" << edge2I << "] " << e2
484  << " coords:" << e2.line(surf2Pts)
485  << " - "
486  << (
487  handling > 1
488  ? "cached" : handling
489  ? "stored" : "suppressed"
490  ) << endl;
491  }
492 
493  if (handling)
494  {
495  if (cutPointId == -1)
496  {
497  cutPointId = allCutPoints.size();
498  allCutPoints.append(pHit.hitPoint());
499  }
500  surfEdgeCuts[edgeI].append(cutPointId);
501  }
502 
503  if (handling > 0)
504  {
505  const labelList& facesB = surf2.edgeFaces()[edge2I];
506  forAll(facesB, faceBI)
507  {
508  storeIntersection
509  (
510  cutFrom,
511  facesA,
512  facesB[faceBI],
513  allCutPoints,
514  cutPointId,
515  allCutEdges
516  );
517  }
518  }
519  }
520  else
521  {
522  // 4. Edge hits edge.
523 
524  // Cut edge with new point (creates duplicates when
525  // doing the surf2 with surf1 intersection but these
526  // are merged later on)
527 
528  // edge hits all faces on surf2 connected to the edge
529  //
530  // The edge-edge intersection is symmetric, store only once.
531  // - When intersecting two surfaces, note which edges are cut each
532  // time, but only create an edge from the first pass.
533  // - For self-intersection, it is slightly trickier if we don't
534  // want too many duplicate points.
535 
536  const label edge2I = getEdge(surf2, surf2Facei, nearLabel);
537  const edge& e2 = surf2.edges()[edge2I];
538  label cutPointId = -1;
539 
540  // Storage treatment
541  // =0: nothing/ignore
542  // >0: store point/edge-cut. Attempt to create new edge.
543  // <0: store point/edge-cut only
544  int handling = 0;
545  switch (cutFrom)
546  {
548  {
549  handling = 1;
550  break;
551  }
553  {
554  handling = -1;
555  break;
556  }
559  {
560  // The edge-edge intersection is hashed as an 'edge' to
561  // exploit the commutative lookup.
562  // Ie, only do the cut once
563  const edge intersect(edgeI, edge2I);
564 
565  if (edgeEdgeIntersection_.insert(intersect))
566  {
567  handling = 1;
568  forAll(e1, edgepti)
569  {
570  const label endId = e1[edgepti];
571  const point& nearPt = surf1Pts[endId];
572 
573  if
574  (
575  mag(pHit.hitPoint() - nearPt)
576  < surf1PointTol[endId]
577  )
578  {
579  cutPointId = allCutPoints.size();
580 
581  if (snapToEnd_)
582  {
583  if (snappedEnds_.insert(endId, cutPointId))
584  {
585  // First time with this end-point
586  allCutPoints.append(nearPt);
587  }
588  else
589  {
590  // Already seen this end point
591  cutPointId = snappedEnds_[endId];
592  handling = 2; // cached
593  }
594  }
595  else
596  {
597  allCutPoints.append(nearPt);
598  }
599 
600  break;
601  }
602  }
603  }
604 
605  break;
606  }
607 
609  return;
610  break;
611  }
612 
613  if (debug & 2)
614  {
615  Pout<< "hit-type[4] " << pHit.hitPoint() << " is surf1:"
616  << " from edge[" << edgeI << "] " << e1
617  << "==" << e1.line(surf1Pts)
618  << " surf2: edge[" << edge2I << "] " << e2
619  << " coords:" << e2.line(surf2Pts)
620  << " - "
621  << (
622  handling < 0
623  ? "cut-point" : handling
624  ? "stored" : "suppressed"
625  )
626  << endl;
627  }
628 
629  if (handling)
630  {
631  if (cutPointId == -1)
632  {
633  cutPointId = allCutPoints.size();
634  allCutPoints.append(pHit.hitPoint());
635  }
636  surfEdgeCuts[edgeI].append(cutPointId);
637  }
638 
639  if (handling)
640  {
641  const vector eVec = e1.unitVec(surf1Pts);
642 
643  const labelList& facesB = surf2.edgeFaces()[edge2I];
644  forAll(facesB, faceBI)
645  {
646  // Intersecting edge should be non-coplanar with face
647  if
648  (
649  mag((surf2.faceNormals()[facesB[faceBI]] & eVec))
650  > 0.01
651  )
652  {
653  storeIntersection
654  (
655  cutFrom,
656  facesA,
657  facesB[faceBI],
658  allCutPoints,
659  cutPointId,
660  allCutEdges
661  );
662  }
663  }
664  }
665  }
666  }
667  else
668  {
669  if (edgeEnd >= 0)
670  {
671  // 5. Point hits face. Do what? Introduce
672  // point & triangulation in face?
673 
674  // Look exactly at what side (of surf2) edge is. Leave out ones on
675  // inside of surf2 (i.e. on opposite side of normal)
676 
677  // Vertex on/near surf2; vertex away from surf2
678  // otherVert on outside of surf2
679  const label nearVert = (edgeEnd == 0 ? e1.start() : e1.end());
680  const label otherVert = (edgeEnd == 0 ? e1.end() : e1.start());
681 
682  const point& nearPt = surf1Pts[nearVert];
683  const point& otherPt = surf1Pts[otherVert];
684 
685  const vector eVec = otherPt - nearPt;
686 
687  if ((surf2.faceNormals()[surf2Facei] & eVec) > 0)
688  {
689  // map to nearVert
690  // Reclassify as normal edge-face pierce (see below)
691  bool cached = false;
692 
693  label cutPointId = allCutPoints.size();
694  if (snapToEnd_)
695  {
696  if (snappedEnds_.insert(nearVert, cutPointId))
697  {
698  // First time with this end-point
699  allCutPoints.append(nearPt);
700  }
701  else
702  {
703  // Already seen this end point
704  cutPointId = snappedEnds_[nearVert];
705  cached = true;
706  }
707  }
708  else
709  {
710  allCutPoints.append(nearPt);
711  }
712 
713  surfEdgeCuts[edgeI].append(cutPointId);
714 
715  if (debug & 2)
716  {
717  Pout<< "hit-type[5] " << pHit.hitPoint()
718  << " shifted to " << nearPt
719  << " from edge[" << edgeI << "] " << e1
720  << "==" << e1.line(surf1Pts)
721  << " hits surf2 face[" << surf2Facei << "]"
722  << " - "
723  << (cached ? "cached" : "stored") << endl;
724  }
725 
726  // edge hits single face only
727  storeIntersection
728  (
729  cutFrom,
730  facesA,
731  surf2Facei,
732  allCutPoints,
733  cutPointId,
734  allCutEdges
735  );
736  }
737  else
738  {
739  if (debug & 2)
740  {
741  Pout<< "hit-type[5] " << pHit.hitPoint()
742  << " from edge[" << edgeI << "] " << e1
743  << " hits inside of surf2 face[" << surf2Facei << "]"
744  << " - discarded" << endl;
745  }
746  }
747  }
748  else
749  {
750  // 6. Edge pierces face. 'Normal' situation.
751  if (debug & 2)
752  {
753  Pout<< "hit-type[6] " << pHit.hitPoint()
754  << " from edge[" << edgeI << "] " << e1
755  << "==" << e1.line(surf1Pts)
756  << " hits surf2 face[" << surf2Facei << "]"
757  << " - stored" << endl;
758  }
759 
760  const label cutPointId = allCutPoints.size();
761  allCutPoints.append(pHit.hitPoint());
762  surfEdgeCuts[edgeI].append(cutPointId);
763 
764  // edge hits single face only
765  storeIntersection
766  (
767  cutFrom,
768  facesA,
769  surf2Facei,
770  allCutPoints,
771  cutPointId,
772  allCutEdges
773  );
774  }
775  }
776 }
777 
778 
779 // Cut all edges of surf1 with surf2. Sets
780 // - cutPoints : coordinates of cutPoints
781 // - cutEdges : newly created edges between cutPoints
782 // - facePairToVertex : hash from face1I and face2I to edge
783 // - facePairToEdgeId : hash from face1I and face2I to index in cutEdge
784 // - surfEdgeCuts : gives for each edge the cutPoints
785 // (in order from start to end)
786 //
787 void Foam::surfaceIntersection::doCutEdges
788 (
789  const triSurface& surf1,
790  const triSurfaceSearch& querySurf2,
791  const enum intersectionType cutFrom,
792 
793  DynamicList<point>& allCutPoints,
794  DynamicList<edge>& allCutEdges,
795  List<DynamicList<label>>& surfEdgeCuts
796 )
797 {
798  const scalar oldTol = intersection::setPlanarTol(tolerance_);
799 
800  const pointField& surf1Pts = surf1.localPoints();
801 
802  // Calculate local (to point) tolerance based on min edge length.
803  scalarField surf1PointTol(surf1Pts.size());
804 
805  forAll(surf1PointTol, pointi)
806  {
807  surf1PointTol[pointi] = tolerance_ * minEdgeLen(surf1, pointi);
808  }
809 
810  const indexedOctree<treeDataPrimitivePatch<triSurface>>& searchTree
811  = querySurf2.tree();
812 
813  if
814  (
815  cutFrom == surfaceIntersection::SELF
817  )
818  {
819  // An edge may intersect multiple faces
820  // - mask out faces that have already been hit before trying again
821  // - never intersect with faces attached to the edge itself
822  DynamicList<label> maskFaces(32);
823 
824  // Optionally prevent intersection within a single region.
825  // Like self-intersect, but only if regions are different
826  bitSet maskRegions(32);
827 
828  treeDataTriSurface::findAllIntersectOp
829  allIntersectOp(searchTree, maskFaces);
830 
831  forAll(surf1.edges(), edgeI)
832  {
833  const edge& e = surf1.edges()[edgeI];
834  const vector edgeVec = e.vec(surf1Pts);
835 
836  // Extend start/end by 1/2 tolerance - ensures cleaner cutting
837  const point ptStart =
838  surf1Pts[e.start()] - 0.5*surf1PointTol[e.start()]*edgeVec;
839  const point ptEnd =
840  surf1Pts[e.end()] + 0.5*surf1PointTol[e.end()]*edgeVec;
841 
842  maskRegions.clear();
843  if (cutFrom == surfaceIntersection::SELF_REGION)
844  {
845  for (auto& facei : surf1.edgeFaces()[edgeI])
846  {
847  maskRegions.set(surf1[facei].region());
848  }
849  }
850 
851  // Never intersect with faces attached directly to the edge itself,
852  // nor with faces attached to its end points. This mask contains
853  // some duplicates, but filtering them out is less efficient.
854  maskFaces = surf1.pointFaces()[e.start()];
855  maskFaces.append(surf1.pointFaces()[e.end()]);
856 
857  while (true)
858  {
859  pointIndexHit pHit = searchTree.findLine
860  (
861  ptStart,
862  ptEnd,
863  allIntersectOp
864  );
865 
866  if (!pHit.hit())
867  {
868  break;
869  }
870 
871  maskFaces.append(pHit.index());
872 
873  if (maskRegions.test(surf1[pHit.index()].region()))
874  {
875  continue;
876  }
877 
878  classifyHit
879  (
880  surf1,
881  surf1PointTol,
882  surf1,
883  cutFrom,
884  edgeI,
885  pHit,
886 
887  allCutPoints,
888  allCutEdges,
889  surfEdgeCuts
890  );
891  }
892  }
893  }
894  else
895  {
896  const triSurface& surf2 = querySurf2.surface();
897 
898  forAll(surf1.edges(), edgeI)
899  {
900  const edge& e = surf1.edges()[edgeI];
901  const vector edgeVec = e.vec(surf1Pts);
902 
903  const point tolVec = intersection::planarTol()*(edgeVec);
904  const scalar tolDim = mag(tolVec);
905 
906  // Extend start/end by 1/2 tolerance - ensures cleaner cutting
907  point ptStart =
908  surf1Pts[e.start()] - 0.5*surf1PointTol[e.start()]*edgeVec;
909  const point ptEnd =
910  surf1Pts[e.end()] + 0.5*surf1PointTol[e.end()]*edgeVec;
911 
912  bool doTrack = false;
913  do
914  {
915  pointIndexHit pHit = searchTree.findLine(ptStart, ptEnd);
916 
917  if (!pHit.hit())
918  {
919  break;
920  }
921 
922  classifyHit
923  (
924  surf1,
925  surf1PointTol,
926  surf2,
927  cutFrom,
928  edgeI,
929  pHit,
930 
931  allCutPoints,
932  allCutEdges,
933  surfEdgeCuts
934  );
935 
936  if (tolerance_ > 0)
937  {
938  if (mag(pHit.hitPoint() - ptEnd) < tolDim)
939  {
940  // Near the end => done
941  doTrack = false;
942  }
943  else
944  {
945  // Continue tracking a bit further on
946  ptStart = pHit.hitPoint() + tolVec;
947  doTrack = true;
948  }
949  }
950  }
951  while (doTrack); // execute at least once
952  }
953  }
954  if (debug & 2)
955  {
956  Pout<< endl;
957  }
958 
959  // These temporaries are now unneeded:
960  edgeEdgeIntersection_.clear();
961  snappedEnds_.clear();
962 
964 }
965 
966 
967 void Foam::surfaceIntersection::joinDisconnected
968 (
969  DynamicList<edge>& allCutEdges
970 )
971 {
972  // This simple heuristic seems to work just as well (or better) than
973  // more complicated schemes
974  //
975  // For any face/face intersection that only appears once,
976  // consider which other faces/points are involved and connect between
977  // those points.
978  // Just do a simple connect-the-dots?
979 
980  Pair<Map<labelPairHashSet>> missedFacePoint;
981 
982  // Stage 1:
983  // - Extract "faceId -> (faceId, pointId)"
984  // for all face/face pairs that only have one interaction
985  forAllConstIters(facePairToEdge_, iter)
986  {
987  const labelPair& twoFaces = iter.key();
988  const edge& e = iter.val();
989 
990  if (e.count() == 1)
991  {
992  // minVertex = -1 (unused), maxVertex = pointId
993  const label pointId = e.maxVertex();
994 
995  missedFacePoint[0](twoFaces[0]).insert
996  (
997  labelPair(twoFaces[1], pointId)
998  );
999 
1000  missedFacePoint[1](twoFaces[1]).insert
1001  (
1002  labelPair(twoFaces[0], pointId)
1003  );
1004  }
1005  }
1006 
1007 
1008  // Stage 2:
1009  // - anything with two cross-interactions could cause a new edge:
1010 
1011  edgeHashSet newEdges;
1012  forAll(missedFacePoint, sidei)
1013  {
1014  const auto& mapping = missedFacePoint[sidei];
1015 
1016  forAllConstIters(mapping, iter)
1017  {
1018  const auto& connect = iter.val();
1019 
1020  if (connect.size() == 2)
1021  {
1022  // exactly two face/face cross-interactions
1023 
1024  edge e;
1025  for (const auto& facePoint : connect)
1026  {
1027  e.insert(facePoint.second());
1028  }
1029  e.sort();
1030 
1031  // Only consider edges with two unique ends,
1032  // and do not introduce duplicates
1033  if (e.count() == 2 && !edgeToId_.found(e))
1034  {
1035  newEdges.insert(e);
1036  }
1037  }
1038  }
1039  }
1040 
1041  label edgeId = allCutEdges.size();
1042  edgeList newEdgesLst = newEdges.sortedToc();
1043  for (const auto& e : newEdgesLst)
1044  {
1045  // Record complete (line) intersection of two faces
1046  allCutEdges.append(e);
1047  edgeToId_.insert(e, edgeId);
1048  ++edgeId;
1049  }
1050 }
1051 
1052 
1053 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1054 
1056 :
1057  tolerance_(1e-3),
1058  allowEdgeHits_(true),
1059  snapToEnd_(true),
1060  warnDegenerate_(0),
1061  cutPoints_(0),
1062  cutEdges_(0),
1063  facePairToEdge_(0),
1064  facePairToEdgeId_(0),
1065  surf1EdgeCuts_(0),
1066  surf2EdgeCuts_(0)
1067 {}
1068 
1069 
1072  const triSurfaceSearch& query1,
1073  const triSurfaceSearch& query2,
1074  const dictionary& dict
1075 )
1076 :
1077  tolerance_(1e-3),
1078  allowEdgeHits_(true),
1079  snapToEnd_(true),
1080  warnDegenerate_(0),
1081  cutPoints_(0),
1082  cutEdges_(0),
1083  facePairToEdge_(2*max(query1.surface().size(), query2.surface().size())),
1084  facePairToEdgeId_(2*max(query1.surface().size(), query2.surface().size())),
1085  surf1EdgeCuts_(0),
1086  surf2EdgeCuts_(0)
1087 {
1088  setOptions(dict);
1089 
1090  const triSurface& surf1 = query1.surface();
1091  const triSurface& surf2 = query2.surface();
1092 
1093  //
1094  // Cut all edges of surf1 with surf2.
1095  //
1096  if (debug)
1097  {
1098  Pout<< "Cutting surf1 edges" << endl;
1099  }
1100 
1101 
1102  DynamicList<edge> allCutEdges(surf1.nEdges()/20);
1103  DynamicList<point> allCutPoints(surf1.nPoints()/20);
1104 
1105 
1106  // From edge to cut index on surface1
1107  List<DynamicList<label>> edgeCuts1(query1.surface().nEdges());
1108 
1109  // 1st surf (for labelPair order)
1110  doCutEdges
1111  (
1112  surf1,
1113  query2,
1115  allCutPoints,
1116  allCutEdges,
1117  edgeCuts1
1118  );
1119  // Transfer to straight labelListList
1120  transfer(edgeCuts1, surf1EdgeCuts_);
1121 
1122 
1123  //
1124  // Cut all edges of surf2 with surf1.
1125  //
1126  if (debug)
1127  {
1128  Pout<< "Cutting surf2 edges" << endl;
1129  }
1130 
1131  // From edge to cut index
1132  List<DynamicList<label>> edgeCuts2(query2.surface().nEdges());
1133 
1134  // 2nd surf (for labelPair order)
1135  doCutEdges
1136  (
1137  surf2,
1138  query1,
1140  allCutPoints,
1141  allCutEdges,
1142  edgeCuts2
1143  );
1144 
1145  // join disconnected intersection points
1146  joinDisconnected(allCutEdges);
1147 
1148  // Transfer to straight label(List)List
1149  transfer(edgeCuts2, surf2EdgeCuts_);
1150  cutEdges_.transfer(allCutEdges);
1151  cutPoints_.transfer(allCutPoints);
1152 
1153  if (debug)
1154  {
1155  Pout<< "surfaceIntersection : Intersection generated:"
1156  << endl
1157  << " points:" << cutPoints_.size() << endl
1158  << " edges :" << cutEdges_.size() << endl;
1159 
1160  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
1161  << endl;
1162 
1163  OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
1164 
1165  // Dump all cut edges to files
1166  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
1167  OFstream edge1Stream("surf1EdgeCuts.obj");
1168  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
1169 
1170  Pout<< "Dumping cut edges of surface2 to surf2EdgeCuts.obj" << endl;
1171  OFstream edge2Stream("surf2EdgeCuts.obj");
1172  writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream);
1173  }
1174 
1175  // Temporaries
1176  facePairToEdge_.clear();
1177 
1178  // Cleanup any duplicate cuts?
1179  // mergeEdges();
1180 }
1181 
1182 
1185  const triSurfaceSearch& query1,
1186  const dictionary& dict
1187 )
1188 :
1189  tolerance_(1e-3),
1190  allowEdgeHits_(true),
1191  snapToEnd_(true),
1192  warnDegenerate_(0),
1193  cutPoints_(0),
1194  cutEdges_(0),
1195  facePairToEdge_(2*query1.surface().size()),
1196  facePairToEdgeId_(2*query1.surface().size()),
1197  surf1EdgeCuts_(0),
1198  surf2EdgeCuts_(0)
1199 {
1200  setOptions(dict);
1201 
1202  const intersectionType cutFrom = selfIntersectionNames.getOrDefault
1203  (
1204  "intersectionMethod",
1205  dict,
1206  intersectionType::SELF
1207  );
1208 
1209  if (cutFrom == intersectionType::NONE)
1210  {
1211  if (debug)
1212  {
1213  Pout<< "Skipping self-intersection (selected: none)" << endl;
1214  }
1215 
1216  // Temporaries
1217  facePairToEdge_.clear();
1218  facePairToEdgeId_.clear();
1219 
1220  return;
1221  }
1222 
1223  const triSurface& surf1 = query1.surface();
1224 
1225  //
1226  // Cut all edges of surf1 with surf1 itself.
1227  //
1228  if (debug)
1229  {
1230  Pout<< "Cutting surf1 edges" << endl;
1231  }
1232 
1233  DynamicList<edge> allCutEdges;
1234  DynamicList<point> allCutPoints;
1235 
1236  // From edge to cut index on surface1
1237  List<DynamicList<label>> edgeCuts1(query1.surface().nEdges());
1238 
1239  // self-intersection
1240  doCutEdges
1241  (
1242  surf1,
1243  query1,
1244  cutFrom,
1245  allCutPoints,
1246  allCutEdges,
1247  edgeCuts1
1248  );
1249 
1250  // join disconnected intersection points
1251  joinDisconnected(allCutEdges);
1252 
1253  // Transfer to straight label(List)List
1254  transfer(edgeCuts1, surf1EdgeCuts_);
1255  cutEdges_.transfer(allCutEdges);
1256  cutPoints_.transfer(allCutPoints);
1257 
1258  // Short-circuit
1259  if (cutPoints_.empty() && cutEdges_.empty())
1260  {
1261  if (debug)
1262  {
1263  Pout<< "Empty intersection" << endl;
1264  }
1265  return;
1266  }
1267 
1268  if (debug)
1269  {
1270  Pout<< "surfaceIntersection : Intersection generated and compressed:"
1271  << endl
1272  << " points:" << cutPoints_.size() << endl
1273  << " edges :" << cutEdges_.size() << endl;
1274 
1275 
1276  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
1277  << endl;
1278 
1279  OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
1280 
1281  // Dump all cut edges to files
1282  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
1283  OFstream edge1Stream("surf1EdgeCuts.obj");
1284  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
1285  }
1286 
1287  // Temporaries
1288  facePairToEdge_.clear();
1289 
1290  // // Cleanup any duplicate cuts?
1291  // mergeEdges();
1292 }
1293 
1294 
1297  const triSurface& surf1,
1298  const edgeIntersections& intersections1,
1299  const triSurface& surf2,
1300  const edgeIntersections& intersections2
1301 )
1302 :
1303  tolerance_(1e-3),
1304  allowEdgeHits_(true),
1305  snapToEnd_(true),
1306  warnDegenerate_(0),
1307  cutPoints_(0),
1308  cutEdges_(0),
1309  facePairToEdge_(2*max(surf1.size(), surf2.size())),
1310  facePairToEdgeId_(2*max(surf1.size(), surf2.size())),
1311  surf1EdgeCuts_(0),
1312  surf2EdgeCuts_(0)
1313 {
1314 
1315  // All intersection Pout (so for both surfaces)
1316  DynamicList<edge> allCutEdges((surf1.nEdges() + surf2.nEdges())/20);
1317  DynamicList<point> allCutPoints((surf1.nPoints() + surf2.nPoints())/20);
1318 
1319 
1320  // Cut all edges of surf1 with surf2
1321  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1322 
1323  if (debug)
1324  {
1325  Pout<< "Storing surf1 intersections" << endl;
1326  }
1327 
1328  {
1329  // From edge to cut index on surface1
1330  List<DynamicList<label>> edgeCuts1(surf1.nEdges());
1331 
1332  forAll(intersections1, edgeI)
1333  {
1334  const List<pointIndexHit>& intersections = intersections1[edgeI];
1335 
1336  forAll(intersections, i)
1337  {
1338  // edgeI intersects surf2. Store point.
1339  const pointIndexHit& pHit = intersections[i];
1340  const label cutPointId = allCutPoints.size();
1341 
1342  allCutPoints.append(pHit.hitPoint());
1343  edgeCuts1[edgeI].append(cutPointId);
1344 
1345  storeIntersection
1346  (
1348  surf1.edgeFaces()[edgeI],
1349  pHit.index(),
1350  allCutPoints,
1351  cutPointId,
1352  allCutEdges
1353  );
1354  }
1355  }
1356 
1357  // Transfer to straight labelListList
1358  transfer(edgeCuts1, surf1EdgeCuts_);
1359  }
1360 
1361 
1362  // Cut all edges of surf2 with surf1
1363  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1364 
1365  if (debug)
1366  {
1367  Pout<< "Storing surf2 intersections" << endl;
1368  }
1369 
1370  {
1371  // From edge to cut index on surface2
1372  List<DynamicList<label>> edgeCuts2(surf2.nEdges());
1373 
1374  forAll(intersections2, edgeI)
1375  {
1376  const List<pointIndexHit>& intersections = intersections2[edgeI];
1377 
1378  forAll(intersections, i)
1379  {
1380  // edgeI intersects surf1. Store point.
1381  const pointIndexHit& pHit = intersections[i];
1382  const label cutPointId = allCutPoints.size();
1383 
1384  allCutPoints.append(pHit.hitPoint());
1385  edgeCuts2[edgeI].append(cutPointId);
1386 
1387  storeIntersection
1388  (
1390  surf2.edgeFaces()[edgeI],
1391  pHit.index(),
1392  allCutPoints,
1393  cutPointId,
1394  allCutEdges
1395  );
1396  }
1397  }
1398 
1399  // Transfer to surf2EdgeCuts_ (straight labelListList)
1400  transfer(edgeCuts2, surf2EdgeCuts_);
1401  }
1402 
1403 
1404  // Transfer to straight label(List)List
1405  cutEdges_.transfer(allCutEdges);
1406  cutPoints_.transfer(allCutPoints);
1407 
1408 
1409  if (debug)
1410  {
1411  Pout<< "surfaceIntersection : Intersection generated:"
1412  << endl
1413  << " points:" << cutPoints_.size() << endl
1414  << " edges :" << cutEdges_.size() << endl;
1415 
1416  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
1417  << endl;
1418 
1419  OBJstream("intEdges.obj").write(cutEdges_, cutPoints_);
1420 
1421  // Dump all cut edges to files
1422  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
1423  OFstream edge1Stream("surf1EdgeCuts.obj");
1424  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
1425 
1426  Pout<< "Dumping cut edges of surface2 to surf2EdgeCuts.obj" << endl;
1427  OFstream edge2Stream("surf2EdgeCuts.obj");
1428  writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream);
1429  }
1430 
1431  // Temporaries
1432  facePairToEdge_.clear();
1433 
1434  // // Cleanup any duplicate cuts?
1435  // mergeEdges();
1436 }
1437 
1438 
1439 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1440 
1442 {
1443  return cutPoints_;
1444 }
1445 
1446 
1448 {
1449  return cutEdges_;
1450 }
1451 
1452 
1454 {
1455  return facePairToEdgeId_;
1456 }
1457 
1458 
1461  const bool isFirstSurf
1462 ) const
1463 {
1464  if (isFirstSurf)
1465  {
1466  return surf1EdgeCuts_;
1467  }
1468  else
1469  {
1470  return surf2EdgeCuts_;
1471  }
1472 }
1473 
1474 
1476 {
1477  return surf1EdgeCuts_;
1478 }
1479 
1480 
1482 {
1483  return surf2EdgeCuts_;
1484 }
1485 
1486 
1487 void Foam::surfaceIntersection::mergePoints(const scalar mergeDist)
1488 {
1489  pointField newPoints;
1490  labelList pointMap;
1491 
1492  const label nMerged = Foam::mergePoints
1493  (
1494  cutPoints_,
1495  mergeDist,
1496  false,
1497  pointMap,
1498  newPoints
1499  );
1500 
1501  if (nMerged)
1502  {
1503  cutPoints_.transfer(newPoints);
1504 
1505  forAll(cutEdges_, edgei)
1506  {
1507  edge& e = cutEdges_[edgei];
1508 
1509  e[0] = pointMap[e[0]];
1510  e[1] = pointMap[e[1]];
1511  }
1512 
1513  forAll(surf1EdgeCuts_, edgei)
1514  {
1515  inplaceRenumber(pointMap, surf1EdgeCuts_[edgei]);
1516  inplaceUniqueSort(surf1EdgeCuts_[edgei]);
1517  }
1518  forAll(surf2EdgeCuts_, edgei)
1519  {
1520  inplaceRenumber(pointMap, surf2EdgeCuts_[edgei]);
1521  inplaceUniqueSort(surf2EdgeCuts_[edgei]);
1522  }
1523  }
1524 
1525  this->mergeEdges();
1526 }
1527 
1528 
1530 {
1531  edgeHashSet uniqEdges(2*cutEdges_.size());
1532 
1533  label nUniqEdges = 0;
1534  labelList edgeNumbering(cutEdges_.size(), -1);
1535 
1536  forAll(cutEdges_, edgeI)
1537  {
1538  const edge& e = cutEdges_[edgeI];
1539 
1540  // Remove degenerate and repeated edges
1541  // - reordering (e[0] < e[1]) is not really necessary
1542  if (e[0] != e[1] && uniqEdges.insert(e))
1543  {
1544  edgeNumbering[edgeI] = nUniqEdges;
1545  if (nUniqEdges != edgeI)
1546  {
1547  cutEdges_[nUniqEdges] = e;
1548  }
1549  cutEdges_[nUniqEdges].sort();
1550  ++nUniqEdges;
1551  }
1552  }
1553 
1554  // if (nUniqEdges < cutEdges_.size())
1555  // {
1556  // // Additional safety, in case the edge was replaced?
1557  // forAllIters(facePairToEdge_, iter)
1558  // {
1559  // iter.val() = edgeNumbering[iter.val()];
1560  // }
1561  // }
1562 
1563  cutEdges_.setSize(nUniqEdges); // truncate
1564 }
1565 
1566 
1567 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
insert
srcOptions insert("case", fileName(rootDirSource/caseDirSource))
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::surfaceIntersection::surf2EdgeCuts
const labelListList & surf2EdgeCuts() const
List of cut points on edges of surface2.
Definition: surfaceIntersection.C:1481
Foam::Enum
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: IOstreamOption.H:57
pointIndexHit.H
Foam::PrimitivePatch::edgeFaces
const labelListList & edgeFaces() const
Return edge-face addressing.
Definition: PrimitivePatch.C:262
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
edgeIntersections.H
Foam::OBJstream
OFstream that keeps track of vertices.
Definition: OBJstream.H:58
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:55
Foam::intersection::setPlanarTol
static scalar setPlanarTol(const scalar t)
Set the planar tolerance, returning the previous value.
Definition: intersection.H:94
Foam::PrimitivePatch::nEdges
label nEdges() const
Number of edges in patch.
Definition: PrimitivePatch.H:322
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::inplaceUniqueSort
void inplaceUniqueSort(ListType &input)
Inplace sorting and removal of duplicates.
Definition: ListOpsTemplates.C:468
Foam::surfaceIntersection::intersectionType
intersectionType
Surface intersection types for classify, doCutEdges.
Definition: surfaceIntersection.H:135
Foam::intersection::planarTol
static scalar planarTol()
Return planar tolerance.
Definition: intersection.H:88
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::surfaceIntersection::surfaceIntersection
surfaceIntersection()
Construct null.
Definition: surfaceIntersection.C:1055
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::surfaceIntersection::facePairToEdgeId
const labelPairLookup & facePairToEdgeId() const
Lookup of pairs of faces to created edges.
Definition: surfaceIntersection.C:1453
Foam::PointIndexHit::hitPoint
const point_type & hitPoint() const
Return hit point. Fatal if not hit.
Definition: PointIndexHit.H:154
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
triSurface.H
Foam::HashSet< edge, Hash< edge > >
Foam::OBJstream::write
virtual Ostream & write(const char c)
Write character.
Definition: OBJstream.C:78
bitSet.H
Foam::triSurfaceSearch
Helper class to search on triSurface.
Definition: triSurfaceSearch.H:58
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::surfaceIntersection::mergeEdges
void mergeEdges()
Merge duplicate edges.
Definition: surfaceIntersection.C:1529
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
surfaceIntersection.H
Foam::facePoint
label facePoint(const int facei, const block &block, const label i, const label j)
Definition: blockMeshMergeTopological.C:212
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::surfaceIntersection::surf1EdgeCuts
const labelListList & surf1EdgeCuts() const
List of cut points on edges of surface1.
Definition: surfaceIntersection.C:1475
Foam::PointIndexHit
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:52
labelPairHashes.H
A HashTable to objects of type <T> with a labelPair key. The hashing is based on labelPair (FixedList...
Foam::Field< vector >
plane.H
Foam::triSurface
Triangulated surface description with patch information.
Definition: triSurface.H:76
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::surfaceIntersection::NONE
None = invalid (for input only)
Definition: surfaceIntersection.H:141
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::surfaceIntersection::cutPoints
const pointField & cutPoints() const
The list of cut points.
Definition: surfaceIntersection.C:1441
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::PrimitivePatch::nPoints
label nPoints() const
Number of points supporting patch faces.
Definition: PrimitivePatch.H:316
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::triangle::POINT
Close to point.
Definition: triangle.H:96
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::surfaceIntersection::cutEdges
const edgeList & cutEdges() const
The list of created edges.
Definition: surfaceIntersection.C:1447
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::mergePoints
label mergePoints(const PointList &points, const scalar mergeTol, const bool verbose, labelList &pointMap, typename PointList::const_reference origin=PointList::value_type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::HashTable< label, labelPair, Foam::Hash< labelPair > >
Foam::surfaceIntersection::SECOND
Second surface.
Definition: surfaceIntersection.H:138
Foam::surfaceIntersection::SELF_REGION
Self-intersection, region-wise only.
Definition: surfaceIntersection.H:140
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
A PointIndexHit for 3D points.
Definition: pointIndexHit.H:46
Foam::triangle::EDGE
Close to edge.
Definition: triangle.H:97
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::surfaceIntersection::FIRST
First surface.
Definition: surfaceIntersection.H:137
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::surfaceIntersection::SELF
Self-intersection.
Definition: surfaceIntersection.H:139
Foam::PointIndexHit::index
label index() const noexcept
Return the hit index.
Definition: PointIndexHit.H:136
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::triSurfaceSearch::surface
const triSurface & surface() const
Return reference to the surface.
Definition: triSurfaceSearch.H:129
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
triSurfaceSearch.H
mergePoints.H
Merge points. See below.
Foam::triSurface::face_type
labelledTri face_type
The face type (same as the underlying PrimitivePatch)
Definition: triSurface.H:209
Foam::surfaceIntersection::mergePoints
void mergePoints(const scalar mergeDist)
Geometric merge points (points within mergeDist) prior to.
Definition: surfaceIntersection.C:1487
Foam::edgeIntersections
Holder of intersections of edges of a surface with another surface. Optionally shuffles around points...
Definition: edgeIntersections.H:62
Foam::VectorSpace::size
static constexpr direction size() noexcept
The number of elements in the VectorSpace = Ncmpts.
Definition: VectorSpace.H:176
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::surfaceIntersection::edgeCuts
const labelListList & edgeCuts(const bool isFirstSurf) const
Access either surf1EdgeCuts (isFirstSurface = true) or.
Definition: surfaceIntersection.C:1460
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
OBJstream.H
Foam::edgeHashSet
HashSet< edge, Hash< edge > > edgeHashSet
A HashSet with edge for its key.
Definition: edgeHashes.H:51
Foam::surfaceIntersection::selfIntersectionNames
static const Enum< intersectionType > selfIntersectionNames
The user-selectable self-intersection enumeration names.
Definition: surfaceIntersection.H:145