1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 \*---------------------------------------------------------------------------*/
29 #include "surfaceFeatures.H"
30 #include "triSurface.H"
32 #include "octreeDataEdges.H"
33 #include "octreeDataPoint.H"
34 #include "meshTools.H"
35 #include "linePointRef.H"
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(Foam::surfaceFeatures, 0);
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 //- Get nearest point on edge and classify position on edge.
47 Foam::pointIndexHit Foam::surfaceFeatures::edgeNearest
54 pointHit eHit = linePointRef(start, end).nearestDist(sample);
56 // Classification of position on edge.
61 // Nearest point is on edge itself.
62 // Note: might be at or very close to endpoint. We should use tolerance
68 // Nearest point has to be one of the end points. Find out
72 mag(eHit.rawPoint() - start)
73 < mag(eHit.rawPoint() - end)
84 return pointIndexHit(eHit.hit(), eHit.rawPoint(), endPoint);
88 // Go from selected edges only to a value for every edge
89 Foam::List<Foam::surfaceFeatures::edgeStatus> Foam::surfaceFeatures::toStatus()
92 List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
95 for (label i = 0; i < externalStart_; i++)
97 edgeStat[featureEdges_[i]] = REGION;
101 for (label i = externalStart_; i < internalStart_; i++)
103 edgeStat[featureEdges_[i]] = EXTERNAL;
107 for (label i = internalStart_; i < featureEdges_.size(); i++)
109 edgeStat[featureEdges_[i]] = INTERNAL;
116 // Set from value for every edge
117 void Foam::surfaceFeatures::setFromStatus(const List<edgeStatus>& edgeStat)
125 forAll(edgeStat, edgeI)
127 if (edgeStat[edgeI] == REGION)
131 else if (edgeStat[edgeI] == EXTERNAL)
135 else if (edgeStat[edgeI] == INTERNAL)
141 externalStart_ = nRegion;
142 internalStart_ = externalStart_ + nExternal;
147 featureEdges_.setSize(internalStart_ + nInternal);
150 label externalI = externalStart_;
151 label internalI = internalStart_;
153 forAll(edgeStat, edgeI)
155 if (edgeStat[edgeI] == REGION)
157 featureEdges_[regionI++] = edgeI;
159 else if (edgeStat[edgeI] == EXTERNAL)
161 featureEdges_[externalI++] = edgeI;
163 else if (edgeStat[edgeI] == INTERNAL)
165 featureEdges_[internalI++] = edgeI;
169 // Calculate consistent feature points
170 calcFeatPoints(edgeStat);
174 //construct feature points where more than 2 feature edges meet
175 void Foam::surfaceFeatures::calcFeatPoints(const List<edgeStatus>& edgeStat)
177 DynamicList<label> featurePoints(surf_.nPoints()/1000);
179 const labelListList& pointEdges = surf_.pointEdges();
181 forAll(pointEdges, pointI)
183 const labelList& pEdges = pointEdges[pointI];
185 label nFeatEdges = 0;
189 if (edgeStat[pEdges[i]] != NONE)
197 featurePoints.append(pointI);
200 featurePoints.shrink();
201 featurePoints_.transfer(featurePoints);
202 featurePoints.clear();
206 // Returns next feature edge connected to pointI with correct value.
207 Foam::label Foam::surfaceFeatures::nextFeatEdge
209 const List<edgeStatus>& edgeStat,
210 const labelList& featVisited,
211 const label unsetVal,
212 const label prevEdgeI,
216 const labelList& pEdges = surf_.pointEdges()[vertI];
218 label nextEdgeI = -1;
222 label edgeI = pEdges[i];
227 && edgeStat[edgeI] != NONE
228 && featVisited[edgeI] == unsetVal
237 // More than one feature edge to choose from. End of segment.
247 // Finds connected feature edges by walking from prevEdgeI in direction of
248 // prevPointI. Marks feature edges visited in featVisited by assigning them
249 // the current feature line number. Returns cumulative length of edges walked.
250 // Works in one of two modes:
251 // - mark : step to edges with featVisited = -1.
252 // Mark edges visited with currentFeatI.
253 // - clear : step to edges with featVisited = currentFeatI
254 // Mark edges visited with -2 and erase from feature edges.
255 Foam::surfaceFeatures::labelScalar Foam::surfaceFeatures::walkSegment
258 const List<edgeStatus>& edgeStat,
259 const label startEdgeI,
260 const label startPointI,
261 const label currentFeatI,
262 labelList& featVisited
265 label edgeI = startEdgeI;
267 label vertI = startPointI;
272 // edgeI : first edge on this segment
273 // vertI : one of the endpoints of this segment
275 // Start walking, marking off edges (in featVisited)
287 unsetVal = currentFeatI;
291 scalar visitedLength = 0.0;
297 // Step to next feature edge with value unsetVal
298 edgeI = nextFeatEdge(edgeStat, featVisited, unsetVal, edgeI, vertI);
300 if (edgeI == -1 || edgeI == startEdgeI)
305 // Mark with current value. If in clean mode also remove feature edge.
309 featVisited[edgeI] = currentFeatI;
313 featVisited[edgeI] = -2;
317 // Step to next vertex on edge
318 const edge& e = surf_.edges()[edgeI];
320 vertI = e.otherVertex(vertI);
323 // Update cumulative length
324 visitedLength += e.mag(surf_.localPoints());
328 if (nVisited > surf_.nEdges())
330 Warning<< "walkSegment : reached iteration limit in walking "
331 << "feature edges on surface from edge:" << startEdgeI
332 << " vertex:" << startPointI << nl
333 << "Returning with large length" << endl;
335 return labelScalar(nVisited, GREAT);
340 return labelScalar(nVisited, visitedLength);
344 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
346 Foam::surfaceFeatures::surfaceFeatures(const triSurface& surf)
356 // Construct from components.
357 Foam::surfaceFeatures::surfaceFeatures
359 const triSurface& surf,
360 const labelList& featurePoints,
361 const labelList& featureEdges,
362 const label externalStart,
363 const label internalStart
367 featurePoints_(featurePoints),
368 featureEdges_(featureEdges),
369 externalStart_(externalStart),
370 internalStart_(externalStart)
374 // Construct from surface, angle and min length
375 Foam::surfaceFeatures::surfaceFeatures
377 const triSurface& surf,
378 const scalar includedAngle,
389 findFeatures(includedAngle);
391 if (minLen > 0 || minElems > 0)
393 trimFeatures(minLen, minElems);
398 //- Construct from dictionary
399 Foam::surfaceFeatures::surfaceFeatures
401 const triSurface& surf,
402 const dictionary& featInfoDict
406 featurePoints_(featInfoDict.lookup("featurePoints")),
407 featureEdges_(featInfoDict.lookup("featureEdges")),
408 externalStart_(readLabel(featInfoDict.lookup("externalStart"))),
409 internalStart_(readLabel(featInfoDict.lookup("internalStart")))
413 //- Construct from file
414 Foam::surfaceFeatures::surfaceFeatures
416 const triSurface& surf,
417 const fileName& fName
428 dictionary featInfoDict(str);
430 featureEdges_ = labelList(featInfoDict.lookup("featureEdges"));
431 featurePoints_ = labelList(featInfoDict.lookup("featurePoints"));
432 externalStart_ = readLabel(featInfoDict.lookup("externalStart"));
433 internalStart_ = readLabel(featInfoDict.lookup("internalStart"));
437 //- Construct as copy
438 Foam::surfaceFeatures::surfaceFeatures(const surfaceFeatures& sf)
441 featurePoints_(sf.featurePoints()),
442 featureEdges_(sf.featureEdges()),
443 externalStart_(sf.externalStart()),
444 internalStart_(sf.internalStart())
448 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
450 Foam::labelList Foam::surfaceFeatures::selectFeatureEdges
452 const bool regionEdges,
453 const bool externalEdges,
454 const bool internalEdges
457 DynamicList<label> selectedEdges;
461 selectedEdges.setSize(selectedEdges.size() + nRegionEdges());
463 for (label i = 0; i < externalStart_; i++)
465 selectedEdges.append(featureEdges_[i]);
471 selectedEdges.setSize(selectedEdges.size() + nExternalEdges());
473 for (label i = externalStart_; i < internalStart_; i++)
475 selectedEdges.append(featureEdges_[i]);
481 selectedEdges.setSize(selectedEdges.size() + nInternalEdges());
483 for (label i = internalStart_; i < featureEdges_.size(); i++)
485 selectedEdges.append(featureEdges_[i]);
489 return selectedEdges.shrink();
493 void Foam::surfaceFeatures::findFeatures(const scalar includedAngle)
498 (180.0-includedAngle)
499 * mathematicalConstant::pi/180.0
502 const labelListList& edgeFaces = surf_.edgeFaces();
503 const vectorField& faceNormals = surf_.faceNormals();
504 const pointField& points = surf_.points();
506 // Per edge whether is feature edge.
507 List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
509 forAll(edgeFaces, edgeI)
511 const labelList& eFaces = edgeFaces[edgeI];
513 if (eFaces.size() != 2)
515 // Non-manifold. What to do here? Is region edge? external edge?
516 edgeStat[edgeI] = REGION;
520 label face0 = eFaces[0];
521 label face1 = eFaces[1];
523 if (surf_[face0].region() != surf_[face1].region())
525 edgeStat[edgeI] = REGION;
529 if ((faceNormals[face0] & faceNormals[face1]) < minCos)
532 // Check if convex or concave by looking at angle
533 // between face centres and normal
535 surf_[face1].centre(points)
536 - surf_[face0].centre(points);
538 if ((f0Tof1 & faceNormals[face0]) > 0.0)
540 edgeStat[edgeI] = INTERNAL;
544 edgeStat[edgeI] = EXTERNAL;
551 setFromStatus(edgeStat);
555 // Remove small strings of edges. First assigns string number to
556 // every edge and then works out the length of them.
557 void Foam::surfaceFeatures::trimFeatures
563 // Convert feature edge list to status per edge.
564 List<edgeStatus> edgeStat(toStatus());
567 // Mark feature edges according to connected lines.
569 // -2: part of too small a feature line
570 // >0: feature line number
571 labelList featLines(surf_.nEdges(), -1);
573 // Current featureline number.
576 // Current starting edge
577 label startEdgeI = 0;
581 // Find unset featureline
582 for (; startEdgeI < edgeStat.size(); startEdgeI++)
586 edgeStat[startEdgeI] != NONE
587 && featLines[startEdgeI] == -1
590 // Found unassigned feature edge.
595 if (startEdgeI == edgeStat.size())
597 // No unset feature edge found. All feature edges have line number
602 featLines[startEdgeI] = featI;
604 const edge& startEdge = surf_.edges()[startEdgeI];
606 // Walk 'left' and 'right' from startEdge.
607 labelScalar leftPath =
612 startEdgeI, // edge, not yet assigned to a featureLine
613 startEdge[0], // start of edge
615 featLines // Mark for all edges
618 labelScalar rightPath =
624 startEdge[1], // end of edge
631 (leftPath.len_ + rightPath.len_ < minLen)
632 || (leftPath.n_ + rightPath.n_ < minElems)
635 // Rewalk same route (recognizable by featLines == featI)
636 // to reset featLines.
638 featLines[startEdgeI] = -2;
642 false, // 'clean' mode
644 startEdgeI, // edge, not yet assigned to a featureLine
645 startEdge[0], // start of edge
646 featI, // Unset value
647 featLines // Mark for all edges
655 startEdge[1], // end of edge
667 // Unmark all feature lines that have featLines=-2
668 forAll(featureEdges_, i)
670 label edgeI = featureEdges_[i];
672 if (featLines[edgeI] == -2)
674 edgeStat[edgeI] = NONE;
678 // Convert back to edge labels
679 setFromStatus(edgeStat);
683 void Foam::surfaceFeatures::writeDict(Ostream& writeFile) const
686 dictionary featInfoDict;
687 featInfoDict.add("externalStart", externalStart_);
688 featInfoDict.add("internalStart", internalStart_);
689 featInfoDict.add("featureEdges", featureEdges_);
690 featInfoDict.add("featurePoints", featurePoints_);
692 featInfoDict.write(writeFile);
696 void Foam::surfaceFeatures::write(const fileName& fName) const
704 void Foam::surfaceFeatures::writeObj(const fileName& prefix) const
706 OFstream regionStr(prefix + "_regionEdges.obj");
707 Pout<< "Writing region edges to " << regionStr.name() << endl;
710 for (label i = 0; i < externalStart_; i++)
712 const edge& e = surf_.edges()[featureEdges_[i]];
714 meshTools::writeOBJ(regionStr, surf_.localPoints()[e[0]]); verti++;
715 meshTools::writeOBJ(regionStr, surf_.localPoints()[e[1]]); verti++;
716 regionStr << "l " << verti-1 << ' ' << verti << endl;
720 OFstream externalStr(prefix + "_externalEdges.obj");
721 Pout<< "Writing external edges to " << externalStr.name() << endl;
724 for (label i = externalStart_; i < internalStart_; i++)
726 const edge& e = surf_.edges()[featureEdges_[i]];
728 meshTools::writeOBJ(externalStr, surf_.localPoints()[e[0]]); verti++;
729 meshTools::writeOBJ(externalStr, surf_.localPoints()[e[1]]); verti++;
730 externalStr << "l " << verti-1 << ' ' << verti << endl;
733 OFstream internalStr(prefix + "_internalEdges.obj");
734 Pout<< "Writing internal edges to " << internalStr.name() << endl;
737 for (label i = internalStart_; i < featureEdges_.size(); i++)
739 const edge& e = surf_.edges()[featureEdges_[i]];
741 meshTools::writeOBJ(internalStr, surf_.localPoints()[e[0]]); verti++;
742 meshTools::writeOBJ(internalStr, surf_.localPoints()[e[1]]); verti++;
743 internalStr << "l " << verti-1 << ' ' << verti << endl;
746 OFstream pointStr(prefix + "_points.obj");
747 Pout<< "Writing feature points to " << pointStr.name() << endl;
749 forAll(featurePoints_, i)
751 label pointI = featurePoints_[i];
753 meshTools::writeOBJ(pointStr, surf_.localPoints()[pointI]);
758 // Get nearest vertex on patch for every point of surf in pointSet.
759 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
761 const labelList& pointLabels,
762 const pointField& samples,
763 const scalarField& maxDist
766 // Build tree out of all samples.
767 octree<octreeDataPoint> ppTree
769 treeBoundBox(samples), // overall search domain
770 octreeDataPoint(samples), // all information needed to do checks
772 20.0, // maximum ratio of cubes v.s. cells
773 100.0 // max. duplicity; n/a since no bounding boxes.
776 // From patch point to surface point
777 Map<label> nearest(2*pointLabels.size());
779 const pointField& surfPoints = surf_.localPoints();
781 forAll(pointLabels, i)
783 label surfPointI = pointLabels[i];
785 const point& surfPt = surfPoints[surfPointI];
787 point maxDistPt(maxDist[i], maxDist[i], maxDist[i]);
789 treeBoundBox tightest(surfPt - maxDistPt, surfPt + maxDistPt);
790 scalar tightestDist = Foam::GREAT;
792 label sampleI = ppTree.findNearest
801 FatalErrorIn("surfaceFeatures::nearestSamples")
802 << "Problem for point "
803 << surfPointI << " in tree " << ppTree.octreeBb()
804 << abort(FatalError);
809 magSqr(samples[sampleI] - surfPt)
810 < Foam::sqr(maxDist[sampleI])
813 nearest.insert(sampleI, surfPointI);
825 << "Dumping nearest surface feature points to nearestSamples.obj"
827 << "View this Lightwave-OBJ file with e.g. javaview" << endl
830 OFstream objStream("nearestSamples.obj");
835 Map<label>::const_iterator iter = nearest.begin();
836 iter != nearest.end();
840 meshTools::writeOBJ(objStream, samples[iter.key()]); vertI++;
841 meshTools::writeOBJ(objStream, surfPoints[iter()]); vertI++;
842 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
850 // Get nearest sample point for regularly sampled points along
851 // selected edges. Return map from sample to edge label
852 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
854 const labelList& selectedEdges,
855 const pointField& samples,
856 const scalarField& sampleDist,
857 const scalarField& maxDist,
858 const scalar minSampleDist
861 const pointField& surfPoints = surf_.localPoints();
862 const edgeList& surfEdges = surf_.edges();
864 scalar maxSearch = max(maxDist);
865 vector span(maxSearch, maxSearch, maxSearch);
867 // octree.shapes holds reference!
868 octree<octreeDataPoint> ppTree
870 treeBoundBox(samples), // overall search domain
871 octreeDataPoint(samples), // all information needed to do checks
873 20.0, // maximum ratio of cubes v.s. cells
874 100.0 // max. duplicity; n/a since no bounding boxes.
877 // From patch point to surface edge.
878 Map<label> nearest(2*selectedEdges.size());
880 forAll(selectedEdges, i)
882 label surfEdgeI = selectedEdges[i];
884 const edge& e = surfEdges[surfEdgeI];
886 if (debug && (i % 1000) == 0)
888 Pout<< "looking at surface feature edge " << surfEdgeI
889 << " verts:" << e << " points:" << surfPoints[e[0]]
890 << ' ' << surfPoints[e[1]] << endl;
893 // Normalized edge vector
894 vector eVec = e.vec(surfPoints);
895 scalar eMag = mag(eVec);
905 // Coordinate along edge (0 .. eMag)
910 point edgePoint(surfPoints[e.start()] + s*eVec);
912 treeBoundBox tightest(edgePoint - span, edgePoint + span);
913 scalar tightestDist = Foam::GREAT;
915 label sampleI = ppTree.findNearest
924 // No point close enough to surface edge.
927 if (tightestDist < maxDist[sampleI])
929 nearest.insert(sampleI, surfEdgeI);
937 // Step to next sample point using local distance.
938 // Truncate to max 1/minSampleDist samples per feature edge.
939 s += max(minSampleDist*eMag, sampleDist[sampleI]);
941 if (s >= (1-minSampleDist)*eMag)
943 // Do one more sample, at edge endpoint
956 Pout<< "Dumping nearest surface edges to nearestEdges.obj\n"
957 << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
959 OFstream objStream("nearestEdges.obj");
964 Map<label>::const_iterator iter = nearest.begin();
965 iter != nearest.end();
969 label sampleI = iter.key();
971 meshTools::writeOBJ(objStream, samples[sampleI]); vertI++;
973 const edge& e = surfEdges[iter()];
976 e.line(surfPoints).nearestDist(samples[sampleI]).rawPoint();
978 meshTools::writeOBJ(objStream, nearPt); vertI++;
980 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
988 // Get nearest edge on patch for regularly sampled points along the feature
989 // edges. Return map from patch edge to feature edge.
991 // Q: using point-based sampleDist and maxDist (distance to look around
992 // each point). Should they be edge-based e.g. by averaging or max()?
993 Foam::Map<Foam::pointIndexHit> Foam::surfaceFeatures::nearestEdges
995 const labelList& selectedEdges,
996 const edgeList& sampleEdges,
997 const labelList& selectedSampleEdges,
998 const pointField& samplePoints,
999 const scalarField& sampleDist,
1000 const scalarField& maxDist,
1001 const scalar minSampleDist
1004 // Build tree out of selected sample edges.
1005 octree<octreeDataEdges> ppTree
1007 treeBoundBox(samplePoints), // overall search domain
1013 ), // geometric info container for edges
1015 20.0, // maximum ratio of cubes v.s. cells
1016 10.0 // max. duplicity
1019 const pointField& surfPoints = surf_.localPoints();
1020 const edgeList& surfEdges = surf_.edges();
1022 scalar maxSearch = max(maxDist);
1023 vector span(maxSearch, maxSearch, maxSearch);
1026 Map<pointIndexHit> nearest(2*sampleEdges.size());
1029 // Loop over all selected edges. Sample at regular intervals. Find nearest
1030 // sampleEdges (using octree)
1033 forAll(selectedEdges, i)
1035 label surfEdgeI = selectedEdges[i];
1037 const edge& e = surfEdges[surfEdgeI];
1039 if (debug && (i % 1000) == 0)
1041 Pout<< "looking at surface feature edge " << surfEdgeI
1042 << " verts:" << e << " points:" << surfPoints[e[0]]
1043 << ' ' << surfPoints[e[1]] << endl;
1046 // Normalized edge vector
1047 vector eVec = e.vec(surfPoints);
1048 scalar eMag = mag(eVec);
1053 // Sample along edge
1058 // Coordinate along edge (0 .. eMag)
1063 point edgePoint(surfPoints[e.start()] + s*eVec);
1065 treeBoundBox tightest(edgePoint - span, edgePoint + span);
1066 scalar tightestDist = Foam::GREAT;
1068 label index = ppTree.findNearest
1077 // No edge close enough to surface edge.
1081 label sampleEdgeI = ppTree.shapes().edgeLabels()[index];
1083 const edge& e = sampleEdges[sampleEdgeI];
1085 if (tightestDist < maxDist[e.start()])
1090 pointIndexHit(true, edgePoint, surfEdgeI)
1099 // Step to next sample point using local distance.
1100 // Truncate to max 1/minSampleDist samples per feature edge.
1101 // s += max(minSampleDist*eMag, sampleDist[e.start()]);
1104 if (s >= (1-minSampleDist)*eMag)
1106 // Do one more sample, at edge endpoint
1118 Pout<< "Dumping nearest surface feature edges to nearestEdges.obj\n"
1119 << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
1121 OFstream objStream("nearestEdges.obj");
1126 Map<pointIndexHit>::const_iterator iter = nearest.begin();
1127 iter != nearest.end();
1131 label sampleEdgeI = iter.key();
1133 const edge& sampleEdge = sampleEdges[sampleEdgeI];
1135 // Write line from edgeMid to point on feature edge
1136 meshTools::writeOBJ(objStream, sampleEdge.centre(samplePoints));
1139 meshTools::writeOBJ(objStream, iter().rawPoint());
1142 objStream<< "l " << vertI-1 << ' ' << vertI << endl;
1150 // Get nearest surface edge for every sample. Return in form of
1151 // labelLists giving surfaceEdge label&intersectionpoint.
1152 void Foam::surfaceFeatures::nearestSurfEdge
1154 const labelList& selectedEdges,
1155 const pointField& samples,
1156 const vector& searchSpan, // Search span
1157 labelList& edgeLabel,
1158 labelList& edgeEndPoint,
1159 pointField& edgePoint
1162 edgeLabel.setSize(samples.size());
1163 edgeEndPoint.setSize(samples.size());
1164 edgePoint.setSize(samples.size());
1166 const pointField& localPoints = surf_.localPoints();
1168 octree<octreeDataEdges> ppTree
1170 treeBoundBox(localPoints), // overall search domain
1176 ), // all information needed to do geometric checks
1178 20.0, // maximum ratio of cubes v.s. cells
1179 10.0 // max. duplicity
1185 const point& sample = samples[i];
1187 treeBoundBox tightest(sample - searchSpan, sample + searchSpan);
1189 scalar tightestDist = magSqr(searchSpan);
1206 edgeLabel[i] = selectedEdges[index];
1208 // Unfortunately findNearest does not return nearest point so
1210 const edge& e = surf_.edges()[edgeLabel[i]];
1212 pointIndexHit pHit =
1215 localPoints[e.start()],
1216 localPoints[e.end()],
1220 edgePoint[i] = pHit.rawPoint();
1221 edgeEndPoint[i] = pHit.index();
1227 // Get nearest point on nearest feature edge for every sample (is edge)
1228 void Foam::surfaceFeatures::nearestSurfEdge
1230 const labelList& selectedEdges,
1232 const edgeList& sampleEdges,
1233 const labelList& selectedSampleEdges,
1234 const pointField& samplePoints,
1236 const vector& searchSpan, // Search span
1237 labelList& edgeLabel, // label of surface edge or -1
1238 pointField& pointOnEdge, // point on above edge
1239 pointField& pointOnFeature // point on sample edge
1242 edgeLabel.setSize(selectedSampleEdges.size());
1243 pointOnEdge.setSize(selectedSampleEdges.size());
1244 pointOnFeature.setSize(selectedSampleEdges.size());
1248 octree<octreeDataEdges> ppTree
1250 treeBoundBox(surf_.localPoints()), // overall search domain
1254 surf_.localPoints(),
1256 ), // all information needed to do geometric checks
1258 10.0, // maximum ratio of cubes v.s. cells
1259 10.0 // max. duplicity
1263 forAll(selectedSampleEdges, i)
1265 const edge& e = sampleEdges[selectedSampleEdges[i]];
1267 linePointRef edgeLine = e.line(samplePoints);
1269 point eMid(edgeLine.centre());
1271 treeBoundBox tightest(eMid - searchSpan, eMid + searchSpan);
1289 edgeLabel[i] = featureEdges_[index];
1295 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1297 void Foam::surfaceFeatures::operator=(const surfaceFeatures& rhs)
1299 // Check for assignment to self
1304 "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1305 ) << "Attempted assignment to self"
1306 << abort(FatalError);
1309 if (&surf_ != &rhs.surface())
1313 "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
1314 ) << "Operating on different surfaces"
1315 << abort(FatalError);
1318 featurePoints_ = rhs.featurePoints();
1319 featureEdges_ = rhs.featureEdges();
1320 externalStart_ = rhs.externalStart();
1321 internalStart_ = rhs.internalStart();
1325 // ************************************************************************* //