FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

surfaceFeatures.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 Description
00025 
00026 \*---------------------------------------------------------------------------*/
00027 
00028 #include "surfaceFeatures.H"
00029 #include <triSurface/triSurface.H>
00030 #include <meshTools/octree.H>
00031 #include <meshTools/octreeDataEdges.H>
00032 #include <meshTools/octreeDataPoint.H>
00033 #include <meshTools/meshTools.H>
00034 #include <OpenFOAM/linePointRef.H>
00035 #include <OpenFOAM/OFstream.H>
00036 #include <OpenFOAM/IFstream.H>
00037 
00038 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00039 
00040 defineTypeNameAndDebug(Foam::surfaceFeatures, 0);
00041 
00042 
00043 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00044 
00045 //- Get nearest point on edge and classify position on edge.
00046 Foam::pointIndexHit Foam::surfaceFeatures::edgeNearest
00047 (
00048     const point& start,
00049     const point& end,
00050     const point& sample
00051 )
00052 {
00053     pointHit eHit = linePointRef(start, end).nearestDist(sample);
00054 
00055     // Classification of position on edge.
00056     label endPoint;
00057 
00058     if (eHit.hit())
00059     {
00060         // Nearest point is on edge itself.
00061         // Note: might be at or very close to endpoint. We should use tolerance
00062         // here.
00063         endPoint = -1;
00064     }
00065     else
00066     {
00067         // Nearest point has to be one of the end points. Find out
00068         // which one.
00069         if
00070         (
00071             mag(eHit.rawPoint() - start)
00072           < mag(eHit.rawPoint() - end)
00073         )
00074         {
00075             endPoint = 0;
00076         }
00077         else
00078         {
00079             endPoint = 1;
00080         }
00081     }
00082 
00083     return pointIndexHit(eHit.hit(), eHit.rawPoint(), endPoint);
00084 }
00085 
00086 
00087 // Go from selected edges only to a value for every edge
00088 Foam::List<Foam::surfaceFeatures::edgeStatus> Foam::surfaceFeatures::toStatus()
00089  const
00090 {
00091     List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
00092 
00093     // Region edges first
00094     for (label i = 0; i < externalStart_; i++)
00095     {
00096         edgeStat[featureEdges_[i]] = REGION;
00097     }
00098 
00099     // External edges
00100     for (label i = externalStart_; i < internalStart_; i++)
00101     {
00102         edgeStat[featureEdges_[i]] = EXTERNAL;
00103     }
00104 
00105     // Internal edges
00106     for (label i = internalStart_; i < featureEdges_.size(); i++)
00107     {
00108         edgeStat[featureEdges_[i]] = INTERNAL;
00109     }
00110 
00111     return edgeStat;
00112 }
00113 
00114 
00115 // Set from value for every edge
00116 void Foam::surfaceFeatures::setFromStatus(const List<edgeStatus>& edgeStat)
00117 {
00118     // Count
00119 
00120     label nRegion = 0;
00121     label nExternal = 0;
00122     label nInternal = 0;
00123 
00124     forAll(edgeStat, edgeI)
00125     {
00126         if (edgeStat[edgeI] == REGION)
00127         {
00128             nRegion++;
00129         }
00130         else if (edgeStat[edgeI] == EXTERNAL)
00131         {
00132             nExternal++;
00133         }
00134         else if (edgeStat[edgeI] == INTERNAL)
00135         {
00136             nInternal++;
00137         }
00138     }
00139 
00140     externalStart_ = nRegion;
00141     internalStart_ = externalStart_ + nExternal;
00142 
00143 
00144     // Copy
00145 
00146     featureEdges_.setSize(internalStart_ + nInternal);
00147 
00148     label regionI = 0;
00149     label externalI = externalStart_;
00150     label internalI = internalStart_;
00151 
00152     forAll(edgeStat, edgeI)
00153     {
00154         if (edgeStat[edgeI] == REGION)
00155         {
00156             featureEdges_[regionI++] = edgeI;
00157         }
00158         else if (edgeStat[edgeI] == EXTERNAL)
00159         {
00160             featureEdges_[externalI++] = edgeI;
00161         }
00162         else if (edgeStat[edgeI] == INTERNAL)
00163         {
00164             featureEdges_[internalI++] = edgeI;
00165         }
00166     }
00167 
00168     // Calculate consistent feature points
00169     calcFeatPoints(edgeStat);
00170 }
00171 
00172 
00173 //construct feature points where more than 2 feature edges meet
00174 void Foam::surfaceFeatures::calcFeatPoints(const List<edgeStatus>& edgeStat)
00175 {
00176     DynamicList<label> featurePoints(surf_.nPoints()/1000);
00177 
00178     const labelListList& pointEdges = surf_.pointEdges();
00179 
00180     forAll(pointEdges, pointI)
00181     {
00182         const labelList& pEdges = pointEdges[pointI];
00183 
00184         label nFeatEdges = 0;
00185 
00186         forAll(pEdges, i)
00187         {
00188             if (edgeStat[pEdges[i]] != NONE)
00189             {
00190                 nFeatEdges++;
00191             }
00192         }
00193 
00194         if (nFeatEdges > 2)
00195         {
00196             featurePoints.append(pointI);
00197         }
00198     }
00199 
00200     featurePoints_.transfer(featurePoints);
00201 }
00202 
00203 
00204 // Returns next feature edge connected to pointI with correct value.
00205 Foam::label Foam::surfaceFeatures::nextFeatEdge
00206 (
00207     const List<edgeStatus>& edgeStat,
00208     const labelList& featVisited,
00209     const label unsetVal,
00210     const label prevEdgeI,
00211     const label vertI
00212 ) const
00213 {
00214     const labelList& pEdges = surf_.pointEdges()[vertI];
00215 
00216     label nextEdgeI = -1;
00217 
00218     forAll(pEdges, i)
00219     {
00220         label edgeI = pEdges[i];
00221 
00222         if
00223         (
00224             edgeI != prevEdgeI
00225          && edgeStat[edgeI] != NONE
00226          && featVisited[edgeI] == unsetVal
00227         )
00228         {
00229             if (nextEdgeI == -1)
00230             {
00231                 nextEdgeI = edgeI;
00232             }
00233             else
00234             {
00235                 // More than one feature edge to choose from. End of segment.
00236                 return -1;
00237             }
00238         }
00239     }
00240 
00241     return nextEdgeI;
00242 }
00243 
00244 
00245 // Finds connected feature edges by walking from prevEdgeI in direction of
00246 // prevPointI. Marks feature edges visited in featVisited by assigning them
00247 // the current feature line number. Returns cumulative length of edges walked.
00248 // Works in one of two modes:
00249 // - mark : step to edges with featVisited = -1.
00250 //          Mark edges visited with currentFeatI.
00251 // - clear : step to edges with featVisited = currentFeatI
00252 //           Mark edges visited with -2 and erase from feature edges.
00253 Foam::surfaceFeatures::labelScalar Foam::surfaceFeatures::walkSegment
00254 (
00255     const bool mark,
00256     const List<edgeStatus>& edgeStat,
00257     const label startEdgeI,
00258     const label startPointI,
00259     const label currentFeatI,
00260     labelList& featVisited
00261 )
00262 {
00263     label edgeI = startEdgeI;
00264 
00265     label vertI = startPointI;
00266 
00267 
00268     //
00269     // Now we have:
00270     //    edgeI : first edge on this segment
00271     //    vertI : one of the endpoints of this segment
00272     //
00273     // Start walking, marking off edges (in featVisited)
00274     // as we go along.
00275     //
00276 
00277     label unsetVal;
00278 
00279     if (mark)
00280     {
00281         unsetVal = -1;
00282     }
00283     else
00284     {
00285         unsetVal = currentFeatI;
00286     }
00287 
00288 
00289     scalar visitedLength = 0.0;
00290 
00291     label nVisited = 0;
00292 
00293     do
00294     {
00295         // Step to next feature edge with value unsetVal
00296         edgeI = nextFeatEdge(edgeStat, featVisited, unsetVal, edgeI, vertI);
00297 
00298         if (edgeI == -1 || edgeI == startEdgeI)
00299         {
00300             break;
00301         }
00302 
00303         // Mark with current value. If in clean mode also remove feature edge.
00304 
00305         if (mark)
00306         {
00307             featVisited[edgeI] = currentFeatI;
00308         }
00309         else
00310         {
00311             featVisited[edgeI] = -2;
00312         }
00313 
00314 
00315         // Step to next vertex on edge
00316         const edge& e = surf_.edges()[edgeI];
00317 
00318         vertI = e.otherVertex(vertI);
00319 
00320 
00321         // Update cumulative length
00322         visitedLength += e.mag(surf_.localPoints());
00323 
00324         nVisited++;
00325 
00326         if (nVisited > surf_.nEdges())
00327         {
00328             Warning<< "walkSegment : reached iteration limit in walking "
00329                 << "feature edges on surface from edge:" << startEdgeI
00330                 << " vertex:" << startPointI << nl
00331                 << "Returning with large length" << endl;
00332 
00333             return labelScalar(nVisited, GREAT);
00334         }
00335     }
00336     while (true);
00337 
00338     return labelScalar(nVisited, visitedLength);
00339 }
00340 
00341 
00342 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00343 
00344 Foam::surfaceFeatures::surfaceFeatures(const triSurface& surf)
00345 :
00346     surf_(surf),
00347     featurePoints_(0),
00348     featureEdges_(0),
00349     externalStart_(0),
00350     internalStart_(0)
00351 {}
00352 
00353 
00354 // Construct from components.
00355 Foam::surfaceFeatures::surfaceFeatures
00356 (
00357     const triSurface& surf,
00358     const labelList& featurePoints,
00359     const labelList& featureEdges,
00360     const label externalStart,
00361     const label internalStart
00362 )
00363 :
00364     surf_(surf),
00365     featurePoints_(featurePoints),
00366     featureEdges_(featureEdges),
00367     externalStart_(externalStart),
00368     internalStart_(externalStart)
00369 {}
00370 
00371 
00372 // Construct from surface, angle and min length
00373 Foam::surfaceFeatures::surfaceFeatures
00374 (
00375     const triSurface& surf,
00376     const scalar includedAngle,
00377     const scalar minLen,
00378     const label minElems
00379 )
00380 :
00381     surf_(surf),
00382     featurePoints_(0),
00383     featureEdges_(0),
00384     externalStart_(0),
00385     internalStart_(0)
00386 {
00387     findFeatures(includedAngle);
00388 
00389     if (minLen > 0 || minElems > 0)
00390     {
00391         trimFeatures(minLen, minElems);
00392     }
00393 }
00394 
00395 
00396 //- Construct from dictionary
00397 Foam::surfaceFeatures::surfaceFeatures
00398 (
00399     const triSurface& surf,
00400     const dictionary& featInfoDict
00401 )
00402 :
00403     surf_(surf),
00404     featurePoints_(featInfoDict.lookup("featurePoints")),
00405     featureEdges_(featInfoDict.lookup("featureEdges")),
00406     externalStart_(readLabel(featInfoDict.lookup("externalStart"))),
00407     internalStart_(readLabel(featInfoDict.lookup("internalStart")))
00408 {}
00409 
00410 
00411 //- Construct from file
00412 Foam::surfaceFeatures::surfaceFeatures
00413 (
00414     const triSurface& surf,
00415     const fileName& fName
00416 )
00417 :
00418     surf_(surf),
00419     featurePoints_(0),
00420     featureEdges_(0),
00421     externalStart_(0),
00422     internalStart_(0)
00423 {
00424     IFstream str(fName);
00425 
00426     dictionary featInfoDict(str);
00427 
00428     featureEdges_ = labelList(featInfoDict.lookup("featureEdges"));
00429     featurePoints_ = labelList(featInfoDict.lookup("featurePoints"));
00430     externalStart_ = readLabel(featInfoDict.lookup("externalStart"));
00431     internalStart_ = readLabel(featInfoDict.lookup("internalStart"));
00432 }
00433 
00434 
00435 //- Construct as copy
00436 Foam::surfaceFeatures::surfaceFeatures(const surfaceFeatures& sf)
00437 :
00438     surf_(sf.surface()),
00439     featurePoints_(sf.featurePoints()),
00440     featureEdges_(sf.featureEdges()),
00441     externalStart_(sf.externalStart()),
00442     internalStart_(sf.internalStart())
00443 {}
00444 
00445 
00446 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00447 
00448 Foam::labelList Foam::surfaceFeatures::selectFeatureEdges
00449 (
00450     const bool regionEdges,
00451     const bool externalEdges,
00452     const bool internalEdges
00453 ) const
00454 {
00455     DynamicList<label> selectedEdges;
00456 
00457     if (regionEdges)
00458     {
00459         selectedEdges.setCapacity(selectedEdges.size() + nRegionEdges());
00460 
00461         for (label i = 0; i < externalStart_; i++)
00462         {
00463             selectedEdges.append(featureEdges_[i]);
00464         }
00465     }
00466 
00467     if (externalEdges)
00468     {
00469         selectedEdges.setCapacity(selectedEdges.size() + nExternalEdges());
00470 
00471         for (label i = externalStart_; i < internalStart_; i++)
00472         {
00473             selectedEdges.append(featureEdges_[i]);
00474         }
00475     }
00476 
00477     if (internalEdges)
00478     {
00479         selectedEdges.setCapacity(selectedEdges.size() + nInternalEdges());
00480 
00481         for (label i = internalStart_; i < featureEdges_.size(); i++)
00482         {
00483             selectedEdges.append(featureEdges_[i]);
00484         }
00485     }
00486 
00487     return selectedEdges.shrink();
00488 }
00489 
00490 
00491 void Foam::surfaceFeatures::findFeatures(const scalar includedAngle)
00492 {
00493     scalar minCos =
00494         Foam::cos
00495         (
00496             (180.0-includedAngle)
00497           * mathematicalConstant::pi/180.0
00498         );
00499 
00500     const labelListList& edgeFaces = surf_.edgeFaces();
00501     const vectorField& faceNormals = surf_.faceNormals();
00502     const pointField& points = surf_.points();
00503 
00504     // Per edge whether is feature edge.
00505     List<edgeStatus> edgeStat(surf_.nEdges(), NONE);
00506 
00507     forAll(edgeFaces, edgeI)
00508     {
00509         const labelList& eFaces = edgeFaces[edgeI];
00510 
00511         if (eFaces.size() != 2)
00512         {
00513             // Non-manifold. What to do here? Is region edge? external edge?
00514             edgeStat[edgeI] = REGION;
00515         }
00516         else
00517         {
00518             label face0 = eFaces[0];
00519             label face1 = eFaces[1];
00520 
00521             if (surf_[face0].region() != surf_[face1].region())
00522             {
00523                 edgeStat[edgeI] = REGION;
00524             }
00525             else
00526             {
00527                 if ((faceNormals[face0] & faceNormals[face1]) < minCos)
00528                 {
00529 
00530                     // Check if convex or concave by looking at angle
00531                     // between face centres and normal
00532                     vector f0Tof1 =
00533                         surf_[face1].centre(points)
00534                         - surf_[face0].centre(points);
00535 
00536                     if ((f0Tof1 & faceNormals[face0]) > 0.0)
00537                     {
00538                         edgeStat[edgeI] = INTERNAL;
00539                     }
00540                     else
00541                     {
00542                         edgeStat[edgeI] = EXTERNAL;
00543                     }
00544                 }
00545             }
00546         }
00547     }
00548 
00549     setFromStatus(edgeStat);
00550 }
00551 
00552 
00553 // Remove small strings of edges. First assigns string number to
00554 // every edge and then works out the length of them.
00555 void Foam::surfaceFeatures::trimFeatures
00556 (
00557     const scalar minLen,
00558     const label minElems
00559 )
00560 {
00561     // Convert feature edge list to status per edge.
00562     List<edgeStatus> edgeStat(toStatus());
00563 
00564 
00565     // Mark feature edges according to connected lines.
00566     // -1: unassigned
00567     // -2: part of too small a feature line
00568     // >0: feature line number
00569     labelList featLines(surf_.nEdges(), -1);
00570 
00571     // Current featureline number.
00572     label featI = 0;
00573 
00574     // Current starting edge
00575     label startEdgeI = 0;
00576 
00577     do
00578     {
00579         // Find unset featureline
00580         for (; startEdgeI < edgeStat.size(); startEdgeI++)
00581         {
00582             if
00583             (
00584                 edgeStat[startEdgeI] != NONE
00585              && featLines[startEdgeI] == -1
00586             )
00587             {
00588                 // Found unassigned feature edge.
00589                 break;
00590             }
00591         }
00592 
00593         if (startEdgeI == edgeStat.size())
00594         {
00595             // No unset feature edge found. All feature edges have line number
00596             // assigned.
00597             break;
00598         }
00599 
00600         featLines[startEdgeI] = featI;
00601 
00602         const edge& startEdge = surf_.edges()[startEdgeI];
00603 
00604         // Walk 'left' and 'right' from startEdge.
00605         labelScalar leftPath =
00606             walkSegment
00607             (
00608                 true,           // 'mark' mode
00609                 edgeStat,
00610                 startEdgeI,     // edge, not yet assigned to a featureLine
00611                 startEdge[0],   // start of edge
00612                 featI,          // Mark value
00613                 featLines       // Mark for all edges
00614             );
00615 
00616         labelScalar rightPath =
00617             walkSegment
00618             (
00619                 true,
00620                 edgeStat,
00621                 startEdgeI,
00622                 startEdge[1],   // end of edge
00623                 featI,
00624                 featLines
00625             );
00626 
00627         if
00628         (
00629             (leftPath.len_ + rightPath.len_ < minLen)
00630          || (leftPath.n_ + rightPath.n_ < minElems)
00631         )
00632         {
00633             // Rewalk same route (recognizable by featLines == featI)
00634             // to reset featLines.
00635 
00636             featLines[startEdgeI] = -2;
00637 
00638             walkSegment
00639             (
00640                 false,          // 'clean' mode
00641                 edgeStat,
00642                 startEdgeI,     // edge, not yet assigned to a featureLine
00643                 startEdge[0],   // start of edge
00644                 featI,          // Unset value
00645                 featLines       // Mark for all edges
00646             );
00647 
00648             walkSegment
00649             (
00650                 false,
00651                 edgeStat,
00652                 startEdgeI,
00653                 startEdge[1],   // end of edge
00654                 featI,
00655                 featLines
00656             );
00657         }
00658         else
00659         {
00660             featI++;
00661         }
00662     }
00663     while (true);
00664 
00665     // Unmark all feature lines that have featLines=-2
00666     forAll(featureEdges_, i)
00667     {
00668         label edgeI = featureEdges_[i];
00669 
00670         if (featLines[edgeI] == -2)
00671         {
00672             edgeStat[edgeI] = NONE;
00673         }
00674     }
00675 
00676     // Convert back to edge labels
00677     setFromStatus(edgeStat);
00678 }
00679 
00680 
00681 void Foam::surfaceFeatures::writeDict(Ostream& writeFile) const
00682 {
00683 
00684     dictionary featInfoDict;
00685     featInfoDict.add("externalStart", externalStart_);
00686     featInfoDict.add("internalStart", internalStart_);
00687     featInfoDict.add("featureEdges", featureEdges_);
00688     featInfoDict.add("featurePoints", featurePoints_);
00689 
00690     featInfoDict.write(writeFile);
00691 }
00692 
00693 
00694 void Foam::surfaceFeatures::write(const fileName& fName) const
00695 {
00696     OFstream str(fName);
00697 
00698     writeDict(str);
00699 }
00700 
00701 
00702 void Foam::surfaceFeatures::writeObj(const fileName& prefix) const
00703 {
00704     OFstream regionStr(prefix + "_regionEdges.obj");
00705     Pout<< "Writing region edges to " << regionStr.name() << endl;
00706 
00707     label verti = 0;
00708     for (label i = 0; i < externalStart_; i++)
00709     {
00710         const edge& e = surf_.edges()[featureEdges_[i]];
00711 
00712         meshTools::writeOBJ(regionStr, surf_.localPoints()[e[0]]); verti++;
00713         meshTools::writeOBJ(regionStr, surf_.localPoints()[e[1]]); verti++;
00714         regionStr << "l " << verti-1 << ' ' << verti << endl;
00715     }
00716 
00717 
00718     OFstream externalStr(prefix + "_externalEdges.obj");
00719     Pout<< "Writing external edges to " << externalStr.name() << endl;
00720 
00721     verti = 0;
00722     for (label i = externalStart_; i < internalStart_; i++)
00723     {
00724         const edge& e = surf_.edges()[featureEdges_[i]];
00725 
00726         meshTools::writeOBJ(externalStr, surf_.localPoints()[e[0]]); verti++;
00727         meshTools::writeOBJ(externalStr, surf_.localPoints()[e[1]]); verti++;
00728         externalStr << "l " << verti-1 << ' ' << verti << endl;
00729     }
00730 
00731     OFstream internalStr(prefix + "_internalEdges.obj");
00732     Pout<< "Writing internal edges to " << internalStr.name() << endl;
00733 
00734     verti = 0;
00735     for (label i = internalStart_; i < featureEdges_.size(); i++)
00736     {
00737         const edge& e = surf_.edges()[featureEdges_[i]];
00738 
00739         meshTools::writeOBJ(internalStr, surf_.localPoints()[e[0]]); verti++;
00740         meshTools::writeOBJ(internalStr, surf_.localPoints()[e[1]]); verti++;
00741         internalStr << "l " << verti-1 << ' ' << verti << endl;
00742     }
00743 
00744     OFstream pointStr(prefix + "_points.obj");
00745     Pout<< "Writing feature points to " << pointStr.name() << endl;
00746 
00747     forAll(featurePoints_, i)
00748     {
00749         label pointI = featurePoints_[i];
00750 
00751         meshTools::writeOBJ(pointStr, surf_.localPoints()[pointI]);
00752     }
00753 }
00754 
00755 
00756 // Get nearest vertex on patch for every point of surf in pointSet.
00757 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
00758 (
00759     const labelList& pointLabels,
00760     const pointField& samples,
00761     const scalarField& maxDist
00762 ) const
00763 {
00764     // Build tree out of all samples.
00765 
00766     //Note: cannot be done one the fly - gcc4.4 compiler bug.
00767     treeBoundBox bb(samples);
00768 
00769     octree<octreeDataPoint> ppTree
00770     (
00771         bb,                         // overall search domain
00772         octreeDataPoint(samples),   // all information needed to do checks
00773         1,          // min levels
00774         20.0,       // maximum ratio of cubes v.s. cells
00775         100.0       // max. duplicity; n/a since no bounding boxes.
00776     );
00777 
00778     // From patch point to surface point
00779     Map<label> nearest(2*pointLabels.size());
00780 
00781     const pointField& surfPoints = surf_.localPoints();
00782 
00783     forAll(pointLabels, i)
00784     {
00785         label surfPointI = pointLabels[i];
00786 
00787         const point& surfPt = surfPoints[surfPointI];
00788 
00789         point maxDistPt(maxDist[i], maxDist[i], maxDist[i]);
00790 
00791         treeBoundBox tightest(surfPt - maxDistPt, surfPt + maxDistPt);
00792         scalar tightestDist = Foam::GREAT;
00793 
00794         label sampleI = ppTree.findNearest
00795         (
00796             surfPt,
00797             tightest,
00798             tightestDist
00799         );
00800 
00801         if (sampleI == -1)
00802         {
00803             FatalErrorIn("surfaceFeatures::nearestSamples")
00804                 << "Problem for point "
00805                 << surfPointI << " in tree " << ppTree.octreeBb()
00806                 << abort(FatalError);
00807         }
00808 
00809         if
00810         (
00811             magSqr(samples[sampleI] - surfPt)
00812           < Foam::sqr(maxDist[sampleI])
00813         )
00814         {
00815             nearest.insert(sampleI, surfPointI);
00816         }
00817     }
00818 
00819 
00820     if (debug)
00821     {
00822         //
00823         // Dump to obj file
00824         //
00825 
00826         Pout<< endl
00827             << "Dumping nearest surface feature points to nearestSamples.obj"
00828             << endl
00829             << "View this Lightwave-OBJ file with e.g. javaview" << endl
00830             << endl;
00831 
00832         OFstream objStream("nearestSamples.obj");
00833 
00834         label vertI = 0;
00835         for
00836         (
00837             Map<label>::const_iterator iter = nearest.begin();
00838             iter != nearest.end();
00839             ++iter
00840         )
00841         {
00842             meshTools::writeOBJ(objStream, samples[iter.key()]); vertI++;
00843             meshTools::writeOBJ(objStream, surfPoints[iter()]); vertI++;
00844             objStream<< "l " << vertI-1 << ' ' << vertI << endl;
00845         }
00846     }
00847 
00848     return nearest;
00849 }
00850 
00851 
00852 // Get nearest sample point for regularly sampled points along
00853 // selected edges. Return map from sample to edge label
00854 Foam::Map<Foam::label> Foam::surfaceFeatures::nearestSamples
00855 (
00856     const labelList& selectedEdges,
00857     const pointField& samples,
00858     const scalarField& sampleDist,
00859     const scalarField& maxDist,
00860     const scalar minSampleDist
00861 ) const
00862 {
00863     const pointField& surfPoints = surf_.localPoints();
00864     const edgeList& surfEdges = surf_.edges();
00865 
00866     scalar maxSearch = max(maxDist);
00867     vector span(maxSearch, maxSearch, maxSearch);
00868 
00869     //Note: cannot be done one the fly - gcc4.4 compiler bug.
00870     treeBoundBox bb(samples);
00871 
00872     octree<octreeDataPoint> ppTree
00873     (
00874         bb,                         // overall search domain
00875         octreeDataPoint(samples),   // all information needed to do checks
00876         1,          // min levels
00877         20.0,       // maximum ratio of cubes v.s. cells
00878         100.0       // max. duplicity; n/a since no bounding boxes.
00879     );
00880 
00881     // From patch point to surface edge.
00882     Map<label> nearest(2*selectedEdges.size());
00883 
00884     forAll(selectedEdges, i)
00885     {
00886         label surfEdgeI = selectedEdges[i];
00887 
00888         const edge& e = surfEdges[surfEdgeI];
00889 
00890         if (debug && (i % 1000) == 0)
00891         {
00892             Pout<< "looking at surface feature edge " << surfEdgeI
00893                 << " verts:" << e << " points:" << surfPoints[e[0]]
00894                 << ' ' << surfPoints[e[1]] << endl;
00895         }
00896 
00897         // Normalized edge vector
00898         vector eVec = e.vec(surfPoints);
00899         scalar eMag = mag(eVec);
00900         eVec /= eMag;
00901 
00902 
00903         //
00904         // Sample along edge
00905         //
00906 
00907         bool exit = false;
00908 
00909         // Coordinate along edge (0 .. eMag)
00910         scalar s = 0.0;
00911 
00912         while (true)
00913         {
00914             point edgePoint(surfPoints[e.start()] + s*eVec);
00915 
00916             treeBoundBox tightest(edgePoint - span, edgePoint + span);
00917             scalar tightestDist = Foam::GREAT;
00918 
00919             label sampleI = ppTree.findNearest
00920             (
00921                 edgePoint,
00922                 tightest,
00923                 tightestDist
00924             );
00925 
00926             if (sampleI == -1)
00927             {
00928                 // No point close enough to surface edge.
00929                 break;
00930             }
00931             if (tightestDist < maxDist[sampleI])
00932             {
00933                 nearest.insert(sampleI, surfEdgeI);
00934             }
00935 
00936             if (exit)
00937             {
00938                 break;
00939             }
00940 
00941             // Step to next sample point using local distance.
00942             // Truncate to max 1/minSampleDist samples per feature edge.
00943             s += max(minSampleDist*eMag, sampleDist[sampleI]);
00944 
00945             if (s >= (1-minSampleDist)*eMag)
00946             {
00947                 // Do one more sample, at edge endpoint
00948                 s = eMag;
00949                 exit = true;
00950             }
00951         }
00952     }
00953 
00954 
00955 
00956     if (debug)
00957     {
00958         // Dump to obj file
00959 
00960         Pout<< "Dumping nearest surface edges to nearestEdges.obj\n"
00961             << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
00962 
00963         OFstream objStream("nearestEdges.obj");
00964 
00965         label vertI = 0;
00966         for
00967         (
00968             Map<label>::const_iterator iter = nearest.begin();
00969             iter != nearest.end();
00970             ++iter
00971         )
00972         {
00973             label sampleI = iter.key();
00974 
00975             meshTools::writeOBJ(objStream, samples[sampleI]); vertI++;
00976 
00977             const edge& e = surfEdges[iter()];
00978 
00979             point nearPt =
00980                 e.line(surfPoints).nearestDist(samples[sampleI]).rawPoint();
00981 
00982             meshTools::writeOBJ(objStream, nearPt); vertI++;
00983 
00984             objStream<< "l " << vertI-1 << ' ' << vertI << endl;
00985         }
00986     }
00987 
00988     return nearest;
00989 }
00990 
00991 
00992 // Get nearest edge on patch for regularly sampled points along the feature
00993 // edges. Return map from patch edge to feature edge.
00994 //
00995 // Q: using point-based sampleDist and maxDist (distance to look around
00996 // each point). Should they be edge-based e.g. by averaging or max()?
00997 Foam::Map<Foam::pointIndexHit> Foam::surfaceFeatures::nearestEdges
00998 (
00999     const labelList& selectedEdges,
01000     const edgeList& sampleEdges,
01001     const labelList& selectedSampleEdges,
01002     const pointField& samplePoints,
01003     const scalarField& sampleDist,
01004     const scalarField& maxDist,
01005     const scalar minSampleDist
01006 ) const
01007 {
01008     // Build tree out of selected sample edges.
01009     octree<octreeDataEdges> ppTree
01010     (
01011         treeBoundBox(samplePoints), // overall search domain
01012         octreeDataEdges
01013         (
01014             sampleEdges,
01015             samplePoints,
01016             selectedSampleEdges
01017         ),                          // geometric info container for edges
01018         1,                          // min levels
01019         20.0,                       // maximum ratio of cubes v.s. cells
01020         10.0                        // max. duplicity
01021     );
01022 
01023     const pointField& surfPoints = surf_.localPoints();
01024     const edgeList& surfEdges = surf_.edges();
01025 
01026     scalar maxSearch = max(maxDist);
01027     vector span(maxSearch, maxSearch, maxSearch);
01028 
01029 
01030     Map<pointIndexHit> nearest(2*sampleEdges.size());
01031 
01032     //
01033     // Loop over all selected edges. Sample at regular intervals. Find nearest
01034     // sampleEdges (using octree)
01035     //
01036 
01037     forAll(selectedEdges, i)
01038     {
01039         label surfEdgeI = selectedEdges[i];
01040 
01041         const edge& e = surfEdges[surfEdgeI];
01042 
01043         if (debug && (i % 1000) == 0)
01044         {
01045             Pout<< "looking at surface feature edge " << surfEdgeI
01046                 << " verts:" << e << " points:" << surfPoints[e[0]]
01047                 << ' ' << surfPoints[e[1]] << endl;
01048         }
01049 
01050         // Normalized edge vector
01051         vector eVec = e.vec(surfPoints);
01052         scalar eMag = mag(eVec);
01053         eVec /= eMag;
01054 
01055 
01056         //
01057         // Sample along edge
01058         //
01059 
01060         bool exit = false;
01061 
01062         // Coordinate along edge (0 .. eMag)
01063         scalar s = 0.0;
01064 
01065         while (true)
01066         {
01067             point edgePoint(surfPoints[e.start()] + s*eVec);
01068 
01069             treeBoundBox tightest(edgePoint - span, edgePoint + span);
01070             scalar tightestDist = Foam::GREAT;
01071 
01072             label index = ppTree.findNearest
01073             (
01074                 edgePoint,
01075                 tightest,
01076                 tightestDist
01077             );
01078 
01079             if (index == -1)
01080             {
01081                 // No edge close enough to surface edge.
01082                 break;
01083             }
01084 
01085             label sampleEdgeI = ppTree.shapes().edgeLabels()[index];
01086 
01087             const edge& e = sampleEdges[sampleEdgeI];
01088 
01089             if (tightestDist < maxDist[e.start()])
01090             {
01091                 nearest.insert
01092                 (
01093                     sampleEdgeI,
01094                     pointIndexHit(true, edgePoint, surfEdgeI)
01095                 );
01096             }
01097 
01098             if (exit)
01099             {
01100                 break;
01101             }
01102 
01103             // Step to next sample point using local distance.
01104             // Truncate to max 1/minSampleDist samples per feature edge.
01105 //            s += max(minSampleDist*eMag, sampleDist[e.start()]);
01106 s += 0.01*eMag;
01107 
01108             if (s >= (1-minSampleDist)*eMag)
01109             {
01110                 // Do one more sample, at edge endpoint
01111                 s = eMag;
01112                 exit = true;
01113             }
01114         }
01115     }
01116 
01117 
01118     if (debug)
01119     {
01120         // Dump to obj file
01121 
01122         Pout<< "Dumping nearest surface feature edges to nearestEdges.obj\n"
01123             << "View this Lightwave-OBJ file with e.g. javaview\n" << endl;
01124 
01125         OFstream objStream("nearestEdges.obj");
01126 
01127         label vertI = 0;
01128         for
01129         (
01130             Map<pointIndexHit>::const_iterator iter = nearest.begin();
01131             iter != nearest.end();
01132             ++iter
01133         )
01134         {
01135             label sampleEdgeI = iter.key();
01136 
01137             const edge& sampleEdge = sampleEdges[sampleEdgeI];
01138 
01139             // Write line from edgeMid to point on feature edge
01140             meshTools::writeOBJ(objStream, sampleEdge.centre(samplePoints));
01141             vertI++;
01142 
01143             meshTools::writeOBJ(objStream, iter().rawPoint());
01144             vertI++;
01145 
01146             objStream<< "l " << vertI-1 << ' ' << vertI << endl;
01147         }
01148     }
01149 
01150     return nearest;
01151 }
01152 
01153 
01154 // Get nearest surface edge for every sample. Return in form of
01155 // labelLists giving surfaceEdge label&intersectionpoint.
01156 void Foam::surfaceFeatures::nearestSurfEdge
01157 (
01158     const labelList& selectedEdges,
01159     const pointField& samples,
01160     const vector& searchSpan,   // Search span
01161     labelList& edgeLabel,
01162     labelList& edgeEndPoint,
01163     pointField& edgePoint
01164 ) const
01165 {
01166     edgeLabel.setSize(samples.size());
01167     edgeEndPoint.setSize(samples.size());
01168     edgePoint.setSize(samples.size());
01169 
01170     const pointField& localPoints = surf_.localPoints();
01171 
01172     octree<octreeDataEdges> ppTree
01173     (
01174         treeBoundBox(localPoints),  // overall search domain
01175         octreeDataEdges
01176         (
01177             surf_.edges(),
01178             localPoints,
01179             selectedEdges
01180         ),          // all information needed to do geometric checks
01181         1,          // min levels
01182         20.0,       // maximum ratio of cubes v.s. cells
01183         10.0        // max. duplicity
01184     );
01185 
01186 
01187     forAll(samples, i)
01188     {
01189         const point& sample = samples[i];
01190 
01191         treeBoundBox tightest(sample - searchSpan, sample + searchSpan);
01192 
01193         scalar tightestDist = magSqr(searchSpan);
01194 
01195         label index =
01196             ppTree.findNearest
01197             (
01198                 sample,
01199                 tightest,
01200                 tightestDist
01201             );
01202 
01203 
01204         if (index == -1)
01205         {
01206             edgeLabel[i] = -1;
01207         }
01208         else
01209         {
01210             edgeLabel[i] = selectedEdges[index];
01211 
01212             // Unfortunately findNearest does not return nearest point so
01213             // recalculate
01214             const edge& e = surf_.edges()[edgeLabel[i]];
01215 
01216             pointIndexHit pHit =
01217                 edgeNearest
01218                 (
01219                     localPoints[e.start()],
01220                     localPoints[e.end()],
01221                     sample
01222                 );
01223 
01224             edgePoint[i] = pHit.rawPoint();
01225             edgeEndPoint[i] = pHit.index();
01226         }
01227     }
01228 }
01229 
01230 
01231 // Get nearest point on nearest feature edge for every sample (is edge)
01232 void Foam::surfaceFeatures::nearestSurfEdge
01233 (
01234     const labelList& selectedEdges,
01235 
01236     const edgeList& sampleEdges,
01237     const labelList& selectedSampleEdges,
01238     const pointField& samplePoints,
01239 
01240     const vector& searchSpan,   // Search span
01241     labelList& edgeLabel,       // label of surface edge or -1
01242     pointField& pointOnEdge,    // point on above edge
01243     pointField& pointOnFeature  // point on sample edge
01244 ) const
01245 {
01246     edgeLabel.setSize(selectedSampleEdges.size());
01247     pointOnEdge.setSize(selectedSampleEdges.size());
01248     pointOnFeature.setSize(selectedSampleEdges.size());
01249 
01250 
01251     octree<octreeDataEdges> ppTree
01252     (
01253         treeBoundBox(surf_.localPoints()),  // overall search domain
01254         octreeDataEdges
01255         (
01256             surf_.edges(),
01257             surf_.localPoints(),
01258             selectedEdges
01259         ),          // all information needed to do geometric checks
01260         1,          // min levels
01261         10.0,       // maximum ratio of cubes v.s. cells
01262         10.0        // max. duplicity
01263     );
01264 
01265 
01266     forAll(selectedSampleEdges, i)
01267     {
01268         const edge& e = sampleEdges[selectedSampleEdges[i]];
01269 
01270         linePointRef edgeLine = e.line(samplePoints);
01271 
01272         point eMid(edgeLine.centre());
01273 
01274         treeBoundBox tightest(eMid - searchSpan, eMid + searchSpan);
01275 
01276         label index =
01277             ppTree.findNearest
01278             (
01279                 edgeLine,
01280                 tightest,
01281                 pointOnEdge[i],
01282                 pointOnFeature[i]
01283             );
01284 
01285 
01286         if (index == -1)
01287         {
01288             edgeLabel[i] = -1;
01289         }
01290         else
01291         {
01292             edgeLabel[i] = featureEdges_[index];
01293         }
01294     }
01295 }
01296 
01297 
01298 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
01299 
01300 void Foam::surfaceFeatures::operator=(const surfaceFeatures& rhs)
01301 {
01302     // Check for assignment to self
01303     if (this == &rhs)
01304     {
01305         FatalErrorIn
01306         (
01307             "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
01308         )   << "Attempted assignment to self"
01309             << abort(FatalError);
01310     }
01311 
01312     if (&surf_ != &rhs.surface())
01313     {
01314         FatalErrorIn
01315         (
01316             "Foam::surfaceFeatures::operator=(const Foam::surfaceFeatures&)"
01317         )   << "Operating on different surfaces"
01318             << abort(FatalError);
01319     }
01320 
01321     featurePoints_ = rhs.featurePoints();
01322     featureEdges_ = rhs.featureEdges();
01323     externalStart_ = rhs.externalStart();
01324     internalStart_ = rhs.internalStart();
01325 }
01326 
01327 
01328 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines