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 | Copyright (C) 2011-2013 OpenFOAM Foundation
6  \\/ M anipulation |
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 "surfaceIntersection.H"
27 #include "triSurfaceSearch.H"
28 #include "labelPairLookup.H"
29 #include "OFstream.H"
30 #include "HashSet.H"
31 #include "triSurface.H"
32 #include "pointIndexHit.H"
33 #include "mergePoints.H"
34 #include "plane.H"
35 #include "edgeIntersections.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41 defineTypeNameAndDebug(surfaceIntersection, 0);
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 // Checks if there exists a special topological situation that causes
48 // edge and the face it hit not to be recognized.
49 //
50 // For now if the face shares a point with the edge
51 bool Foam::surfaceIntersection::excludeEdgeHit
52 (
53  const triSurface& surf,
54  const label edgeI,
55  const label faceI,
56  const scalar
57 )
58 {
59  const triSurface::FaceType& f = surf.localFaces()[faceI];
60  const edge& e = surf.edges()[edgeI];
61 
62  forAll(f, fp)
63  {
64  if (f[0] == e.start() || f[0] == e.end())
65  {
66  return true;
67  }
68  }
69 
70 // {
71 // // Get edge vector
72 // vector eVec = e.vec(surf.localPoints());
73 // eVec /= mag(eVec) + VSMALL;
74 //
75 // const labelList& eLabels = surf.faceEdges()[faceI];
76 //
77 // // Get edge vector of 0th edge of face
78 // vector e0Vec = surf.edges()[eLabels[0]].vec(surf.localPoints());
79 // e0Vec /= mag(e0Vec) + VSMALL;
80 //
81 // vector n = e0Vec ^ eVec;
82 //
83 // if (mag(n) < SMALL)
84 // {
85 // // e0 is aligned with e. Choose next edge of face.
86 // vector e1Vec = surf.edges()[eLabels[1]].vec(surf.localPoints());
87 // e1Vec /= mag(e1Vec) + VSMALL;
88 //
89 // n = e1Vec ^ eVec;
90 //
91 // if (mag(n) < SMALL)
92 // {
93 // // Problematic triangle. Two edges aligned with edgeI. Give
94 // // up.
95 // return true;
96 // }
97 // }
98 //
99 // // Check if same as faceNormal
100 // if (mag(n & surf.faceNormals()[faceI]) > 1-tol)
101 // {
102 //
103 // Pout<< "edge:" << e << " face:" << faceI
104 // << " e0Vec:" << e0Vec << " n:" << n
105 // << " normalComponent:" << (n & surf.faceNormals()[faceI])
106 // << " tol:" << tol << endl;
107 //
108 // return true;
109 // }
110 // else
111 // {
112 // return false;
113 // }
114 // }
115 
116  return false;
117 }
118 
119 
123 //Foam::pointIndexHit Foam::surfaceIntersection::faceEdgeIntersection
124 //(
125 // const triSurface& surf,
126 // const label hitFaceI,
127 //
128 // const vector& n,
129 // const point& eStart,
130 // const point& eEnd
131 //)
132 //{
133 // pointIndexHit pInter;
134 //
135 // const pointField& points = surf.points();
136 //
137 // const triSurface::FaceType& f = surf.localFaces()[hitFaceI];
138 //
139 // // Plane for intersect test.
140 // plane pl(eStart, n);
141 //
142 // forAll(f, fp)
143 // {
144 // label fp1 = f.fcIndex(fp);
145 //
146 // const point& start = points[f[fp]];
147 // const point& end = points[f[fp1]];
148 //
149 // vector eVec(end - start);
150 //
151 // scalar s = pl.normalIntersect(start, eVec);
152 //
153 // if (s < 0 || s > 1)
154 // {
155 // pInter.setPoint(start + s*eVec);
156 //
157 // // Check if is correct one: orientation walking
158 // // eStart - eEnd - hitPoint should be opposite n
159 // vector n2(triPointRef(start, end, pInter.hitPoint()).normal());
160 //
161 // Pout<< "plane normal:" << n
162 // << " start:" << start << " end:" << end
163 // << " hit at:" << pInter.hitPoint()
164 // << " resulting normal:" << n2 << endl;
165 //
166 // if ((n2 & n) < 0)
167 // {
168 // pInter.setHit();
169 //
170 // // Find corresponding edge between f[fp] f[fp1]
171 // label edgeI =
172 // meshTools::findEdge
173 // (
174 // surf.edges(),
175 // surf.faceEdges()[hitFaceI],
176 // f[fp],
177 // f[fp1]
178 // );
179 //
180 // pInter.setIndex(edgeI);
181 //
182 // return pInter;
183 // }
184 // }
185 // }
186 //
187 // FatalErrorIn("surfaceIntersection::borderEdgeIntersection")
188 // << "Did not find intersection of plane " << pl
189 // << " with edges of face " << hitFaceI << " verts:" << f
190 // << abort(FatalError);
191 //
192 // return pInter;
193 //}
194 
195 
196 void Foam::surfaceIntersection::storeIntersection
197 (
198  const bool isFirstSurf,
199  const labelList& facesA,
200  const label faceB,
201  DynamicList<edge>& allCutEdges,
202  DynamicList<point>& allCutPoints
203 )
204 {
205  forAll(facesA, facesAI)
206  {
207  label faceA = facesA[facesAI];
208 
209  // Combine two faces. Always make sure the face from the first surface
210  // is element 0.
211  FixedList<label, 2> twoFaces;
212  if (isFirstSurf)
213  {
214  twoFaces[0] = faceA;
215  twoFaces[1] = faceB;
216  }
217  else
218  {
219  twoFaces[0] = faceB;
220  twoFaces[1] = faceA;
221  }
222 
223  labelPairLookup::const_iterator iter = facePairToVertex_.find(twoFaces);
224 
225  if (iter == facePairToVertex_.end())
226  {
227  // New intersection. Store face-face intersection.
228  facePairToVertex_.insert(twoFaces, allCutPoints.size()-1);
229  }
230  else
231  {
232  // Second occurrence of surf1-surf2 intersection.
233  // Or rather the face on surf1 intersects a face on
234  // surface2 twice -> we found edge.
235 
236  // Check whether perhaps degenerate
237  const point& prevHit = allCutPoints[*iter];
238  const point& thisHit = allCutPoints.last();
239 
240  if (mag(prevHit - thisHit) < SMALL)
241  {
242  WarningIn
243  (
244  "Foam::surfaceIntersection::storeIntersection"
245  "(const bool isFirstSurf, const labelList& facesA,"
246  "const label faceB, DynamicList<edge>& allCutEdges,"
247  "DynamicList<point>& allCutPoints)"
248  ) << "Encountered degenerate edge between face "
249  << twoFaces[0] << " on first surface"
250  << " and face " << twoFaces[1] << " on second surface"
251  << endl
252  << "Point on first surface:" << prevHit << endl
253  << "Point on second surface:" << thisHit << endl
254  << endl;
255  }
256  else
257  {
258  allCutEdges.append(edge(*iter, allCutPoints.size()-1));
259 
260  // Remember face on surf
261  facePairToEdge_.insert(twoFaces, allCutEdges.size()-1);
262  }
263  }
264  }
265 }
266 
267 
268 // Classify cut of edge of surface1 with surface2:
269 // 1- point of edge hits point on surface2
270 // 2- edge pierces point on surface2
271 // 3- point of edge hits edge on surface2
272 // 4- edge pierces edge on surface2
273 // 5- point of edge hits face on surface2
274 // 6- edge pierces face on surface2
275 //
276 // Note that handling of 2 and 4 should be the same but with surface1 and
277 // surface2 reversed.
278 void Foam::surfaceIntersection::classifyHit
279 (
280  const triSurface& surf1,
281  const scalarField& surf1PointTol,
282  const triSurface& surf2,
283  const bool isFirstSurf,
284  const label edgeI,
285  const scalar tolDim,
286  const pointIndexHit& pHit,
287 
288  DynamicList<edge>& allCutEdges,
289  DynamicList<point>& allCutPoints,
290  List<DynamicList<label> >& surfEdgeCuts
291 )
292 {
293  const edge& e = surf1.edges()[edgeI];
294 
295  const labelList& facesA = surf1.edgeFaces()[edgeI];
296 
297  // Label of face on surface2 edgeI intersected
298  label surf2FaceI = pHit.index();
299 
300  // Classify point on surface2
301 
302  const triSurface::FaceType& f2 = surf2.localFaces()[surf2FaceI];
303  const pointField& surf2Pts = surf2.localPoints();
304 
305  label nearType, nearLabel;
306 
307  f2.nearestPointClassify(pHit.hitPoint(), surf2Pts, nearType, nearLabel);
308 
309  // Classify points on edge of surface1
310  label edgeEnd =
311  classify
312  (
313  surf1PointTol[e.start()],
314  surf1PointTol[e.end()],
315  pHit.hitPoint(),
316  e,
317  surf1.localPoints()
318  );
319 
320  if (nearType == triPointRef::POINT)
321  {
322  if (edgeEnd >= 0)
323  {
324  // 1. Point hits point. Do nothing.
325  if (debug & 2)
326  {
327  Pout<< pHit.hitPoint() << " is surf1:"
328  << " end point of edge " << e
329  << " surf2: vertex " << f2[nearLabel]
330  << " coord:" << surf2Pts[f2[nearLabel]] << endl;
331  }
332  }
333  else
334  {
335  // 2. Edge hits point. Cut edge with new point.
336  if (debug & 2)
337  {
338  Pout<< pHit.hitPoint() << " is surf1:"
339  << " somewhere on edge " << e
340  << " surf2: vertex " << f2[nearLabel]
341  << " coord:" << surf2Pts[f2[nearLabel]] << endl;
342  }
343 
344  allCutPoints.append(pHit.hitPoint());
345  surfEdgeCuts[edgeI].append(allCutPoints.size()-1);
346 
347  const labelList& facesB = surf2.pointFaces()[f2[nearLabel]];
348 
349  forAll(facesB, faceBI)
350  {
351  storeIntersection
352  (
353  isFirstSurf,
354  facesA,
355  facesB[faceBI],
356  allCutEdges,
357  allCutPoints
358  );
359  }
360  }
361  }
362  else if (nearType == triPointRef::EDGE)
363  {
364  if (edgeEnd >= 0)
365  {
366  // 3. Point hits edge. Do nothing on this side. Reverse
367  // is handled by 2 (edge hits point)
368  label edge2I = getEdge(surf2, surf2FaceI, nearLabel);
369  const edge& e2 = surf2.edges()[edge2I];
370 
371  if (debug&2)
372  {
373  Pout<< pHit.hitPoint() << " is surf1:"
374  << " end point of edge " << e
375  << " surf2: edge " << e2
376  << " coords:" << surf2Pts[e2.start()]
377  << surf2Pts[e2.end()] << endl;
378  }
379  }
380  else
381  {
382  // 4. Edge hits edge.
383 
384  // Cut edge with new point (creates duplicates when
385  // doing the surf2 with surf1 intersection but these
386  // are merged later on)
387 
388  label edge2I = getEdge(surf2, surf2FaceI, nearLabel);
389  const edge& e2 = surf2.edges()[edge2I];
390 
391  if (debug&2)
392  {
393  Pout<< pHit.hitPoint() << " is surf1:"
394  << " somewhere on edge " << e
395  << " surf2: edge " << e2
396  << " coords:" << surf2Pts[e2.start()]
397  << surf2Pts[e2.end()] << endl;
398  }
399 
400  allCutPoints.append(pHit.hitPoint());
401  surfEdgeCuts[edgeI].append(allCutPoints.size()-1);
402 
403  // edge hits all faces on surf2 connected to the edge
404 
405  if (isFirstSurf)
406  {
407  // edge-edge intersection is symmetric, store only
408  // once.
409  // edge hits all faces on surf2 connected to the
410  // edge
411 
412  const labelList& facesB = surf2.edgeFaces()[edge2I];
413 
414  forAll(facesB, faceBI)
415  {
416  storeIntersection
417  (
418  isFirstSurf,
419  facesA,
420  facesB[faceBI],
421  allCutEdges,
422  allCutPoints
423  );
424  }
425  }
426  }
427  }
428  else
429  {
430  if (edgeEnd >= 0)
431  {
432  // 5. Point hits face. Do what? Introduce
433  // point & triangulation in face?
434  if (debug&2)
435  {
436  Pout<< pHit.hitPoint() << " is surf1:"
437  << " end point of edge " << e
438  << " surf2: face " << surf2FaceI
439  << endl;
440  }
441 
442  //
443  // Look exactly at what side (of surf2) edge is. Leave out ones on
444  // inside of surf2 (i.e. on opposite side of normal)
445  //
446 
447  // Vertex on/near surf2
448  label nearVert = -1;
449 
450  if (edgeEnd == 0)
451  {
452  nearVert = e.start();
453  }
454  else
455  {
456  nearVert = e.end();
457  }
458 
459  const point& nearPt = surf1.localPoints()[nearVert];
460 
461  // Vertex away from surf2
462  label otherVert = e.otherVertex(nearVert);
463 
464  const point& otherPt = surf1.localPoints()[otherVert];
465 
466 
467  if (debug)
468  {
469  Pout
470  << pHit.hitPoint() << " is surf1:"
471  << " end point of edge " << e << " coord:"
472  << surf1.localPoints()[nearVert]
473  << " surf2: face " << surf2FaceI << endl;
474  }
475 
476  vector eVec = otherPt - nearPt;
477 
478  if ((surf2.faceNormals()[surf2FaceI] & eVec) > 0)
479  {
480  // otherVert on outside of surf2
481 
482  // Shift hitPoint a bit along edge.
483  //point hitPt = nearPt + 0.1*eVec;
484  point hitPt = nearPt;
485 
486  if (debug&2)
487  {
488  Pout<< "Shifted " << pHit.hitPoint()
489  << " to " << hitPt
490  << " along edge:" << e
491  << " coords:" << surf1.localPoints()[e.start()]
492  << surf1.localPoints()[e.end()] << endl;
493  }
494 
495  // Reclassify as normal edge-face pierce (see below)
496 
497  allCutPoints.append(hitPt);
498  surfEdgeCuts[edgeI].append(allCutPoints.size()-1);
499 
500  // edge hits single face only
501  storeIntersection
502  (
503  isFirstSurf,
504  facesA,
505  surf2FaceI,
506  allCutEdges,
507  allCutPoints
508  );
509  }
510  else
511  {
512  if (debug&2)
513  {
514  Pout<< "Discarding " << pHit.hitPoint()
515  << " since edge " << e << " on inside of surf2."
516  << " surf2 normal:" << surf2.faceNormals()[surf2FaceI]
517  << endl;
518  }
519  }
520  }
521  else
522  {
523  // 6. Edge pierces face. 'Normal' situation.
524  if (debug&2)
525  {
526  Pout<< pHit.hitPoint() << " is surf1:"
527  << " somewhere on edge " << e
528  << " surf2: face " << surf2FaceI
529  << endl;
530  }
531 
532  // edgeI intersects surf2. Store point.
533  allCutPoints.append(pHit.hitPoint());
534  surfEdgeCuts[edgeI].append(allCutPoints.size()-1);
535 
536  // edge hits single face only
537  storeIntersection
538  (
539  isFirstSurf,
540  facesA,
541  surf2FaceI,
542  allCutEdges,
543  allCutPoints
544  );
545  }
546  }
547  if (debug&2)
548  {
549  Pout<< endl;
550  }
551 }
552 
553 
554 // Cut all edges of surf1 with surf2. Sets
555 // - cutPoints : coordinates of cutPoints
556 // - cutEdges : newly created edges between cutPoints
557 // - facePairToVertex : hash from face1I and face2I to cutPoint
558 // - facePairToEdge : hash from face1I and face2I to cutEdge
559 // - surfEdgeCuts : gives for each edge the cutPoints
560 // (in order from start to end)
561 //
562 void Foam::surfaceIntersection::doCutEdges
563 (
564  const triSurface& surf1,
565  const triSurfaceSearch& querySurf2,
566  const bool isFirstSurf,
567  const bool isSelfIntersection,
568 
569  DynamicList<edge>& allCutEdges,
570  DynamicList<point>& allCutPoints,
571  List<DynamicList<label> >& surfEdgeCuts
572 )
573 {
574  scalar oldTol = intersection::setPlanarTol(1e-3);
575 
576  const pointField& surf1Pts = surf1.localPoints();
577 
578  // Calculate local (to point) tolerance based on min edge length.
579  scalarField surf1PointTol(surf1Pts.size());
580 
581  forAll(surf1PointTol, pointI)
582  {
583  surf1PointTol[pointI] =
585  * minEdgeLen(surf1, pointI);
586  }
587 
588  const triSurface& surf2 = querySurf2.surface();
589 
590  forAll(surf1.edges(), edgeI)
591  {
592  const edge& e = surf1.edges()[edgeI];
593 
594  point pStart = surf1Pts[e.start()];
595  const point& pEnd = surf1Pts[e.end()];
596 
597  const point tolVec = intersection::planarTol()*(pEnd-pStart);
598  const scalar tolDim = mag(tolVec);
599 
600  bool doTrack = false;
601  do
602  {
603  pointIndexHit pHit = querySurf2.tree().findLine(pStart, pEnd);
604 
605  if (pHit.hit())
606  {
607  if (isSelfIntersection)
608  {
609  // Skip all intersections which are hit at endpoints of
610  // edge.
611  // Problem is that if faces are almost coincident the
612  // intersection point will be calculated quite incorrectly
613  // The error might easily be larger than 1% of the edge
614  // length.
615  // So what we do here is to exclude hit faces if our edge
616  // is in their plane and they share a point with the edge.
617 
618  // Label of face on surface2 edgeI intersected
619  label hitFaceI = pHit.index();
620 
621  if
622  (
623  !excludeEdgeHit
624  (
625  surf1,
626  edgeI,
627  hitFaceI,
628  0.1 // 1-cos of angle between normals
629  )
630  )
631  {
632  // Classify point on surface1
633  label edgeEnd = classify
634  (
635  surf1PointTol[e.start()],
636  surf1PointTol[e.end()],
637  pHit.hitPoint(),
638  e,
639  surf1Pts
640  );
641 
642  if (edgeEnd < 0)
643  {
644  if (debug)
645  {
646  Pout<< "edge:" << edgeI << " vertices:" << e
647  << " start:" << surf1Pts[e.start()]
648  << " end:" << surf1Pts[e.end()]
649  << " hit:" << pHit.hitPoint()
650  << " tolDim:" << tolDim
651  << " planarTol:"
653  << endl;
654  }
655  allCutPoints.append(pHit.hitPoint());
656  surfEdgeCuts[edgeI].append(allCutPoints.size()-1);
657  }
658  }
659  }
660  else
661  {
662  classifyHit
663  (
664  surf1,
665  surf1PointTol,
666  surf2,
667  isFirstSurf,
668  edgeI,
669  tolDim,
670  pHit,
671 
672  allCutEdges,
673  allCutPoints,
674  surfEdgeCuts
675  );
676  }
677 
678  if (mag(pHit.hitPoint() - pEnd) < tolDim)
679  {
680  doTrack = false;
681  }
682  else
683  {
684  pStart = pHit.hitPoint() + tolVec;
685 
686  doTrack = true;
687  }
688  }
689  else
690  {
691  doTrack = false;
692  }
693  }
694  while (doTrack);
695  }
696 
698 }
699 
700 
701 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
702 
703 // Null constructor
705 :
706  cutPoints_(0),
707  cutEdges_(0),
708  facePairToVertex_(0),
709  facePairToEdge_(0),
710  surf1EdgeCuts_(0),
711  surf2EdgeCuts_(0)
712 {}
713 
714 
715 // Construct from two surfaces
717 (
718  const triSurfaceSearch& query1,
719  const triSurfaceSearch& query2
720 )
721 :
722  cutPoints_(0),
723  cutEdges_(0),
724  facePairToVertex_(2*max(query1.surface().size(), query2.surface().size())),
725  facePairToEdge_(2*max(query1.surface().size(), query2.surface().size())),
726  surf1EdgeCuts_(0),
727  surf2EdgeCuts_(0)
728 {
729  const triSurface& surf1 = query1.surface();
730  const triSurface& surf2 = query2.surface();
731 
732  //
733  // Cut all edges of surf1 with surf2.
734  //
735  if (debug)
736  {
737  Pout<< "Cutting surf1 edges" << endl;
738  }
739 
740 
741  DynamicList<edge> allCutEdges(surf1.nEdges()/20);
742  DynamicList<point> allCutPoints(surf1.nPoints()/20);
743 
744 
745  // From edge to cut index on surface1
746  List<DynamicList<label> > edgeCuts1(query1.surface().nEdges());
747 
748  doCutEdges
749  (
750  surf1,
751  query2,
752  true, // is first surface; construct labelPair in correct
753  // order
754  false, // not self intersection
755 
756  allCutEdges,
757  allCutPoints,
758  edgeCuts1
759  );
760  // Transfer to straight labelListList
761  transfer(edgeCuts1, surf1EdgeCuts_);
762 
763 
764  //
765  // Cut all edges of surf2 with surf1.
766  //
767  if (debug)
768  {
769  Pout<< "Cutting surf2 edges" << endl;
770  }
771 
772  // From edge to cut index
773  List<DynamicList<label> > edgeCuts2(query2.surface().nEdges());
774 
775  doCutEdges
776  (
777  surf2,
778  query1,
779  false, // is second surface
780  false, // not self intersection
781 
782  allCutEdges,
783  allCutPoints,
784  edgeCuts2
785  );
786 
787  // Transfer to straight label(List)List
788  transfer(edgeCuts2, surf2EdgeCuts_);
789  cutEdges_.transfer(allCutEdges);
790  cutPoints_.transfer(allCutPoints);
791 
792 
793  if (debug)
794  {
795  Pout<< "surfaceIntersection : Intersection generated:"
796  << endl
797  << " points:" << cutPoints_.size() << endl
798  << " edges :" << cutEdges_.size() << endl;
799 
800  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
801  << endl;
802 
803  OFstream intStream("intEdges.obj");
804  writeOBJ(cutPoints_, cutEdges_, intStream);
805 
806  // Dump all cut edges to files
807  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
808  OFstream edge1Stream("surf1EdgeCuts.obj");
809  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
810 
811  Pout<< "Dumping cut edges of surface2 to surf2EdgeCuts.obj" << endl;
812  OFstream edge2Stream("surf2EdgeCuts.obj");
813  writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream);
814  }
815 }
816 
817 
818 // Construct from full intersection Poutrmation
820 (
821  const triSurface& surf1,
822  const edgeIntersections& intersections1,
823  const triSurface& surf2,
824  const edgeIntersections& intersections2
825 )
826 :
827  cutPoints_(0),
828  cutEdges_(0),
829  facePairToVertex_(2*max(surf1.size(), surf2.size())),
830  facePairToEdge_(2*max(surf1.size(), surf2.size())),
831  surf1EdgeCuts_(0),
832  surf2EdgeCuts_(0)
833 {
834 
835  // All intersection Pout (so for both surfaces)
836  DynamicList<edge> allCutEdges((surf1.nEdges() + surf2.nEdges())/20);
837  DynamicList<point> allCutPoints((surf1.nPoints() + surf2.nPoints())/20);
838 
839 
840  // Cut all edges of surf1 with surf2
841  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
842 
843  if (debug)
844  {
845  Pout<< "Storing surf1 intersections" << endl;
846  }
847 
848  {
849  // From edge to cut index on surface1
850  List<DynamicList<label> > edgeCuts1(surf1.nEdges());
851 
852  forAll(intersections1, edgeI)
853  {
854  const List<pointIndexHit>& intersections = intersections1[edgeI];
855 
856  forAll(intersections, i)
857  {
858  const pointIndexHit& pHit = intersections[i];
859 
860  // edgeI intersects surf2. Store point.
861  allCutPoints.append(pHit.hitPoint());
862  edgeCuts1[edgeI].append(allCutPoints.size()-1);
863 
864  storeIntersection
865  (
866  true, // is first surface
867  surf1.edgeFaces()[edgeI],
868  pHit.index(), // surf2FaceI
869  allCutEdges,
870  allCutPoints
871  );
872  }
873  }
874 
875  // Transfer to straight labelListList
876  transfer(edgeCuts1, surf1EdgeCuts_);
877  }
878 
879 
880 
881  // Cut all edges of surf2 with surf1
882  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
883 
884  if (debug)
885  {
886  Pout<< "Storing surf2 intersections" << endl;
887  }
888 
889  {
890  // From edge to cut index on surface2
891  List<DynamicList<label> > edgeCuts2(surf2.nEdges());
892 
893  forAll(intersections2, edgeI)
894  {
895  const List<pointIndexHit>& intersections = intersections2[edgeI];
896 
897  forAll(intersections, i)
898  {
899  const pointIndexHit& pHit = intersections[i];
900 
901  // edgeI intersects surf1. Store point.
902  allCutPoints.append(pHit.hitPoint());
903  edgeCuts2[edgeI].append(allCutPoints.size()-1);
904 
905  storeIntersection
906  (
907  false, // is second surface
908  surf2.edgeFaces()[edgeI],
909  pHit.index(), // surf2FaceI
910  allCutEdges,
911  allCutPoints
912  );
913  }
914  }
915 
916  // Transfer to surf2EdgeCuts_ (straight labelListList)
917  transfer(edgeCuts2, surf2EdgeCuts_);
918  }
919 
920 
921  // Transfer to straight label(List)List
922  cutEdges_.transfer(allCutEdges);
923  cutPoints_.transfer(allCutPoints);
924 
925 
926  if (debug)
927  {
928  Pout<< "surfaceIntersection : Intersection generated:"
929  << endl
930  << " points:" << cutPoints_.size() << endl
931  << " edges :" << cutEdges_.size() << endl;
932 
933  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
934  << endl;
935 
936  OFstream intStream("intEdges.obj");
937  writeOBJ(cutPoints_, cutEdges_, intStream);
938 
939  // Dump all cut edges to files
940  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
941  OFstream edge1Stream("surf1EdgeCuts.obj");
942  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
943 
944  Pout<< "Dumping cut edges of surface2 to surf2EdgeCuts.obj" << endl;
945  OFstream edge2Stream("surf2EdgeCuts.obj");
946  writeIntersectedEdges(surf2, surf2EdgeCuts_, edge2Stream);
947  }
948 
949 
950  // Debugging stuff
951  {
952  // Check all facePairToVertex is used.
953  labelHashSet usedPoints;
954 
955  forAllConstIter(labelPairLookup, facePairToEdge_, iter)
956  {
957  label edgeI = iter();
958 
959  const edge& e = cutEdges_[edgeI];
960 
961  usedPoints.insert(e[0]);
962  usedPoints.insert(e[1]);
963  }
964 
965  forAllConstIter(labelPairLookup, facePairToVertex_, iter)
966  {
967  label pointI = iter();
968 
969  if (!usedPoints.found(pointI))
970  {
971  WarningIn("surfaceIntersection::surfaceIntersection")
972  << "Problem: cut point:" << pointI
973  << " coord:" << cutPoints_[pointI]
974  << " not used by any edge" << endl;
975  }
976  }
977  }
978 }
979 
980 
981 // Construct from single surface. Used to test for self-intersection.
983 (
984  const triSurfaceSearch& query1
985 )
986 :
987  cutPoints_(0),
988  cutEdges_(0),
989  facePairToVertex_(2*query1.surface().size()),
990  facePairToEdge_(2*query1.surface().size()),
991  surf1EdgeCuts_(0),
992  surf2EdgeCuts_(0)
993 {
994  const triSurface& surf1 = query1.surface();
995 
996  //
997  // Cut all edges of surf1 with surf1 itself.
998  //
999  if (debug)
1000  {
1001  Pout<< "Cutting surf1 edges" << endl;
1002  }
1003 
1004  DynamicList<edge> allCutEdges;
1005  DynamicList<point> allCutPoints;
1006 
1007  // From edge to cut index on surface1
1008  List<DynamicList<label> > edgeCuts1(query1.surface().nEdges());
1009 
1010  doCutEdges
1011  (
1012  surf1,
1013  query1,
1014  true, // is first surface; construct labelPair in correct
1015  // order
1016  true, // self intersection
1017 
1018 
1019  allCutEdges,
1020  allCutPoints,
1021  edgeCuts1
1022  );
1023 
1024  // Transfer to straight label(List)List
1025  transfer(edgeCuts1, surf1EdgeCuts_);
1026  cutEdges_.transfer(allCutEdges);
1027  cutPoints_.transfer(allCutPoints);
1028 
1029  // Shortcut.
1030  if (cutPoints_.empty() && cutEdges_.empty())
1031  {
1032  if (debug)
1033  {
1034  Pout<< "Empty intersection" << endl;
1035  }
1036  return;
1037  }
1038 
1039  //
1040  // Remove duplicate points (from edge-point or edge-edge cutting)
1041  //
1042 
1043  // Get typical dimension.
1044  scalar minEdgeLen = GREAT;
1045  forAll(surf1.edges(), edgeI)
1046  {
1047  minEdgeLen = min
1048  (
1049  minEdgeLen,
1050  surf1.edges()[edgeI].mag(surf1.localPoints())
1051  );
1052  }
1053 
1054  // Merge points
1055  labelList pointMap;
1056  pointField newPoints;
1057 
1058  bool hasMerged = mergePoints
1059  (
1060  cutPoints_,
1061  minEdgeLen*intersection::planarTol(),
1062  false,
1063  pointMap,
1064  newPoints
1065  );
1066 
1067  if (hasMerged)
1068  {
1069  if (debug)
1070  {
1071  Pout<< "Merged:" << hasMerged
1072  << " mergeDist:" << minEdgeLen*intersection::planarTol()
1073  << " cutPoints:" << cutPoints_.size()
1074  << " newPoints:" << newPoints.size()
1075  << endl;
1076  }
1077 
1078  // Copy points
1079  cutPoints_.transfer(newPoints);
1080 
1081  // Renumber vertices referenced by edges
1082  forAll(cutEdges_, edgeI)
1083  {
1084  edge& e = cutEdges_[edgeI];
1085 
1086  e.start() = pointMap[e.start()];
1087  e.end() = pointMap[e.end()];
1088 
1089  if (e.mag(cutPoints_) < minEdgeLen*intersection::planarTol())
1090  {
1091  if (debug)
1092  {
1093  Pout<< "Degenerate cut:" << edgeI << " vertices:" << e
1094  << " coords:" << cutPoints_[e.start()] << ' '
1095  << cutPoints_[e.end()] << endl;
1096  }
1097  }
1098  }
1099 
1100  // Renumber vertices referenced by edgeCut lists. Remove duplicates.
1101  forAll(surf1EdgeCuts_, edgeI)
1102  {
1103  // Get indices of cutPoints this edge is cut by
1104  labelList& cutVerts = surf1EdgeCuts_[edgeI];
1105 
1106  removeDuplicates(pointMap, cutVerts);
1107  }
1108  }
1109 
1110  if (debug)
1111  {
1112  Pout<< "surfaceIntersection : Intersection generated and compressed:"
1113  << endl
1114  << " points:" << cutPoints_.size() << endl
1115  << " edges :" << cutEdges_.size() << endl;
1116 
1117 
1118  Pout<< "surfaceIntersection : Writing intersection to intEdges.obj"
1119  << endl;
1120 
1121  OFstream intStream("intEdges.obj");
1122  writeOBJ(cutPoints_, cutEdges_, intStream);
1123  }
1124 
1125  if (debug)
1126  {
1127  // Dump all cut edges to files
1128  Pout<< "Dumping cut edges of surface1 to surf1EdgeCuts.obj" << endl;
1129  OFstream edge1Stream("surf1EdgeCuts.obj");
1130  writeIntersectedEdges(surf1, surf1EdgeCuts_, edge1Stream);
1131  }
1132 }
1133 
1134 
1135 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1136 
1138 {
1139  return cutPoints_;
1140 }
1141 
1142 
1144 {
1145  return cutEdges_;
1146 }
1147 
1148 
1150 {
1151  return facePairToVertex_;
1152 }
1153 
1154 
1156 {
1157  return facePairToEdge_;
1158 }
1159 
1160 
1163  const bool isFirstSurf
1164 ) const
1165 {
1166  if (isFirstSurf)
1167  {
1168  return surf1EdgeCuts_;
1169  }
1170  else
1171  {
1172  return surf2EdgeCuts_;
1173  }
1174 }
1175 
1176 
1178 {
1179  return surf1EdgeCuts_;
1180 }
1181 
1182 
1184 {
1185  return surf2EdgeCuts_;
1186 }
1187 
1188 
1189 // ************************************************************************* //
Output to file stream.
Definition: OFstream.H:81
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
vector point
Point is a vector.
Definition: point.H:41
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:390
dimensioned< scalar > mag(const dimensioned< Type > &)
edgeList edges() const
Return edges in face point ordering,.
Definition: triFaceI.H:318
const labelListList & edgeFaces() const
Return edge-face addressing.
Merge points. See below.
bool empty() const
Return true if the UList is empty (ie, size() is zero).
Definition: UListI.H:313
Triangulated surface description with patch information.
Definition: triSurface.H:57
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:310
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:192
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
label index() const
Return index.
label nPoints() const
Return number of points supporting patch faces.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Namespace for OpenFOAM.
static scalar setPlanarTol(const scalar t)
Set the planar tolerance, returning the previous value.
Definition: intersection.H:91
const Point & hitPoint() const
Return hit point.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
scalar mag(const pointField &) const
Return scalar magnitude.
Definition: edgeI.H:163
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
Holder of intersections of edges of a surface with another surface. Optionally shuffles around points...
const Field< PointType > & localPoints() const
Return pointField of points in patch.
const double e
Elementary charge.
Definition: doubleFloat.H:78
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
#define WarningIn(functionName)
Report a warning using Foam::Warning.
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
const labelPairLookup & facePairToVertex() const
#define forAll(list, i)
Definition: UList.H:421
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const pointField & cutPoints() const
const labelListList & edgeCuts(const bool) const
Access either surf1EdgeCuts (isFirstSurface = true) or.
const labelListList & surf2EdgeCuts() const
static scalar planarTol()
Return planar tolerance.
Definition: intersection.H:85
label mergePoints(const UList< Type > &points, const scalar mergeTol, const bool verbose, labelList &pointMap, const Type &origin=Type::zero)
Sorts and merges points. All points closer than/equal mergeTol get merged.
surfaceIntersection()
Construct null.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
const labelListList & surf1EdgeCuts() const
label end() const
Return end vertex label.
Definition: edgeI.H:92
List< label > labelList
A List of labels.
Definition: labelList.H:56
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
const labelPairLookup & facePairToEdge() const
label start() const
Return start vertex label.
Definition: edgeI.H:81
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
label nEdges() const
Return number of edges in patch.
const triSurface & surface() const
Return reference to the surface.
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:109
defineTypeNameAndDebug(combustionModel, 0)
const edgeList & cutEdges() const
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
Helper class to search on triSurface.
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116