surfaceFeatures.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 "surfaceFeatures.H"
27 #include "triSurface.H"
28 #include "indexedOctree.H"
29 #include "treeDataEdge.H"
30 #include "treeDataPoint.H"
31 #include "meshTools.H"
32 #include "linePointRef.H"
33 #include "OFstream.H"
34 #include "IFstream.H"
35 #include "unitConversion.H"
36 #include "EdgeMap.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42 defineTypeNameAndDebug(surfaceFeatures, 0);
43 
44 const scalar surfaceFeatures::parallelTolerance = sin(degToRad(1.0));
45 }
46 
47 
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 
50 //- Get nearest point on edge and classify position on edge.
51 Foam::pointIndexHit Foam::surfaceFeatures::edgeNearest
52 (
53  const point& start,
54  const point& end,
55  const point& sample
56 )
57 {
58  pointHit eHit = linePointRef(start, end).nearestDist(sample);
59 
60  // Classification of position on edge.
61  label endPoint;
62 
63  if (eHit.hit())
64  {
65  // Nearest point is on edge itself.
66  // Note: might be at or very close to endpoint. We should use tolerance
67  // here.
68  endPoint = -1;
69  }
70  else
71  {
72  // Nearest point has to be one of the end points. Find out
73  // which one.
74  if
75  (
76  mag(eHit.rawPoint() - start)
77  < mag(eHit.rawPoint() - end)
78  )
79  {
80  endPoint = 0;
81  }
82  else
83  {
84  endPoint = 1;
85  }
86  }
87 
88  return pointIndexHit(eHit.hit(), eHit.rawPoint(), endPoint);
89 }
90 
91 
92 // Go from selected edges only to a value for every edge
94  const
95 {
96  List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
97 
98  // Region edges first
99  for (label i = 0; i < externalStart_; i++)
100  {
101  edgeStat[featureEdges_[i]] = REGION;
102  }
103 
104  // External edges
105  for (label i = externalStart_; i < internalStart_; i++)
106  {
107  edgeStat[featureEdges_[i]] = EXTERNAL;
108  }
109 
110  // Internal edges
111  for (label i = internalStart_; i < featureEdges_.size(); i++)
112  {
113  edgeStat[featureEdges_[i]] = INTERNAL;
114  }
115 
116  return edgeStat;
117 }
118 
119 
120 // Set from value for every edge
122 (
123  const List<edgeStatus>& edgeStat,
124  const scalar includedAngle
125 )
126 {
127  // Count
128 
129  label nRegion = 0;
130  label nExternal = 0;
131  label nInternal = 0;
132 
133  forAll(edgeStat, edgeI)
134  {
135  if (edgeStat[edgeI] == REGION)
136  {
137  nRegion++;
138  }
139  else if (edgeStat[edgeI] == EXTERNAL)
140  {
141  nExternal++;
142  }
143  else if (edgeStat[edgeI] == INTERNAL)
144  {
145  nInternal++;
146  }
147  }
148 
149  externalStart_ = nRegion;
150  internalStart_ = externalStart_ + nExternal;
151 
152 
153  // Copy
154 
155  featureEdges_.setSize(internalStart_ + nInternal);
156 
157  label regionI = 0;
158  label externalI = externalStart_;
159  label internalI = internalStart_;
160 
161  forAll(edgeStat, edgeI)
162  {
163  if (edgeStat[edgeI] == REGION)
164  {
165  featureEdges_[regionI++] = edgeI;
166  }
167  else if (edgeStat[edgeI] == EXTERNAL)
168  {
169  featureEdges_[externalI++] = edgeI;
170  }
171  else if (edgeStat[edgeI] == INTERNAL)
172  {
173  featureEdges_[internalI++] = edgeI;
174  }
175  }
176 
177  const scalar minCos = Foam::cos(degToRad(180.0 - includedAngle));
178 
179  calcFeatPoints(edgeStat, minCos);
180 }
181 
182 
183 //construct feature points where more than 2 feature edges meet
184 void Foam::surfaceFeatures::calcFeatPoints
185 (
186  const List<edgeStatus>& edgeStat,
187  const scalar minCos
188 )
189 {
190  DynamicList<label> featurePoints(surf_.nPoints()/1000);
191 
192  const labelListList& pointEdges = surf_.pointEdges();
193  const edgeList& edges = surf_.edges();
194  const pointField& localPoints = surf_.localPoints();
195 
196  forAll(pointEdges, pointI)
197  {
198  const labelList& pEdges = pointEdges[pointI];
199 
200  label nFeatEdges = 0;
201 
202  forAll(pEdges, i)
203  {
204  if (edgeStat[pEdges[i]] != NONE)
205  {
206  nFeatEdges++;
207  }
208  }
209 
210  if (nFeatEdges > 2)
211  {
212  featurePoints.append(pointI);
213  }
214  else if (nFeatEdges == 2)
215  {
216  // Check the angle between the two edges
217  DynamicList<vector> edgeVecs(2);
218 
219  forAll(pEdges, i)
220  {
221  const label edgeI = pEdges[i];
222 
223  if (edgeStat[edgeI] != NONE)
224  {
225  edgeVecs.append(edges[edgeI].vec(localPoints));
226  edgeVecs.last() /= mag(edgeVecs.last());
227  }
228  }
229 
230  if (mag(edgeVecs[0] & edgeVecs[1]) < minCos)
231  {
232  featurePoints.append(pointI);
233  }
234  }
235  }
236 
237  featurePoints_.transfer(featurePoints);
238 }
239 
240 
241 void Foam::surfaceFeatures::classifyFeatureAngles
242 (
243  const labelListList& edgeFaces,
244  List<edgeStatus>& edgeStat,
245  const scalar minCos,
246  const bool geometricTestOnly
247 ) const
248 {
249  const vectorField& faceNormals = surf_.faceNormals();
250  const pointField& points = surf_.points();
251 
252  // Special case: minCos=1
253  bool selectAll = (mag(minCos-1.0) < SMALL);
254 
255  forAll(edgeFaces, edgeI)
256  {
257  const labelList& eFaces = edgeFaces[edgeI];
258 
259  if (eFaces.size() != 2)
260  {
261  // Non-manifold. What to do here? Is region edge? external edge?
262  edgeStat[edgeI] = REGION;
263  }
264  else
265  {
266  label face0 = eFaces[0];
267  label face1 = eFaces[1];
268 
269  if
270  (
271  !geometricTestOnly
272  && surf_[face0].region() != surf_[face1].region()
273  )
274  {
275  edgeStat[edgeI] = REGION;
276  }
277  else if
278  (
279  selectAll
280  || ((faceNormals[face0] & faceNormals[face1]) < minCos)
281  )
282  {
283  // Check if convex or concave by looking at angle
284  // between face centres and normal
285  vector f0Tof1 =
286  surf_[face1].centre(points)
287  - surf_[face0].centre(points);
288 
289  if ((f0Tof1 & faceNormals[face0]) >= 0.0)
290  {
291  edgeStat[edgeI] = INTERNAL;
292  }
293  else
294  {
295  edgeStat[edgeI] = EXTERNAL;
296  }
297  }
298  }
299  }
300 }
301 
302 
303 // Returns next feature edge connected to pointI with correct value.
304 Foam::label Foam::surfaceFeatures::nextFeatEdge
305 (
306  const List<edgeStatus>& edgeStat,
307  const labelList& featVisited,
308  const label unsetVal,
309  const label prevEdgeI,
310  const label vertI
311 ) const
312 {
313  const labelList& pEdges = surf_.pointEdges()[vertI];
314 
315  label nextEdgeI = -1;
316 
317  forAll(pEdges, i)
318  {
319  label edgeI = pEdges[i];
320 
321  if
322  (
323  edgeI != prevEdgeI
324  && edgeStat[edgeI] != NONE
325  && featVisited[edgeI] == unsetVal
326  )
327  {
328  if (nextEdgeI == -1)
329  {
330  nextEdgeI = edgeI;
331  }
332  else
333  {
334  // More than one feature edge to choose from. End of segment.
335  return -1;
336  }
337  }
338  }
339 
340  return nextEdgeI;
341 }
342 
343 
344 // Finds connected feature edges by walking from prevEdgeI in direction of
345 // prevPointI. Marks feature edges visited in featVisited by assigning them
346 // the current feature line number. Returns cumulative length of edges walked.
347 // Works in one of two modes:
348 // - mark : step to edges with featVisited = -1.
349 // Mark edges visited with currentFeatI.
350 // - clear : step to edges with featVisited = currentFeatI
351 // Mark edges visited with -2 and erase from feature edges.
352 Foam::surfaceFeatures::labelScalar Foam::surfaceFeatures::walkSegment
353 (
354  const bool mark,
355  const List<edgeStatus>& edgeStat,
356  const label startEdgeI,
357  const label startPointI,
358  const label currentFeatI,
359  labelList& featVisited
360 )
361 {
362  label edgeI = startEdgeI;
363 
364  label vertI = startPointI;
365 
366  scalar visitedLength = 0.0;
367 
368  label nVisited = 0;
369 
370  if (findIndex(featurePoints_, startPointI) >= 0)
371  {
372  // Do not walk across feature points
373 
374  return labelScalar(nVisited, visitedLength);
375  }
376 
377  //
378  // Now we have:
379  // edgeI : first edge on this segment
380  // vertI : one of the endpoints of this segment
381  //
382  // Start walking, marking off edges (in featVisited)
383  // as we go along.
384  //
385 
386  label unsetVal;
387 
388  if (mark)
389  {
390  unsetVal = -1;
391  }
392  else
393  {
394  unsetVal = currentFeatI;
395  }
396 
397  do
398  {
399  // Step to next feature edge with value unsetVal
400  edgeI = nextFeatEdge(edgeStat, featVisited, unsetVal, edgeI, vertI);
401 
402  if (edgeI == -1 || edgeI == startEdgeI)
403  {
404  break;
405  }
406 
407  // Mark with current value. If in clean mode also remove feature edge.
408 
409  if (mark)
410  {
411  featVisited[edgeI] = currentFeatI;
412  }
413  else
414  {
415  featVisited[edgeI] = -2;
416  }
417 
418 
419  // Step to next vertex on edge
420  const edge& e = surf_.edges()[edgeI];
421 
422  vertI = e.otherVertex(vertI);
423 
424 
425  // Update cumulative length
426  visitedLength += e.mag(surf_.localPoints());
427 
428  nVisited++;
429 
430  if (nVisited > surf_.nEdges())
431  {
432  Warning<< "walkSegment : reached iteration limit in walking "
433  << "feature edges on surface from edge:" << startEdgeI
434  << " vertex:" << startPointI << nl
435  << "Returning with large length" << endl;
436 
437  return labelScalar(nVisited, GREAT);
438  }
439  }
440  while (true);
441 
442  return labelScalar(nVisited, visitedLength);
443 }
444 
445 
446 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
447 
449 :
450  surf_(surf),
451  featurePoints_(0),
452  featureEdges_(0),
453  externalStart_(0),
454  internalStart_(0)
455 {}
456 
457 
458 // Construct from components.
460 (
461  const triSurface& surf,
462  const labelList& featurePoints,
463  const labelList& featureEdges,
464  const label externalStart,
465  const label internalStart
466 )
467 :
468  surf_(surf),
469  featurePoints_(featurePoints),
470  featureEdges_(featureEdges),
471  externalStart_(externalStart),
472  internalStart_(externalStart)
473 {}
474 
475 
476 // Construct from surface, angle and min length
478 (
479  const triSurface& surf,
480  const scalar includedAngle,
481  const scalar minLen,
482  const label minElems,
483  const bool geometricTestOnly
484 )
485 :
486  surf_(surf),
487  featurePoints_(0),
488  featureEdges_(0),
489  externalStart_(0),
490  internalStart_(0)
491 {
492  findFeatures(includedAngle, geometricTestOnly);
493 
494  if (minLen > 0 || minElems > 0)
495  {
496  trimFeatures(minLen, minElems, includedAngle);
497  }
498 }
499 
500 
501 //- Construct from dictionary
503 (
504  const triSurface& surf,
505  const dictionary& featInfoDict
506 )
507 :
508  surf_(surf),
509  featurePoints_(featInfoDict.lookup("featurePoints")),
510  featureEdges_(featInfoDict.lookup("featureEdges")),
511  externalStart_(readLabel(featInfoDict.lookup("externalStart"))),
512  internalStart_(readLabel(featInfoDict.lookup("internalStart")))
513 {}
514 
515 
516 //- Construct from file
518 (
519  const triSurface& surf,
520  const fileName& fName
521 )
522 :
523  surf_(surf),
524  featurePoints_(0),
525  featureEdges_(0),
526  externalStart_(0),
527  internalStart_(0)
528 {
529  IFstream str(fName);
530 
531  dictionary featInfoDict(str);
532 
533  featureEdges_ = labelList(featInfoDict.lookup("featureEdges"));
534  featurePoints_ = labelList(featInfoDict.lookup("featurePoints"));
535  externalStart_ = readLabel(featInfoDict.lookup("externalStart"));
536  internalStart_ = readLabel(featInfoDict.lookup("internalStart"));
537 }
538 
539 
541 (
542  const triSurface& surf,
543  const pointField& points,
544  const edgeList& edges,
545  const scalar mergeTol,
546  const bool geometricTestOnly
547 )
548 :
549  surf_(surf),
550  featurePoints_(0),
551  featureEdges_(0),
552  externalStart_(0),
553  internalStart_(0)
554 {
555  // Match edge mesh edges with the triSurface edges
556 
557  const labelListList& surfEdgeFaces = surf_.edgeFaces();
558  const edgeList& surfEdges = surf_.edges();
559 
560  scalar mergeTolSqr = sqr(mergeTol);
561 
562  EdgeMap<label> dynFeatEdges(2*edges.size());
563  DynamicList<labelList> dynFeatureEdgeFaces(edges.size());
564 
565  labelList edgeLabel;
566 
568  (
569  edges,
570  points,
571  mergeTolSqr,
572  edgeLabel // label of surface edge or -1
573  );
574 
575  label count = 0;
576  forAll(edgeLabel, sEdgeI)
577  {
578  const label sEdge = edgeLabel[sEdgeI];
579 
580  if (sEdge == -1)
581  {
582  continue;
583  }
584 
585  dynFeatEdges.insert(surfEdges[sEdge], count++);
586  dynFeatureEdgeFaces.append(surfEdgeFaces[sEdge]);
587  }
588 
589  // Find whether an edge is external or internal
590  List<edgeStatus> edgeStat(dynFeatEdges.size(), NONE);
591 
592  classifyFeatureAngles
593  (
594  dynFeatureEdgeFaces,
595  edgeStat,
596  GREAT,
597  geometricTestOnly
598  );
599 
600  // Transfer the edge status to a list encompassing all edges in the surface
601  // so that calcFeatPoints can be used.
602  List<edgeStatus> allEdgeStat(surf_.nEdges(), NONE);
603 
604  forAll(allEdgeStat, eI)
605  {
606  EdgeMap<label>::const_iterator iter = dynFeatEdges.find(surfEdges[eI]);
607 
608  if (iter != dynFeatEdges.end())
609  {
610  allEdgeStat[eI] = edgeStat[iter()];
611  }
612  }
613 
614  edgeStat.clear();
615  dynFeatEdges.clear();
616 
617  setFromStatus(allEdgeStat, GREAT);
618 }
619 
620 
621 //- Construct as copy
623 :
624  surf_(sf.surface()),
625  featurePoints_(sf.featurePoints()),
626  featureEdges_(sf.featureEdges()),
627  externalStart_(sf.externalStart()),
628  internalStart_(sf.internalStart())
629 {}
630 
631 
632 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
633 
635 (
636  const bool regionEdges,
637  const bool externalEdges,
638  const bool internalEdges
639 ) const
640 {
641  DynamicList<label> selectedEdges;
642 
643  if (regionEdges)
644  {
645  selectedEdges.setCapacity(selectedEdges.size() + nRegionEdges());
646 
647  for (label i = 0; i < externalStart_; i++)
648  {
649  selectedEdges.append(featureEdges_[i]);
650  }
651  }
652 
653  if (externalEdges)
654  {
655  selectedEdges.setCapacity(selectedEdges.size() + nExternalEdges());
656 
657  for (label i = externalStart_; i < internalStart_; i++)
658  {
659  selectedEdges.append(featureEdges_[i]);
660  }
661  }
662 
663  if (internalEdges)
664  {
665  selectedEdges.setCapacity(selectedEdges.size() + nInternalEdges());
666 
667  for (label i = internalStart_; i < featureEdges_.size(); i++)
668  {
669  selectedEdges.append(featureEdges_[i]);
670  }
671  }
672 
673  return selectedEdges.shrink();
674 }
675 
676 
678 (
679  const scalar includedAngle,
680  const bool geometricTestOnly
681 )
682 {
683  scalar minCos = Foam::cos(degToRad(180.0 - includedAngle));
684 
685  // Per edge whether is feature edge.
686  List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
687 
688  classifyFeatureAngles
689  (
690  surf_.edgeFaces(),
691  edgeStat,
692  minCos,
693  geometricTestOnly
694  );
695 
696  setFromStatus(edgeStat, includedAngle);
697 }
698 
699 
700 // Remove small strings of edges. First assigns string number to
701 // every edge and then works out the length of them.
703 (
704  const scalar minLen,
705  const label minElems,
706  const scalar includedAngle
707 )
708 {
709  // Convert feature edge list to status per edge.
710  List<edgeStatus> edgeStat(toStatus());
711 
712 
713  // Mark feature edges according to connected lines.
714  // -1: unassigned
715  // -2: part of too small a feature line
716  // >0: feature line number
717  labelList featLines(surf_.nEdges(), -1);
718 
719  // Current featureline number.
720  label featI = 0;
721 
722  // Current starting edge
723  label startEdgeI = 0;
724 
725  do
726  {
727  // Find unset featureline
728  for (; startEdgeI < edgeStat.size(); startEdgeI++)
729  {
730  if
731  (
732  edgeStat[startEdgeI] != NONE
733  && featLines[startEdgeI] == -1
734  )
735  {
736  // Found unassigned feature edge.
737  break;
738  }
739  }
740 
741  if (startEdgeI == edgeStat.size())
742  {
743  // No unset feature edge found. All feature edges have line number
744  // assigned.
745  break;
746  }
747 
748  featLines[startEdgeI] = featI;
749 
750  const edge& startEdge = surf_.edges()[startEdgeI];
751 
752  // Walk 'left' and 'right' from startEdge.
753  labelScalar leftPath =
754  walkSegment
755  (
756  true, // 'mark' mode
757  edgeStat,
758  startEdgeI, // edge, not yet assigned to a featureLine
759  startEdge[0], // start of edge
760  featI, // Mark value
761  featLines // Mark for all edges
762  );
763 
764  labelScalar rightPath =
765  walkSegment
766  (
767  true,
768  edgeStat,
769  startEdgeI,
770  startEdge[1], // end of edge
771  featI,
772  featLines
773  );
774 
775  if
776  (
777  (
778  leftPath.len_
779  + rightPath.len_
780  + startEdge.mag(surf_.localPoints())
781  < minLen
782  )
783  || (leftPath.n_ + rightPath.n_ + 1 < minElems)
784  )
785  {
786  // Rewalk same route (recognizable by featLines == featI)
787  // to reset featLines.
788 
789  featLines[startEdgeI] = -2;
790 
791  walkSegment
792  (
793  false, // 'clean' mode
794  edgeStat,
795  startEdgeI, // edge, not yet assigned to a featureLine
796  startEdge[0], // start of edge
797  featI, // Unset value
798  featLines // Mark for all edges
799  );
800 
801  walkSegment
802  (
803  false,
804  edgeStat,
805  startEdgeI,
806  startEdge[1], // end of edge
807  featI,
808  featLines
809  );
810  }
811  else
812  {
813  featI++;
814  }
815  }
816  while (true);
817 
818  // Unmark all feature lines that have featLines=-2
819  forAll(featureEdges_, i)
820  {
821  label edgeI = featureEdges_[i];
822 
823  if (featLines[edgeI] == -2)
824  {
825  edgeStat[edgeI] = NONE;
826  }
827  }
828 
829  // Convert back to edge labels
830  setFromStatus(edgeStat, includedAngle);
831 
832  return featLines;
833 }
834 
835 
837 {
838 
839  dictionary featInfoDict;
840  featInfoDict.add("externalStart", externalStart_);
841  featInfoDict.add("internalStart", internalStart_);
842  featInfoDict.add("featureEdges", featureEdges_);
843  featInfoDict.add("featurePoints", featurePoints_);
844 
845  featInfoDict.write(writeFile);
846 }
847 
848 
849 void Foam::surfaceFeatures::write(const fileName& fName) const
850 {
851  OFstream str(fName);
852 
853  writeDict(str);
854 }
855 
856 
857 void Foam::surfaceFeatures::writeObj(const fileName& prefix) const
858 {
859  OFstream regionStr(prefix + "_regionEdges.obj");
860  Pout<< "Writing region edges to " << regionStr.name() << endl;
861 
862  label verti = 0;
863  for (label i = 0; i < externalStart_; i++)
864  {
865  const edge& e = surf_.edges()[featureEdges_[i]];
866 
867  meshTools::writeOBJ(regionStr, surf_.localPoints()[e[0]]); verti++;
868  meshTools::writeOBJ(regionStr, surf_.localPoints()[e[1]]); verti++;
869  regionStr << "l " << verti-1 << ' ' << verti << endl;
870  }
871 
872 
873  OFstream externalStr(prefix + "_externalEdges.obj");
874  Pout<< "Writing external edges to " << externalStr.name() << endl;
875 
876  verti = 0;
877  for (label i = externalStart_; i < internalStart_; i++)
878  {
879  const edge& e = surf_.edges()[featureEdges_[i]];
880 
881  meshTools::writeOBJ(externalStr, surf_.localPoints()[e[0]]); verti++;
882  meshTools::writeOBJ(externalStr, surf_.localPoints()[e[1]]); verti++;
883  externalStr << "l " << verti-1 << ' ' << verti << endl;
884  }
885 
886  OFstream internalStr(prefix + "_internalEdges.obj");
887  Pout<< "Writing internal edges to " << internalStr.name() << endl;
888 
889  verti = 0;
890  for (label i = internalStart_; i < featureEdges_.size(); i++)
891  {
892  const edge& e = surf_.edges()[featureEdges_[i]];
893 
894  meshTools::writeOBJ(internalStr, surf_.localPoints()[e[0]]); verti++;
895  meshTools::writeOBJ(internalStr, surf_.localPoints()[e[1]]); verti++;
896  internalStr << "l " << verti-1 << ' ' << verti << endl;
897  }
898 
899  OFstream pointStr(prefix + "_points.obj");
900  Pout<< "Writing feature points to " << pointStr.name() << endl;
901 
902  forAll(featurePoints_, i)
903  {
904  label pointI = featurePoints_[i];
905 
906  meshTools::writeOBJ(pointStr, surf_.localPoints()[pointI]);
907  }
908 }
909 
910 
911 // Get nearest vertex on patch for every point of surf in pointSet.
913 (
914  const labelList& pointLabels,
915  const pointField& samples,
916  const scalarField& maxDistSqr
917 ) const
918 {
919  // Build tree out of all samples.
920 
921  // Note: cannot be done one the fly - gcc4.4 compiler bug.
922  treeBoundBox bb(samples);
923 
925  (
926  treeDataPoint(samples), // all information needed to do checks
927  bb, // overall search domain
928  8, // maxLevel
929  10, // leafsize
930  3.0 // duplicity
931  );
932 
933  // From patch point to surface point
934  Map<label> nearest(2*pointLabels.size());
935 
936  const pointField& surfPoints = surf_.localPoints();
937 
938  forAll(pointLabels, i)
939  {
940  label surfPointI = pointLabels[i];
941 
942  const point& surfPt = surfPoints[surfPointI];
943 
944  pointIndexHit info = ppTree.findNearest
945  (
946  surfPt,
947  maxDistSqr[i]
948  );
949 
950  if (!info.hit())
951  {
952  FatalErrorIn("surfaceFeatures::nearestSamples")
953  << "Problem for point "
954  << surfPointI << " in tree " << ppTree.bb()
955  << abort(FatalError);
956  }
957 
958  label sampleI = info.index();
959 
960  if (magSqr(samples[sampleI] - surfPt) < maxDistSqr[sampleI])
961  {
962  nearest.insert(sampleI, surfPointI);
963  }
964  }
965 
966 
967  if (debug)
968  {
969  //
970  // Dump to obj file
971  //
972 
973  Pout<< endl
974  << "Dumping nearest surface feature points to nearestSamples.obj"
975  << endl
976  << "View this Lightwave-OBJ file with e.g. javaview" << endl
977  << endl;
978 
979  OFstream objStream("nearestSamples.obj");
980 
981  label vertI = 0;
982  forAllConstIter(Map<label>, nearest, iter)
983  {
984  meshTools::writeOBJ(objStream, samples[iter.key()]); vertI++;
985  meshTools::writeOBJ(objStream, surfPoints[iter()]); vertI++;
986  objStream<< "l " << vertI-1 << ' ' << vertI << endl;
987  }
988  }
989 
990  return nearest;
991 }
992 
993 
994 // Get nearest sample point for regularly sampled points along
995 // selected edges. Return map from sample to edge label
997 (
998  const labelList& selectedEdges,
999  const pointField& samples,
1000  const scalarField& sampleDist,
1001  const scalarField& maxDistSqr,
1002  const scalar minSampleDist
1003 ) const
1004 {
1005  const pointField& surfPoints = surf_.localPoints();
1006  const edgeList& surfEdges = surf_.edges();
1007 
1008  scalar maxSearchSqr = max(maxDistSqr);
1009 
1010  //Note: cannot be done one the fly - gcc4.4 compiler bug.
1011  treeBoundBox bb(samples);
1012 
1014  (
1015  treeDataPoint(samples), // all information needed to do checks
1016  bb, // overall search domain
1017  8, // maxLevel
1018  10, // leafsize
1019  3.0 // duplicity
1020  );
1021 
1022  // From patch point to surface edge.
1023  Map<label> nearest(2*selectedEdges.size());
1024 
1025  forAll(selectedEdges, i)
1026  {
1027  label surfEdgeI = selectedEdges[i];
1028 
1029  const edge& e = surfEdges[surfEdgeI];
1030 
1031  if (debug && (i % 1000) == 0)
1032  {
1033  Pout<< "looking at surface feature edge " << surfEdgeI
1034  << " verts:" << e << " points:" << surfPoints[e[0]]
1035  << ' ' << surfPoints[e[1]] << endl;
1036  }
1037 
1038  // Normalized edge vector
1039  vector eVec = e.vec(surfPoints);
1040  scalar eMag = mag(eVec);
1041  eVec /= eMag;
1042 
1043 
1044  //
1045  // Sample along edge
1046  //
1047 
1048  bool exit = false;
1049 
1050  // Coordinate along edge (0 .. eMag)
1051  scalar s = 0.0;
1052 
1053  while (true)
1054  {
1055  point edgePoint(surfPoints[e.start()] + s*eVec);
1056 
1057  pointIndexHit info = ppTree.findNearest
1058  (
1059  edgePoint,
1060  maxSearchSqr
1061  );
1062 
1063  if (!info.hit())
1064  {
1065  // No point close enough to surface edge.
1066  break;
1067  }
1068 
1069  label sampleI = info.index();
1070 
1071  if (magSqr(info.hitPoint() - edgePoint) < maxDistSqr[sampleI])
1072  {
1073  nearest.insert(sampleI, surfEdgeI);
1074  }
1075 
1076  if (exit)
1077  {
1078  break;
1079  }
1080 
1081  // Step to next sample point using local distance.
1082  // Truncate to max 1/minSampleDist samples per feature edge.
1083  s += max(minSampleDist*eMag, sampleDist[sampleI]);
1084 
1085  if (s >= (1-minSampleDist)*eMag)
1086  {
1087  // Do one more sample, at edge endpoint
1088  s = eMag;
1089  exit = true;
1090  }
1091  }
1092  }
1093 
1094 
1095 
1096  if (debug)
1097  {
1098  // Dump to obj file
1099 
1100  Pout<< "Dumping nearest surface edges to nearestEdges.obj\n"
1101  << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
1102 
1103  OFstream objStream("nearestEdges.obj");
1104 
1105  label vertI = 0;
1106  forAllConstIter(Map<label>, nearest, iter)
1107  {
1108  const label sampleI = iter.key();
1109 
1110  meshTools::writeOBJ(objStream, samples[sampleI]); vertI++;
1111 
1112  const edge& e = surfEdges[iter()];
1113 
1114  point nearPt =
1115  e.line(surfPoints).nearestDist(samples[sampleI]).rawPoint();
1116 
1117  meshTools::writeOBJ(objStream, nearPt); vertI++;
1118 
1119  objStream<< "l " << vertI-1 << ' ' << vertI << endl;
1120  }
1121  }
1122 
1123  return nearest;
1124 }
1125 
1126 
1127 // Get nearest edge on patch for regularly sampled points along the feature
1128 // edges. Return map from patch edge to feature edge.
1129 //
1130 // Q: using point-based sampleDist and maxDist (distance to look around
1131 // each point). Should they be edge-based e.g. by averaging or max()?
1134  const labelList& selectedEdges,
1135  const edgeList& sampleEdges,
1136  const labelList& selectedSampleEdges,
1137  const pointField& samplePoints,
1138  const scalarField& sampleDist,
1139  const scalarField& maxDistSqr,
1140  const scalar minSampleDist
1141 ) const
1142 {
1143  // Build tree out of selected sample edges.
1145  (
1146  treeDataEdge
1147  (
1148  false,
1149  sampleEdges,
1150  samplePoints,
1151  selectedSampleEdges
1152  ), // geometric info container for edges
1153  treeBoundBox(samplePoints), // overall search domain
1154  8, // maxLevel
1155  10, // leafsize
1156  3.0 // duplicity
1157  );
1158 
1159  const pointField& surfPoints = surf_.localPoints();
1160  const edgeList& surfEdges = surf_.edges();
1161 
1162  scalar maxSearchSqr = max(maxDistSqr);
1163 
1164  Map<pointIndexHit> nearest(2*sampleEdges.size());
1165 
1166  //
1167  // Loop over all selected edges. Sample at regular intervals. Find nearest
1168  // sampleEdges (using octree)
1169  //
1170 
1171  forAll(selectedEdges, i)
1172  {
1173  label surfEdgeI = selectedEdges[i];
1174 
1175  const edge& e = surfEdges[surfEdgeI];
1176 
1177  if (debug && (i % 1000) == 0)
1178  {
1179  Pout<< "looking at surface feature edge " << surfEdgeI
1180  << " verts:" << e << " points:" << surfPoints[e[0]]
1181  << ' ' << surfPoints[e[1]] << endl;
1182  }
1183 
1184  // Normalized edge vector
1185  vector eVec = e.vec(surfPoints);
1186  scalar eMag = mag(eVec);
1187  eVec /= eMag;
1188 
1189 
1190  //
1191  // Sample along edge
1192  //
1193 
1194  bool exit = false;
1195 
1196  // Coordinate along edge (0 .. eMag)
1197  scalar s = 0.0;
1198 
1199  while (true)
1200  {
1201  point edgePoint(surfPoints[e.start()] + s*eVec);
1202 
1203  pointIndexHit info = ppTree.findNearest
1204  (
1205  edgePoint,
1206  maxSearchSqr
1207  );
1208 
1209  if (!info.hit())
1210  {
1211  // No edge close enough to surface edge.
1212  break;
1213  }
1214 
1215  label index = info.index();
1216 
1217  label sampleEdgeI = ppTree.shapes().edgeLabels()[index];
1218 
1219  const edge& e = sampleEdges[sampleEdgeI];
1220 
1221  if (magSqr(info.hitPoint() - edgePoint) < maxDistSqr[e.start()])
1222  {
1223  nearest.insert
1224  (
1225  sampleEdgeI,
1226  pointIndexHit(true, edgePoint, surfEdgeI)
1227  );
1228  }
1229 
1230  if (exit)
1231  {
1232  break;
1233  }
1234 
1235  // Step to next sample point using local distance.
1236  // Truncate to max 1/minSampleDist samples per feature edge.
1237  // s += max(minSampleDist*eMag, sampleDist[e.start()]);
1238  s += 0.01*eMag;
1239 
1240  if (s >= (1-minSampleDist)*eMag)
1241  {
1242  // Do one more sample, at edge endpoint
1243  s = eMag;
1244  exit = true;
1245  }
1246  }
1247  }
1248 
1249 
1250  if (debug)
1251  {
1252  // Dump to obj file
1253 
1254  Pout<< "Dumping nearest surface feature edges to nearestEdges.obj\n"
1255  << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
1256 
1257  OFstream objStream("nearestEdges.obj");
1258 
1259  label vertI = 0;
1260  forAllConstIter(Map<pointIndexHit>, nearest, iter)
1261  {
1262  const label sampleEdgeI = iter.key();
1263 
1264  const edge& sampleEdge = sampleEdges[sampleEdgeI];
1265 
1266  // Write line from edgeMid to point on feature edge
1267  meshTools::writeOBJ(objStream, sampleEdge.centre(samplePoints));
1268  vertI++;
1269 
1270  meshTools::writeOBJ(objStream, iter().rawPoint());
1271  vertI++;
1272 
1273  objStream<< "l " << vertI-1 << ' ' << vertI << endl;
1274  }
1275  }
1276 
1277  return nearest;
1278 }
1279 
1280 
1281 // Get nearest surface edge for every sample. Return in form of
1282 // labelLists giving surfaceEdge label&intersectionpoint.
1285  const labelList& selectedEdges,
1286  const pointField& samples,
1287  scalar searchSpanSqr, // Search span
1288  labelList& edgeLabel,
1289  labelList& edgeEndPoint,
1290  pointField& edgePoint
1291 ) const
1292 {
1293  edgeLabel.setSize(samples.size());
1294  edgeEndPoint.setSize(samples.size());
1295  edgePoint.setSize(samples.size());
1296 
1297  const pointField& localPoints = surf_.localPoints();
1298 
1299  treeBoundBox searchDomain(localPoints);
1300  searchDomain.inflate(0.1);
1301 
1303  (
1304  treeDataEdge
1305  (
1306  false,
1307  surf_.edges(),
1308  localPoints,
1309  selectedEdges
1310  ), // all information needed to do geometric checks
1311  searchDomain, // overall search domain
1312  8, // maxLevel
1313  10, // leafsize
1314  3.0 // duplicity
1315  );
1316 
1317  forAll(samples, i)
1318  {
1319  const point& sample = samples[i];
1320 
1321  pointIndexHit info = ppTree.findNearest
1322  (
1323  sample,
1324  searchSpanSqr
1325  );
1326 
1327  if (!info.hit())
1328  {
1329  edgeLabel[i] = -1;
1330  }
1331  else
1332  {
1333  edgeLabel[i] = selectedEdges[info.index()];
1334 
1335  // Need to recalculate to classify edgeEndPoint
1336  const edge& e = surf_.edges()[edgeLabel[i]];
1337 
1338  pointIndexHit pHit = edgeNearest
1339  (
1340  localPoints[e.start()],
1341  localPoints[e.end()],
1342  sample
1343  );
1344 
1345  edgePoint[i] = pHit.rawPoint();
1346  edgeEndPoint[i] = pHit.index();
1347  }
1348  }
1349 }
1350 
1351 
1352 // Get nearest point on nearest feature edge for every sample (is edge)
1355  const labelList& selectedEdges,
1356 
1357  const edgeList& sampleEdges,
1358  const labelList& selectedSampleEdges,
1359  const pointField& samplePoints,
1360 
1361  const vector& searchSpan, // Search span
1362  labelList& edgeLabel, // label of surface edge or -1
1363  pointField& pointOnEdge, // point on above edge
1364  pointField& pointOnFeature // point on sample edge
1365 ) const
1366 {
1367  edgeLabel.setSize(selectedSampleEdges.size());
1368  pointOnEdge.setSize(selectedSampleEdges.size());
1369  pointOnFeature.setSize(selectedSampleEdges.size());
1370 
1371  treeBoundBox searchDomain(surf_.localPoints());
1372 
1374  (
1375  treeDataEdge
1376  (
1377  false,
1378  surf_.edges(),
1379  surf_.localPoints(),
1380  selectedEdges
1381  ), // all information needed to do geometric checks
1382  searchDomain, // overall search domain
1383  8, // maxLevel
1384  10, // leafsize
1385  3.0 // duplicity
1386  );
1387 
1388  forAll(selectedSampleEdges, i)
1389  {
1390  const edge& e = sampleEdges[selectedSampleEdges[i]];
1391 
1392  linePointRef edgeLine = e.line(samplePoints);
1393 
1394  point eMid(edgeLine.centre());
1395 
1396  treeBoundBox tightest(eMid - searchSpan, eMid + searchSpan);
1397 
1398  pointIndexHit info = ppTree.findNearest
1399  (
1400  edgeLine,
1401  tightest,
1402  pointOnEdge[i]
1403  );
1404 
1405  if (!info.hit())
1406  {
1407  edgeLabel[i] = -1;
1408  }
1409  else
1410  {
1411  edgeLabel[i] = selectedEdges[info.index()];
1412 
1413  pointOnFeature[i] = info.hitPoint();
1414  }
1415  }
1416 }
1417 
1418 
1421  const edgeList& edges,
1422  const pointField& points,
1423  scalar searchSpanSqr, // Search span
1424  labelList& edgeLabel
1425 ) const
1426 {
1427  edgeLabel = labelList(surf_.nEdges(), -1);
1428 
1429  treeBoundBox searchDomain(points);
1430  searchDomain.inflate(0.1);
1431 
1433  (
1434  treeDataEdge
1435  (
1436  false,
1437  edges,
1438  points,
1439  identity(edges.size())
1440  ), // all information needed to do geometric checks
1441  searchDomain, // overall search domain
1442  8, // maxLevel
1443  10, // leafsize
1444  3.0 // duplicity
1445  );
1446 
1447  const edgeList& surfEdges = surf_.edges();
1448  const pointField& surfLocalPoints = surf_.localPoints();
1449 
1450  forAll(surfEdges, edgeI)
1451  {
1452  const edge& sample = surfEdges[edgeI];
1453 
1454  const point& startPoint = surfLocalPoints[sample.start()];
1455  const point& midPoint = sample.centre(surfLocalPoints);
1456 
1457  pointIndexHit infoMid = ppTree.findNearest
1458  (
1459  midPoint,
1460  searchSpanSqr
1461  );
1462 
1463  if (infoMid.hit())
1464  {
1465  const vector surfEdgeDir = midPoint - startPoint;
1466 
1467  const edge& featEdge = edges[infoMid.index()];
1468  const vector featEdgeDir = featEdge.vec(points);
1469 
1470  // Check that the edges are nearly parallel
1471  if (mag(surfEdgeDir ^ featEdgeDir) < parallelTolerance)
1472  {
1473  edgeLabel[edgeI] = edgeI;
1474  }
1475  }
1476  }
1477 }
1478 
1479 
1480 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1481 
1483 {
1484  // Check for assignment to self
1485  if (this == &rhs)
1486  {
1487  FatalErrorIn
1488  (
1489  "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1490  ) << "Attempted assignment to self"
1491  << abort(FatalError);
1492  }
1493 
1494  if (&surf_ != &rhs.surface())
1495  {
1496  FatalErrorIn
1497  (
1498  "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1499  ) << "Operating on different surfaces"
1500  << abort(FatalError);
1501  }
1502 
1503  featurePoints_ = rhs.featurePoints();
1504  featureEdges_ = rhs.featureEdges();
1505  externalStart_ = rhs.externalStart();
1506  internalStart_ = rhs.internalStart();
1507 }
1508 
1509 
1510 // ************************************************************************* //
Output to file stream.
Definition: OFstream.H:81
PointHit< Point > nearestDist(const Point &p) const
Return nearest distance to line from a given point.
Definition: lineI.H:95
void setCapacity(const label)
Alter the size of the underlying storage.
Definition: DynamicListI.H:109
void write(const fileName &fName) const
Write as dictionary to file.
const labelList & featureEdges() const
Return feature edge list.
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
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject( name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE ))
const labelList & featurePoints() const
Return feature point list.
dimensioned< scalar > mag(const dimensioned< Type > &)
void nearestFeatEdge(const edgeList &edges, const pointField &points, scalar searchSpanSqr, labelList &edgeLabel) const
Find nearest feature edge to each surface edge. Uses the.
labelList selectFeatureEdges(const bool regionEdges, const bool externalEdges, const bool internalEdges) const
Helper function: select a subset of featureEdges_.
const labelListList & edgeFaces() const
Return edge-face addressing.
label externalStart() const
Start of external edges.
dimensioned< scalar > magSqr(const dimensioned< Type > &)
bool insert(const edge &, const T &newElmt)
Insert a new hashedEntry.
const Type & shapes() const
Reference to shape.
const Point & rawPoint() const
Return point with no checking.
T & last()
Return the last element of the list.
Definition: UListI.H:131
A HashTable to objects of type <T> with a label key.
Definition: Map.H:49
const treeBoundBox & bb() const
Top bounding box.
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
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:75
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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
surfaceFeatures(const triSurface &)
Construct from surface.
Map< pointIndexHit > nearestEdges(const labelList &selectedEdges, const edgeList &sampleEdges, const labelList &selectedSampleEdges, const pointField &samplePoints, const scalarField &sampleDist, const scalarField &maxDistSqr, const scalar minSampleDist=0.1) const
Like nearestSamples but now gets nearest point on.
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
bool hit() const
Is there a hit.
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
Input from file stream.
Definition: IFstream.H:81
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
Holds feature edges/points of surface.
label index() const
Return index.
volScalarField sf(fieldObject, mesh)
Namespace for OpenFOAM.
PointHit< point > pointHit
Definition: pointHit.H:41
label readLabel(Istream &is)
Definition: label.H:64
A line primitive.
Definition: line.H:56
const Point & hitPoint() const
Return hit point.
messageStream Warning
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
const Field< PointType > & localPoints() const
Return pointField of points in patch.
Map< label > nearestSamples(const labelList &selectedPoints, const pointField &samples, const scalarField &maxDistSqr) const
Find nearest sample for selected surface points.
void clear()
Clear the list, i.e. set size to zero.
Definition: List.C:379
static const char nl
Definition: Ostream.H:260
const double e
Elementary charge.
Definition: doubleFloat.H:78
void setSize(const label)
Reset size of List.
Definition: List.C:318
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
linePointRef line(const pointField &) const
Return edge line.
Definition: edgeI.H:169
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Mid-point interpolation (weighting factors = 0.5) scheme class.
Definition: midPoint.H:50
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:118
#define forAll(list, i)
Definition: UList.H:421
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
labelList trimFeatures(const scalar minLen, const label minElems, const scalar includedAngle)
Delete small sets of edges. Edges are stringed up and any.
dimensionedScalar cos(const dimensionedScalar &ds)
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
label otherVertex(const label a) const
Given one vertex, return the other.
Definition: edgeI.H:103
void nearestSurfEdge(const labelList &selectedEdges, const pointField &samples, scalar searchSpanSqr, labelList &edgeLabel, labelList &edgeEndPoint, pointField &edgePoint) const
Find nearest surface edge (out of selectedEdges) for.
Unit conversion functions.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
void findFeatures(const scalar includedAngle, const bool geometricTestOnly)
Find feature edges using provided included angle.
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:739
vector vec(const pointField &) const
Return the vector (end - start)
Definition: edgeI.H:157
label nRegionEdges() const
Return number of region edges.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
void writeDict(Ostream &) const
Write as dictionary.
const triSurface & surface() const
const Vector< Cmpt > & centre(const Foam::List< Vector< Cmpt > > &) const
Return *this (used for point which is a typedef to Vector<scalar>.
Definition: VectorI.H:106
List< edgeStatus > toStatus() const
From member feature edges to status per edge.
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
Non-pointer based hierarchical recursive searching.
Definition: treeDataEdge.H:47
Holds data for octree to work on an edges subset.
Definition: treeDataEdge.H:53
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:452
error FatalError
label end() const
Return end vertex label.
Definition: edgeI.H:92
List< label > labelList
A List of labels.
Definition: labelList.H:56
A class for handling file names.
Definition: fileName.H:69
label nExternalEdges() const
Return number of external edges.
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
Point centre() const
Return centre (centroid)
Definition: lineI.H:73
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:106
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:97
label start() const
Return start vertex label.
Definition: edgeI.H:81
line< point, const point & > linePointRef
Line using referred points.
Definition: linePointRef.H:45
void writeObj(const fileName &prefix) const
Write to separate OBJ files (region, external, internal edges,.
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:210
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:139
label nInternalEdges() const
Return number of internal edges.
void write(Ostream &, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:173
dimensionedSymmTensor sqr(const dimensionedVector &dv)
void setFromStatus(const List< edgeStatus > &edgeStat, const scalar includedAngle)
Set from status per edge.
label nEdges() const
Return number of edges in patch.
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:209
Holds (reference to) pointField. Encapsulation of data needed for octree searches. Used for searching for nearest point. No bounding boxes around points. Only overlaps and calcNearest are implemented, rest makes little sense.
Definition: treeDataPoint.H:59
void operator=(const surfaceFeatures &)
defineTypeNameAndDebug(combustionModel, 0)
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
label internalStart() const
Start of internal edges.
point centre(const pointField &) const
Return centre (centroid)
Definition: edgeI.H:151
dimensionedScalar sin(const dimensionedScalar &ds)