1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
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"
35 #include "unitConversion.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 defineTypeNameAndDebug(Foam::surfaceFeatures, 0);
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 //- Get nearest point on edge and classify position on edge.
45 Foam::pointIndexHit Foam::surfaceFeatures::edgeNearest
52 pointHit eHit = linePointRef(start, end).nearestDist(sample);
54 // Classification of position on edge.
59 // Nearest point is on edge itself.
60 // Note: might be at or very close to endpoint. We should use tolerance
66 // Nearest point has to be one of the end points. Find out
70 mag(eHit.rawPoint() - start)
71 < mag(eHit.rawPoint() - end)
82 return pointIndexHit(eHit.hit(), eHit.rawPoint(), endPoint);
86 // Go from selected edges only to a value for every edge
87 Foam::List<Foam::surfaceFeatures::edgeStatus> Foam::surfaceFeatures::toStatus()
90 List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
93 for (label i = 0; i < externalStart_; i++)
95 edgeStat[featureEdges_[i]] = REGION;
99 for (label i = externalStart_; i < internalStart_; i++)
101 edgeStat[featureEdges_[i]] = EXTERNAL;
105 for (label i = internalStart_; i < featureEdges_.size(); i++)
107 edgeStat[featureEdges_[i]] = INTERNAL;
114 // Set from value for every edge
115 void Foam::surfaceFeatures::setFromStatus(const List<edgeStatus>& edgeStat)
123 forAll(edgeStat, edgeI)
125 if (edgeStat[edgeI] == REGION)
129 else if (edgeStat[edgeI] == EXTERNAL)
133 else if (edgeStat[edgeI] == INTERNAL)
139 externalStart_ = nRegion;
140 internalStart_ = externalStart_ + nExternal;
145 featureEdges_.setSize(internalStart_ + nInternal);
148 label externalI = externalStart_;
149 label internalI = internalStart_;
151 forAll(edgeStat, edgeI)
153 if (edgeStat[edgeI] == REGION)
155 featureEdges_[regionI++] = edgeI;
157 else if (edgeStat[edgeI] == EXTERNAL)
159 featureEdges_[externalI++] = edgeI;
161 else if (edgeStat[edgeI] == INTERNAL)
163 featureEdges_[internalI++] = edgeI;
167 // Calculate consistent feature points
168 calcFeatPoints(edgeStat);
172 //construct feature points where more than 2 feature edges meet
173 void Foam::surfaceFeatures::calcFeatPoints(const List<edgeStatus>& edgeStat)
175 DynamicList<label> featurePoints(surf_.nPoints()/1000);
177 const labelListList& pointEdges = surf_.pointEdges();
179 forAll(pointEdges, pointI)
181 const labelList& pEdges = pointEdges[pointI];
183 label nFeatEdges = 0;
187 if (edgeStat[pEdges[i]] != NONE)
195 featurePoints.append(pointI);
199 featurePoints_.transfer(featurePoints);
203 // Returns next feature edge connected to pointI with correct value.
204 Foam::label Foam::surfaceFeatures::nextFeatEdge
206 const List<edgeStatus>& edgeStat,
207 const labelList& featVisited,
208 const label unsetVal,
209 const label prevEdgeI,
213 const labelList& pEdges = surf_.pointEdges()[vertI];
215 label nextEdgeI = -1;
219 label edgeI = pEdges[i];
224 && edgeStat[edgeI] != NONE
225 && featVisited[edgeI] == unsetVal
234 // More than one feature edge to choose from. End of segment.
244 // Finds connected feature edges by walking from prevEdgeI in direction of
245 // prevPointI. Marks feature edges visited in featVisited by assigning them
246 // the current feature line number. Returns cumulative length of edges walked.
247 // Works in one of two modes:
248 // - mark : step to edges with featVisited = -1.
249 // Mark edges visited with currentFeatI.
250 // - clear : step to edges with featVisited = currentFeatI
251 // Mark edges visited with -2 and erase from feature edges.
252 Foam::surfaceFeatures::labelScalar Foam::surfaceFeatures::walkSegment
255 const List<edgeStatus>& edgeStat,
256 const label startEdgeI,
257 const label startPointI,
258 const label currentFeatI,
259 labelList& featVisited
262 label edgeI = startEdgeI;
264 label vertI = startPointI;
266 scalar visitedLength = 0.0;
270 if (findIndex(featurePoints_, startPointI) >= 0)
272 // Do not walk across feature points
274 return labelScalar(nVisited, visitedLength);
279 // edgeI : first edge on this segment
280 // vertI : one of the endpoints of this segment
282 // Start walking, marking off edges (in featVisited)
294 unsetVal = currentFeatI;
299 // Step to next feature edge with value unsetVal
300 edgeI = nextFeatEdge(edgeStat, featVisited, unsetVal, edgeI, vertI);
302 if (edgeI == -1 || edgeI == startEdgeI)
307 // Mark with current value. If in clean mode also remove feature edge.
311 featVisited[edgeI] = currentFeatI;
315 featVisited[edgeI] = -2;
319 // Step to next vertex on edge
320 const edge& e = surf_.edges()[edgeI];
322 vertI = e.otherVertex(vertI);
325 // Update cumulative length
326 visitedLength += e.mag(surf_.localPoints());
330 if (nVisited > surf_.nEdges())
332 Warning<< "walkSegment : reached iteration limit in walking "
333 << "feature edges on surface from edge:" << startEdgeI
334 << " vertex:" << startPointI << nl
335 << "Returning with large length" << endl;
337 return labelScalar(nVisited, GREAT);
342 return labelScalar(nVisited, visitedLength);
346 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
348 Foam::surfaceFeatures::surfaceFeatures(const triSurface& surf)
358 // Construct from components.
359 Foam::surfaceFeatures::surfaceFeatures
361 const triSurface& surf,
362 const labelList& featurePoints,
363 const labelList& featureEdges,
364 const label externalStart,
365 const label internalStart
369 featurePoints_(featurePoints),
370 featureEdges_(featureEdges),
371 externalStart_(externalStart),
372 internalStart_(externalStart)
376 // Construct from surface, angle and min length
377 Foam::surfaceFeatures::surfaceFeatures
379 const triSurface& surf,
380 const scalar includedAngle,
391 findFeatures(includedAngle);
393 if (minLen > 0 || minElems > 0)
395 trimFeatures(minLen, minElems);
400 //- Construct from dictionary
401 Foam::surfaceFeatures::surfaceFeatures
403 const triSurface& surf,
404 const dictionary& featInfoDict
408 featurePoints_(featInfoDict.lookup("featurePoints")),
409 featureEdges_(featInfoDict.lookup("featureEdges")),
410 externalStart_(readLabel(featInfoDict.lookup("externalStart"))),
411 internalStart_(readLabel(featInfoDict.lookup("internalStart")))
415 //- Construct from file
416 Foam::surfaceFeatures::surfaceFeatures
418 const triSurface& surf,
419 const fileName& fName
430 dictionary featInfoDict(str);
432 featureEdges_ = labelList(featInfoDict.lookup("featureEdges"));
433 featurePoints_ = labelList(featInfoDict.lookup("featurePoints"));
434 externalStart_ = readLabel(featInfoDict.lookup("externalStart"));
435 internalStart_ = readLabel(featInfoDict.lookup("internalStart"));
439 //- Construct as copy
440 Foam::surfaceFeatures::surfaceFeatures(const surfaceFeatures& sf)
443 featurePoints_(sf.featurePoints()),
444 featureEdges_(sf.featureEdges()),
445 externalStart_(sf.externalStart()),
446 internalStart_(sf.internalStart())
450 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
452 Foam::labelList Foam::surfaceFeatures::selectFeatureEdges
454 const bool regionEdges,
455 const bool externalEdges,
456 const bool internalEdges
459 DynamicList<label> selectedEdges;
463 selectedEdges.setCapacity(selectedEdges.size() + nRegionEdges());
465 for (label i = 0; i < externalStart_; i++)
467 selectedEdges.append(featureEdges_[i]);
473 selectedEdges.setCapacity(selectedEdges.size() + nExternalEdges());
475 for (label i = externalStart_; i < internalStart_; i++)
477 selectedEdges.append(featureEdges_[i]);
483 selectedEdges.setCapacity(selectedEdges.size() + nInternalEdges());
485 for (label i = internalStart_; i < featureEdges_.size(); i++)
487 selectedEdges.append(featureEdges_[i]);
491 return selectedEdges.shrink();
495 void Foam::surfaceFeatures::findFeatures(const scalar includedAngle)
497 scalar minCos = Foam::cos(degToRad(180.0 - includedAngle));
499 const labelListList& edgeFaces = surf_.edgeFaces();
500 const vectorField& faceNormals = surf_.faceNormals();
501 const pointField& points = surf_.points();
503 // Per edge whether is feature edge.
504 List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
506 forAll(edgeFaces, edgeI)
508 const labelList& eFaces = edgeFaces[edgeI];
510 if (eFaces.size() != 2)
512 // Non-manifold. What to do here? Is region edge? external edge?
513 edgeStat[edgeI] = REGION;
517 label face0 = eFaces[0];
518 label face1 = eFaces[1];
520 if (surf_[face0].region() != surf_[face1].region())
522 edgeStat[edgeI] = REGION;
526 if ((faceNormals[face0] & faceNormals[face1]) < minCos)
529 // Check if convex or concave by looking at angle
530 // between face centres and normal
532 surf_[face1].centre(points)
533 - surf_[face0].centre(points);
535 if ((f0Tof1 & faceNormals[face0]) > 0.0)
537 edgeStat[edgeI] = INTERNAL;
541 edgeStat[edgeI] = EXTERNAL;
548 setFromStatus(edgeStat);
552 // Remove small strings of edges. First assigns string number to
553 // every edge and then works out the length of them.
554 void Foam::surfaceFeatures::trimFeatures
560 // Convert feature edge list to status per edge.
561 List<edgeStatus> edgeStat(toStatus());
564 // Mark feature edges according to connected lines.
566 // -2: part of too small a feature line
567 // >0: feature line number
568 labelList featLines(surf_.nEdges(), -1);
570 // Current featureline number.
573 // Current starting edge
574 label startEdgeI = 0;
578 // Find unset featureline
579 for (; startEdgeI < edgeStat.size(); startEdgeI++)
583 edgeStat[startEdgeI] != NONE
584 && featLines[startEdgeI] == -1
587 // Found unassigned feature edge.
592 if (startEdgeI == edgeStat.size())
594 // No unset feature edge found. All feature edges have line number
599 featLines[startEdgeI] = featI;
601 const edge& startEdge = surf_.edges()[startEdgeI];
603 // Walk 'left' and 'right' from startEdge.
604 labelScalar leftPath =
609 startEdgeI, // edge, not yet assigned to a featureLine
610 startEdge[0], // start of edge
612 featLines // Mark for all edges
615 labelScalar rightPath =
621 startEdge[1], // end of edge
631 + startEdge.mag(surf_.localPoints())
634 || (leftPath.n_ + rightPath.n_ + 1 < minElems)
637 // Rewalk same route (recognizable by featLines == featI)
638 // to reset featLines.
640 featLines[startEdgeI] = -2;
644 false, // 'clean' mode
646 startEdgeI, // edge, not yet assigned to a featureLine
647 startEdge[0], // start of edge
648 featI, // Unset value
649 featLines // Mark for all edges
657 startEdge[1], // end of edge
669 // Unmark all feature lines that have featLines=-2
670 forAll(featureEdges_, i)
672 label edgeI = featureEdges_[i];
674 if (featLines[edgeI] == -2)
676 edgeStat[edgeI] = NONE;
680 // Convert back to edge labels
681 setFromStatus(edgeStat);
685 void Foam::surfaceFeatures::writeDict(Ostream& writeFile) const
688 dictionary featInfoDict;
689 featInfoDict.add("externalStart", externalStart_);
690 featInfoDict.add("internalStart", internalStart_);
691 featInfoDict.add("featureEdges", featureEdges_);
692 featInfoDict.add("featurePoints", featurePoints_);
694 featInfoDict.write(writeFile);
698 void Foam::surfaceFeatures::write(const fileName& fName) const
706 void Foam::surfaceFeatures::writeObj(const fileName& prefix) const
708 OFstream regionStr(prefix + "_regionEdges.obj");
709 Pout<< "Writing region edges to " << regionStr.name() << endl;
712 for (label i = 0; i < externalStart_; i++)
714 const edge& e = surf_.edges()[featureEdges_[i]];
716 meshTools::writeOBJ(regionStr, surf_.localPoints()[e[0]]); verti++;
717 meshTools::writeOBJ(regionStr, surf_.localPoints()[e[1]]); verti++;
718 regionStr << "l " << verti-1 << ' ' << verti << endl;
722 OFstream externalStr(prefix + "_externalEdges.obj");
723 Pout<< "Writing external edges to " << externalStr.name() << endl;
726 for (label i = externalStart_; i < internalStart_; i++)
728 const edge& e = surf_.edges()[featureEdges_[i]];
730 meshTools::writeOBJ(externalStr, surf_.localPoints()[e[0]]); verti++;
731 meshTools::writeOBJ(externalStr, surf_.localPoints()[e[1]]); verti++;
732 externalStr << "l " << verti-1 << ' ' << verti << endl;
735 OFstream internalStr(prefix + "_internalEdges.obj");
736 Pout<< "Writing internal edges to " << internalStr.name() << endl;
739 for (label i = internalStart_; i < featureEdges_.size(); i++)
741 const edge& e = surf_.edges()[featureEdges_[i]];
743 meshTools::writeOBJ(internalStr, surf_.localPoints()[e[0]]); verti++;
744 meshTools::writeOBJ(internalStr, surf_.localPoints()[e[1]]); verti++;
745 internalStr << "l " << verti-1 << ' ' << verti << endl;
748 OFstream pointStr(prefix + "_points.obj");
749 Pout<< "Writing feature points to " << pointStr.name() << endl;
751 forAll(featurePoints_, i)
753 label pointI = featurePoints_[i];
755 meshTools::writeOBJ(pointStr, surf_.localPoints()[pointI]);
760 // Get nearest vertex on patch for every point of surf in pointSet.
761 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
763 const labelList& pointLabels,
764 const pointField& samples,
765 const scalarField& maxDistSqr
768 // Build tree out of all samples.
770 // Note: cannot be done one the fly - gcc4.4 compiler bug.
771 treeBoundBox bb(samples);
773 indexedOctree<treeDataPoint> ppTree
775 treeDataPoint(samples), // all information needed to do checks
776 bb, // overall search domain
782 // From patch point to surface point
783 Map<label> nearest(2*pointLabels.size());
785 const pointField& surfPoints = surf_.localPoints();
787 forAll(pointLabels, i)
789 label surfPointI = pointLabels[i];
791 const point& surfPt = surfPoints[surfPointI];
793 pointIndexHit info = ppTree.findNearest
801 FatalErrorIn("surfaceFeatures::nearestSamples")
802 << "Problem for point "
803 << surfPointI << " in tree " << ppTree.bb()
804 << abort(FatalError);
807 label sampleI = info.index();
809 if (magSqr(samples[sampleI] - surfPt) < maxDistSqr[sampleI])
811 nearest.insert(sampleI, surfPointI);
823 << "Dumping nearest surface feature points to nearestSamples.obj"
825 << "View this Lightwave-OBJ file with e.g. javaview" << endl
828 OFstream objStream("nearestSamples.obj");
831 forAllConstIter(Map<label>, nearest, iter)
833 meshTools::writeOBJ(objStream, samples[iter.key()]); vertI++;
834 meshTools::writeOBJ(objStream, surfPoints[iter()]); vertI++;
835 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
843 // Get nearest sample point for regularly sampled points along
844 // selected edges. Return map from sample to edge label
845 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
847 const labelList& selectedEdges,
848 const pointField& samples,
849 const scalarField& sampleDist,
850 const scalarField& maxDistSqr,
851 const scalar minSampleDist
854 const pointField& surfPoints = surf_.localPoints();
855 const edgeList& surfEdges = surf_.edges();
857 scalar maxSearchSqr = max(maxDistSqr);
859 //Note: cannot be done one the fly - gcc4.4 compiler bug.
860 treeBoundBox bb(samples);
862 indexedOctree<treeDataPoint> ppTree
864 treeDataPoint(samples), // all information needed to do checks
865 bb, // overall search domain
871 // From patch point to surface edge.
872 Map<label> nearest(2*selectedEdges.size());
874 forAll(selectedEdges, i)
876 label surfEdgeI = selectedEdges[i];
878 const edge& e = surfEdges[surfEdgeI];
880 if (debug && (i % 1000) == 0)
882 Pout<< "looking at surface feature edge " << surfEdgeI
883 << " verts:" << e << " points:" << surfPoints[e[0]]
884 << ' ' << surfPoints[e[1]] << endl;
887 // Normalized edge vector
888 vector eVec = e.vec(surfPoints);
889 scalar eMag = mag(eVec);
899 // Coordinate along edge (0 .. eMag)
904 point edgePoint(surfPoints[e.start()] + s*eVec);
906 pointIndexHit info = ppTree.findNearest
914 // No point close enough to surface edge.
918 label sampleI = info.index();
920 if (magSqr(info.hitPoint() - edgePoint) < maxDistSqr[sampleI])
922 nearest.insert(sampleI, surfEdgeI);
930 // Step to next sample point using local distance.
931 // Truncate to max 1/minSampleDist samples per feature edge.
932 s += max(minSampleDist*eMag, sampleDist[sampleI]);
934 if (s >= (1-minSampleDist)*eMag)
936 // Do one more sample, at edge endpoint
949 Pout<< "Dumping nearest surface edges to nearestEdges.obj\n"
950 << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
952 OFstream objStream("nearestEdges.obj");
955 forAllConstIter(Map<label>, nearest, iter)
957 const label sampleI = iter.key();
959 meshTools::writeOBJ(objStream, samples[sampleI]); vertI++;
961 const edge& e = surfEdges[iter()];
964 e.line(surfPoints).nearestDist(samples[sampleI]).rawPoint();
966 meshTools::writeOBJ(objStream, nearPt); vertI++;
968 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
976 // Get nearest edge on patch for regularly sampled points along the feature
977 // edges. Return map from patch edge to feature edge.
979 // Q: using point-based sampleDist and maxDist (distance to look around
980 // each point). Should they be edge-based e.g. by averaging or max()?
981 Foam::Map<Foam::pointIndexHit> Foam::surfaceFeatures::nearestEdges
983 const labelList& selectedEdges,
984 const edgeList& sampleEdges,
985 const labelList& selectedSampleEdges,
986 const pointField& samplePoints,
987 const scalarField& sampleDist,
988 const scalarField& maxDistSqr,
989 const scalar minSampleDist
992 // Build tree out of selected sample edges.
993 indexedOctree<treeDataEdge> ppTree
1001 ), // geometric info container for edges
1002 treeBoundBox(samplePoints), // overall search domain
1008 const pointField& surfPoints = surf_.localPoints();
1009 const edgeList& surfEdges = surf_.edges();
1011 scalar maxSearchSqr = max(maxDistSqr);
1013 Map<pointIndexHit> nearest(2*sampleEdges.size());
1016 // Loop over all selected edges. Sample at regular intervals. Find nearest
1017 // sampleEdges (using octree)
1020 forAll(selectedEdges, i)
1022 label surfEdgeI = selectedEdges[i];
1024 const edge& e = surfEdges[surfEdgeI];
1026 if (debug && (i % 1000) == 0)
1028 Pout<< "looking at surface feature edge " << surfEdgeI
1029 << " verts:" << e << " points:" << surfPoints[e[0]]
1030 << ' ' << surfPoints[e[1]] << endl;
1033 // Normalized edge vector
1034 vector eVec = e.vec(surfPoints);
1035 scalar eMag = mag(eVec);
1040 // Sample along edge
1045 // Coordinate along edge (0 .. eMag)
1050 point edgePoint(surfPoints[e.start()] + s*eVec);
1052 pointIndexHit info = ppTree.findNearest
1060 // No edge close enough to surface edge.
1064 label index = info.index();
1066 label sampleEdgeI = ppTree.shapes().edgeLabels()[index];
1068 const edge& e = sampleEdges[sampleEdgeI];
1070 if (magSqr(info.hitPoint() - edgePoint) < maxDistSqr[e.start()])
1075 pointIndexHit(true, edgePoint, surfEdgeI)
1084 // Step to next sample point using local distance.
1085 // Truncate to max 1/minSampleDist samples per feature edge.
1086 // s += max(minSampleDist*eMag, sampleDist[e.start()]);
1089 if (s >= (1-minSampleDist)*eMag)
1091 // Do one more sample, at edge endpoint
1103 Pout<< "Dumping nearest surface feature edges to nearestEdges.obj\n"
1104 << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
1106 OFstream objStream("nearestEdges.obj");
1109 forAllConstIter(Map<pointIndexHit>, nearest, iter)
1111 const label sampleEdgeI = iter.key();
1113 const edge& sampleEdge = sampleEdges[sampleEdgeI];
1115 // Write line from edgeMid to point on feature edge
1116 meshTools::writeOBJ(objStream, sampleEdge.centre(samplePoints));
1119 meshTools::writeOBJ(objStream, iter().rawPoint());
1122 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
1130 // Get nearest surface edge for every sample. Return in form of
1131 // labelLists giving surfaceEdge label&intersectionpoint.
1132 void Foam::surfaceFeatures::nearestSurfEdge
1134 const labelList& selectedEdges,
1135 const pointField& samples,
1136 scalar searchSpanSqr, // Search span
1137 labelList& edgeLabel,
1138 labelList& edgeEndPoint,
1139 pointField& edgePoint
1142 edgeLabel.setSize(samples.size());
1143 edgeEndPoint.setSize(samples.size());
1144 edgePoint.setSize(samples.size());
1146 const pointField& localPoints = surf_.localPoints();
1148 indexedOctree<treeDataEdge> ppTree
1156 ), // all information needed to do geometric checks
1157 treeBoundBox(localPoints), // overall search domain
1165 const point& sample = samples[i];
1167 pointIndexHit info = ppTree.findNearest
1179 edgeLabel[i] = selectedEdges[info.index()];
1181 // Need to recalculate to classify edgeEndPoint
1182 const edge& e = surf_.edges()[edgeLabel[i]];
1184 pointIndexHit pHit = edgeNearest
1186 localPoints[e.start()],
1187 localPoints[e.end()],
1191 edgePoint[i] = pHit.rawPoint();
1192 edgeEndPoint[i] = pHit.index();
1198 // Get nearest point on nearest feature edge for every sample (is edge)
1199 void Foam::surfaceFeatures::nearestSurfEdge
1201 const labelList& selectedEdges,
1203 const edgeList& sampleEdges,
1204 const labelList& selectedSampleEdges,
1205 const pointField& samplePoints,
1207 const vector& searchSpan, // Search span
1208 labelList& edgeLabel, // label of surface edge or -1
1209 pointField& pointOnEdge, // point on above edge
1210 pointField& pointOnFeature // point on sample edge
1213 edgeLabel.setSize(selectedSampleEdges.size());
1214 pointOnEdge.setSize(selectedSampleEdges.size());
1215 pointOnFeature.setSize(selectedSampleEdges.size());
1217 indexedOctree<treeDataEdge> ppTree
1223 surf_.localPoints(),
1225 ), // all information needed to do geometric checks
1226 treeBoundBox(surf_.localPoints()), // overall search domain
1232 forAll(selectedSampleEdges, i)
1234 const edge& e = sampleEdges[selectedSampleEdges[i]];
1236 linePointRef edgeLine = e.line(samplePoints);
1238 point eMid(edgeLine.centre());
1240 treeBoundBox tightest(eMid - searchSpan, eMid + searchSpan);
1242 pointIndexHit info = ppTree.findNearest
1255 edgeLabel[i] = selectedEdges[info.index()];
1257 pointOnFeature[i] = info.hitPoint();
1263 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1265 void Foam::surfaceFeatures::operator=(const surfaceFeatures& rhs)
1267 // Check for assignment to self
1272 "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1273 ) << "Attempted assignment to self"
1274 << abort(FatalError);
1277 if (&surf_ != &rhs.surface())
1281 "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1282 ) << "Operating on different surfaces"
1283 << abort(FatalError);
1286 featurePoints_ = rhs.featurePoints();
1287 featureEdges_ = rhs.featureEdges();
1288 externalStart_ = rhs.externalStart();
1289 internalStart_ = rhs.internalStart();
1293 // ************************************************************************* //