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

edgeIntersections.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 "edgeIntersections.H"
00029 #include <meshTools/triSurfaceSearch.H>
00030 #include <triSurface/labelPairLookup.H>
00031 #include <OpenFOAM/OFstream.H>
00032 #include <OpenFOAM/HashSet.H>
00033 #include <triSurface/triSurface.H>
00034 #include <meshTools/pointIndexHit.H>
00035 #include <meshTools/treeDataTriSurface.H>
00036 #include <meshTools/indexedOctree.H>
00037 #include <meshTools/meshTools.H>
00038 #include <OpenFOAM/plane.H>
00039 #include <OpenFOAM/Random.H>
00040 #include <OpenFOAM/mathematicalConstants.H>
00041 #include <meshTools/treeBoundBox.H>
00042 
00043 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00044 
00045 defineTypeNameAndDebug(Foam::edgeIntersections, 0);
00046 
00047 Foam::scalar Foam::edgeIntersections::alignedCos_ =
00048     Foam::cos(89.0 * Foam::mathematicalConstant::pi/180.0);
00049 
00050 
00051 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00052 
00053 void Foam::edgeIntersections::checkEdges(const triSurface& surf)
00054 {
00055     const pointField& localPoints = surf.localPoints();
00056     const edgeList& edges = surf.edges();
00057     const labelListList& edgeFaces = surf.edgeFaces();
00058 
00059     treeBoundBox bb(localPoints);
00060 
00061     scalar minSize = SMALL * bb.minDim();
00062 
00063     forAll(edges, edgeI)
00064     {
00065         const edge& e = edges[edgeI];
00066 
00067         scalar eMag = e.mag(localPoints);
00068 
00069         if (eMag < minSize)
00070         {
00071             WarningIn
00072             (
00073                 "Foam::edgeIntersections::checkEdges(const triSurface& surf)"
00074             )   << "Edge " << edgeI << " vertices " << e
00075                 << " coords:" << localPoints[e[0]] << ' '
00076                 << localPoints[e[1]] << " is very small compared to bounding"
00077                 << " box dimensions " << bb << endl
00078                 << "This might lead to problems in intersection"
00079                 << endl;
00080         }
00081 
00082         if (edgeFaces[edgeI].size() == 1)
00083         {
00084             WarningIn
00085             (
00086                 "Foam::edgeIntersections::checkEdges(const triSurface& surf)"
00087             )   << "Edge " << edgeI << " vertices " << e
00088                 << " coords:" << localPoints[e[0]] << ' '
00089                 << localPoints[e[1]] << " has only one face connected to it:"
00090                 << edgeFaces[edgeI] << endl
00091                 << "This might lead to problems in intersection"
00092                 << endl;
00093         }
00094     }
00095 }
00096 
00097 
00098 // Update intersections for selected edges.
00099 void Foam::edgeIntersections::intersectEdges
00100 (
00101     const triSurface& surf1,
00102     const pointField& points1,          // surf1 meshPoints (not localPoints!)
00103     const triSurfaceSearch& querySurf2,
00104     const scalarField& surf1PointTol,   // surf1 tolerance per point
00105     const labelList& edgeLabels
00106 )
00107 {
00108     const triSurface& surf2 = querySurf2.surface();
00109     const vectorField& normals2 = surf2.faceNormals();
00110 
00111     const labelList& meshPoints = surf1.meshPoints();
00112 
00113     if (debug)
00114     {
00115         Pout<< "Calculating intersection of " << edgeLabels.size() << " edges"
00116             << " out of " << surf1.nEdges() << " with " << surf2.size()
00117             << " triangles ..." << endl;
00118     }
00119 
00120     // Construct octree.
00121     const indexedOctree<treeDataTriSurface>& tree = querySurf2.tree();
00122 
00123 
00124     label nHits = 0;
00125 
00126 
00127     // Go through all edges, calculate intersections
00128     forAll(edgeLabels, i)
00129     {
00130         label edgeI = edgeLabels[i];
00131 
00132         if (debug && (i % 1000 == 0))
00133         {
00134             Pout<< "Intersecting edge " << edgeI << " with surface" << endl;
00135         }
00136 
00137         const edge& e = surf1.edges()[edgeI];
00138 
00139         const point& pStart = points1[meshPoints[e.start()]];
00140         const point& pEnd = points1[meshPoints[e.end()]];
00141 
00142         const vector eVec(pEnd - pStart);
00143         const scalar eMag = mag(eVec);
00144         const vector n(eVec/(eMag + VSMALL));
00145 
00146         // Smallish length for intersection calculation errors.
00147         const point tolVec = 1e-6*eVec;
00148 
00149         // Start tracking somewhat before pStart and upto somewhat after p1.
00150         // Note that tolerances here are smaller than those used to classify
00151         // hit below.
00152         // This will cause this hit to be marked as degenerate and resolved
00153         // later on.
00154         point p0 = pStart - 0.5*surf1PointTol[e[0]]*n;
00155         const point p1 = pEnd + 0.5*surf1PointTol[e[1]]*n;
00156         const scalar maxS = mag(p1 - pStart);
00157 
00158         // Get all intersections of the edge with the surface
00159 
00160         DynamicList<pointIndexHit> currentIntersections(100);
00161         DynamicList<label> currentIntersectionTypes(100);
00162 
00163         while (true)
00164         {
00165             pointIndexHit pHit = tree.findLine(p0, p1);
00166 
00167             if (pHit.hit())
00168             {
00169                 nHits++;
00170 
00171                 currentIntersections.append(pHit);
00172 
00173                 // Classify point on surface1 edge.
00174                 label edgeEnd = -1;
00175 
00176                 if (mag(pHit.hitPoint() - pStart) < surf1PointTol[e[0]])
00177                 {
00178                     edgeEnd = 0;
00179                 }
00180                 else if (mag(pHit.hitPoint() - pEnd) < surf1PointTol[e[1]])
00181                 {
00182                     edgeEnd = 1;
00183                 }
00184                 else if (mag(n & normals2[pHit.index()]) < alignedCos_)
00185                 {
00186                     Pout<< "Flat angle edge:" << edgeI
00187                         << " face:" << pHit.index()
00188                         << " cos:" << mag(n & normals2[pHit.index()])
00189                         << endl;
00190                     edgeEnd = 2;
00191                 }
00192 
00193                 currentIntersectionTypes.append(edgeEnd);
00194 
00195                 if (edgeEnd == 1)
00196                 {
00197                     // Close to end
00198                     break;
00199                 }
00200                 else
00201                 {
00202                     // Continue tracking. Shift by a small amount.
00203                     p0 = pHit.hitPoint() + tolVec;
00204 
00205                     if (((p0-pStart) & n) >= maxS)
00206                     {
00207                         break;
00208                     }
00209                 }
00210             }
00211             else
00212             {
00213                 // No hit.
00214                 break;
00215             }
00216         }
00217 
00218 
00219         // Done current edge. Transfer all data into *this
00220         operator[](edgeI).transfer(currentIntersections);
00221         classification_[edgeI].transfer(currentIntersectionTypes);
00222     }
00223 
00224     if (debug)
00225     {
00226         Pout<< "Found " << nHits << " intersections of edges with surface ..."
00227             << endl;
00228     }
00229 
00230 }
00231 
00232 
00233 // If edgeI intersections are close to endpoint of edge shift endpoints
00234 // slightly along edge
00235 // Updates
00236 // - points1 with new endpoint position
00237 // - affectedEdges with all edges affected by moving the point
00238 // Returns true if changed anything.
00239 bool Foam::edgeIntersections::inlinePerturb
00240 (
00241     const triSurface& surf1,
00242     const scalarField& surf1PointTol,   // surf1 tolerance per point
00243     const label edgeI,
00244     Random& rndGen,
00245     pointField& points1,
00246     boolList& affectedEdges
00247 ) const
00248 {
00249     bool hasPerturbed = false;
00250 
00251     // Check if edge close to endpoint. Note that we only have to check
00252     // the intersection closest to the edge endpoints (i.e. first and last in
00253     // edgeEdgs)
00254 
00255     const labelList& edgeEnds = classification_[edgeI];
00256 
00257     if (edgeEnds.size())
00258     {
00259         bool perturbStart = false;
00260         bool perturbEnd = false;
00261 
00262         // Check first intersection.
00263         if (edgeEnds[0] == 0)
00264         {
00265             perturbStart = true;
00266         }
00267 
00268         if (edgeEnds[edgeEnds.size()-1] == 1)
00269         {
00270             perturbEnd = true;
00271         }
00272 
00273 
00274         if (perturbStart || perturbEnd)
00275         {
00276             const edge& e = surf1.edges()[edgeI];
00277 
00278             label v0 = surf1.meshPoints()[e[0]];
00279             label v1 = surf1.meshPoints()[e[1]];
00280 
00281             vector eVec(points1[v1] - points1[v0]);
00282             vector n = eVec/mag(eVec);
00283 
00284             if (perturbStart)
00285             {
00286                 // Perturb with something (hopefully) larger than tolerance.
00287                 scalar t = 4.0*(rndGen.scalar01() - 0.5);
00288                 points1[v0] += t*surf1PointTol[e[0]]*n;
00289 
00290                 const labelList& pEdges = surf1.pointEdges()[e[0]];
00291 
00292                 forAll(pEdges, i)
00293                 {
00294                     affectedEdges[pEdges[i]] = true;
00295                 }
00296             }
00297             if (perturbEnd)
00298             {
00299                 // Perturb with something larger than tolerance.
00300                 scalar t = 4.0*(rndGen.scalar01() - 0.5);
00301                 points1[v1] += t*surf1PointTol[e[1]]*n;
00302 
00303                 const labelList& pEdges = surf1.pointEdges()[e[1]];
00304 
00305                 forAll(pEdges, i)
00306                 {
00307                     affectedEdges[pEdges[i]] = true;
00308                 }
00309             }
00310             hasPerturbed = true;
00311         }
00312     }
00313 
00314     return hasPerturbed;
00315 }
00316 
00317 
00318 // Perturb single edge endpoint when perpendicular to face
00319 bool Foam::edgeIntersections::rotatePerturb
00320 (
00321     const triSurface& surf1,
00322     const scalarField& surf1PointTol,   // surf1 tolerance per point
00323     const label edgeI,
00324 
00325     Random& rndGen,
00326     pointField& points1,
00327     boolList& affectedEdges
00328 ) const
00329 {
00330     const labelList& meshPoints = surf1.meshPoints();
00331 
00332     const labelList& edgeEnds = classification_[edgeI];
00333 
00334     bool hasPerturbed = false;
00335 
00336     forAll(edgeEnds, i)
00337     {
00338         if (edgeEnds[i] == 2)
00339         {
00340             const edge& e = surf1.edges()[edgeI];
00341 
00342             // Endpoint to modify. Choose either start or end.
00343             label pointI = e[rndGen.bit()];
00344             //label pointI = e[0];
00345 
00346             // Generate random vector slightly larger than tolerance.
00347             vector rndVec = rndGen.vector01() - vector(0.5, 0.5, 0.5);
00348 
00349             // Make sure rndVec only perp to edge
00350             vector n(points1[meshPoints[e[1]]] - points1[meshPoints[e[0]]]);
00351             scalar magN = mag(n) + VSMALL;
00352             n /= magN;
00353 
00354             rndVec -= n*(n & rndVec);
00355 
00356             // Normalize
00357             rndVec /= mag(rndVec) + VSMALL;
00358 
00359             // Scale to be moved by tolerance.
00360             rndVec *= 0.01*magN;
00361 
00362             Pout<< "rotating: shifting endpoint " << meshPoints[pointI]
00363                 << " of edge:" << edgeI << " verts:"
00364                 << points1[meshPoints[e[0]]] << ' '
00365                 << points1[meshPoints[e[1]]]
00366                 << " by " << rndVec
00367                 << " tol:" << surf1PointTol[pointI] << endl;
00368 
00369             points1[meshPoints[pointI]] += rndVec;
00370 
00371             // Mark edges affected by change to point
00372             const labelList& pEdges = surf1.pointEdges()[pointI];
00373 
00374             forAll(pEdges, i)
00375             {
00376                 affectedEdges[pEdges[i]] = true;
00377             }
00378 
00379             hasPerturbed = true;
00380 
00381             // Enough done for current edge; no need to test other intersections
00382             // of this edge.
00383             break;
00384         }
00385     }
00386 
00387     return hasPerturbed;
00388 }
00389 
00390 
00391 // Perturb edge when close to face
00392 bool Foam::edgeIntersections::offsetPerturb
00393 (
00394     const triSurface& surf1,
00395     const triSurface& surf2,
00396     const label edgeI,
00397 
00398     Random& rndGen,
00399     pointField& points1,
00400     boolList& affectedEdges
00401 ) const
00402 {
00403     const labelList& meshPoints = surf1.meshPoints();
00404 
00405     const edge& e = surf1.edges()[edgeI];
00406 
00407     const List<pointIndexHit>& hits = operator[](edgeI);
00408 
00409 
00410     bool hasPerturbed = false;
00411 
00412     // For all hits on edge
00413     forAll(hits, i)
00414     {
00415         const pointIndexHit& pHit = hits[i];
00416 
00417         // Classify point on face of surface2
00418         label surf2FaceI = pHit.index();
00419 
00420         const labelledTri& f2 = surf2.localFaces()[surf2FaceI];
00421 
00422         const pointField& surf2Pts = surf2.localPoints();
00423 
00424         label nearType;
00425         label nearLabel;
00426 
00427         triPointRef tri
00428         (
00429             surf2Pts[f2[0]],
00430             surf2Pts[f2[1]],
00431             surf2Pts[f2[2]]
00432         );
00433 
00434         point ctr = tri.centre();
00435 
00436         // Get measure for tolerance.
00437         scalar tolDim = 0.001*mag(tri.a() - ctr);
00438 
00439         tri.classify(pHit.hitPoint(), tolDim, nearType, nearLabel);
00440 
00441         if (nearType == triPointRef::POINT || nearType == triPointRef::EDGE)
00442         {
00443             // Shift edge towards tri centre
00444             vector offset = 0.01*rndGen.scalar01()*(ctr - pHit.hitPoint());
00445 
00446             // shift e[0]
00447             points1[meshPoints[e[0]]] += offset;
00448 
00449             // Mark edges affected by change to e0
00450             const labelList& pEdges0 = surf1.pointEdges()[e[0]];
00451 
00452             forAll(pEdges0, i)
00453             {
00454                 affectedEdges[pEdges0[i]] = true;
00455             }
00456 
00457             // shift e[1]
00458             points1[meshPoints[e[1]]] += offset;
00459 
00460             // Mark edges affected by change to e1
00461             const labelList& pEdges1 = surf1.pointEdges()[e[1]];
00462 
00463             forAll(pEdges1, i)
00464             {
00465                 affectedEdges[pEdges1[i]] = true;
00466             }
00467 
00468             hasPerturbed = true;
00469 
00470             // No need to test any other hits on this edge
00471             break;
00472         }
00473     }
00474 
00475     return hasPerturbed;
00476 }
00477 
00478 
00479 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00480 
00481 // Construct null
00482 Foam::edgeIntersections::edgeIntersections()
00483 :
00484     List<List<pointIndexHit> >(),
00485     classification_()
00486 {}
00487 
00488 
00489 // Construct from surface and tolerance
00490 Foam::edgeIntersections::edgeIntersections
00491 (
00492     const triSurface& surf1,
00493     const triSurfaceSearch& query2,
00494     const scalarField& surf1PointTol
00495 )
00496 :
00497     List<List<pointIndexHit> >(surf1.nEdges()),
00498     classification_(surf1.nEdges())
00499 {
00500     checkEdges(surf1);
00501     checkEdges(query2.surface());
00502 
00503     // Current set of edges to test
00504     labelList edgesToTest(surf1.nEdges());
00505 
00506     // Start off with all edges
00507     forAll(edgesToTest, i)
00508     {
00509         edgesToTest[i] = i;
00510     }
00511 
00512     // Determine intersections for edgesToTest
00513     intersectEdges
00514     (
00515         surf1,
00516         surf1.points(), // surf1 meshPoints (not localPoints!)
00517         query2,
00518         surf1PointTol,
00519         edgesToTest
00520     );
00521 }
00522 
00523 
00524 // Construct from components
00525 Foam::edgeIntersections::edgeIntersections
00526 (
00527     const List<List<pointIndexHit> >& intersections,
00528     const labelListList& classification
00529 )
00530 :
00531     List<List<pointIndexHit> >(intersections),
00532     classification_(classification)
00533 {}
00534 
00535 
00536 // * * * * * * * * * * * * * * * Static Functions  * * * * * * * * * * * * * //
00537 
00538 Foam::scalarField Foam::edgeIntersections::minEdgeLength(const triSurface& surf)
00539 {
00540     const pointField& localPoints = surf.localPoints();
00541     const labelListList& pointEdges = surf.pointEdges();
00542     const edgeList& edges = surf.edges();
00543 
00544     scalarField minLen(localPoints.size());
00545 
00546     forAll(minLen, pointI)
00547     {
00548         const labelList& pEdges = pointEdges[pointI];
00549 
00550         scalar minDist = GREAT;
00551 
00552         forAll(pEdges, i)
00553         {
00554             minDist = min(minDist, edges[pEdges[i]].mag(localPoints));
00555         }
00556 
00557         minLen[pointI] = minDist;
00558     }
00559     return minLen;
00560 }
00561 
00562 
00563 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00564 
00565 Foam::label Foam::edgeIntersections::removeDegenerates
00566 (
00567     const label nIters,
00568     const triSurface& surf1,
00569     const triSurfaceSearch& query2,
00570     const scalarField& surf1PointTol,
00571     pointField& points1
00572 )
00573 {
00574     const triSurface& surf2 = query2.surface();
00575 
00576     Random rndGen(356574);
00577 
00578     // Current set of edges to (re)test
00579     labelList edgesToTest(surf1.nEdges());
00580 
00581     // Start off with all edges
00582     forAll(edgesToTest, i)
00583     {
00584         edgesToTest[i] = i;
00585     }
00586 
00587 
00588     label iter = 0;
00589 
00590     for (; iter < nIters; iter++)
00591     {
00592         // Go through all edges to (re)test and perturb points if they are
00593         // degenerate hits. Mark off edges that need to be recalculated.
00594 
00595         boolList affectedEdges(surf1.nEdges(), false);
00596         label nShifted = 0;
00597         label nRotated = 0;
00598         label nOffset = 0;
00599 
00600         forAll(edgesToTest, i)
00601         {
00602             label edgeI = edgesToTest[i];
00603 
00604             // If edge not already marked for retesting
00605             if (!affectedEdges[edgeI])
00606             {
00607                 // 1. Check edges close to endpoint and perturb if nessecary.
00608 
00609                 bool shiftedEdgeEndPoints =
00610                     inlinePerturb
00611                     (
00612                         surf1,
00613                         surf1PointTol,
00614                         edgeI,
00615                         rndGen,
00616                         points1,
00617                         affectedEdges
00618                     );
00619 
00620                 nShifted += (shiftedEdgeEndPoints ? 1 : 0);
00621 
00622                 if (!shiftedEdgeEndPoints)
00623                 {
00624                     bool rotatedEdge =
00625                         rotatePerturb
00626                         (
00627                             surf1,
00628                             surf1PointTol,
00629                             edgeI,
00630                             rndGen,
00631                             points1,
00632                             affectedEdges
00633                         );
00634 
00635                     nRotated += (rotatedEdge ? 1 : 0);
00636 
00637                     if (!rotatedEdge)
00638                     {
00639                         // 2. we're sure now that the edge actually pierces the
00640                         // face. Now check the face for intersections close its
00641                         // points/edges
00642 
00643                         bool offsetEdgePoints =
00644                             offsetPerturb
00645                             (
00646                                 surf1,
00647                                 surf2,
00648                                 edgeI,
00649                                 rndGen,
00650                                 points1,
00651                                 affectedEdges
00652                             );
00653 
00654                         nOffset += (offsetEdgePoints ? 1 : 0);
00655                     }
00656                 }
00657             }
00658         }
00659 
00660         if (debug)
00661         {
00662             Pout<< "Edges to test : " << nl
00663                 << "    total:" << edgesToTest.size() << nl
00664                 << "    resolved by:" << nl
00665                 << "        shifting   : " << nShifted << nl
00666                 << "        rotating   : " << nRotated << nl
00667                 << "        offsetting : " << nOffset << nl
00668                 << endl;
00669         }
00670 
00671 
00672         if (nShifted == 0 && nRotated == 0 && nOffset == 0)
00673         {
00674             // Nothing changed in current iteration. Current hit pattern is
00675             // without any degenerates.
00676             break;
00677         }
00678 
00679         // Repack affected edges
00680         labelList newEdgesToTest(surf1.nEdges());
00681         label newEdgeI = 0;
00682 
00683         forAll(affectedEdges, edgeI)
00684         {
00685             if (affectedEdges[edgeI])
00686             {
00687                 newEdgesToTest[newEdgeI++] = edgeI;
00688             }
00689         }
00690         newEdgesToTest.setSize(newEdgeI);
00691 
00692         if (debug)
00693         {
00694             Pout<< "Edges to test:" << nl
00695                 << "    was : " << edgesToTest.size() << nl
00696                 << "    is  : " << newEdgesToTest.size() << nl
00697                 << endl;
00698         }
00699 
00700         // Transfer and test.
00701         edgesToTest.transfer(newEdgesToTest);
00702 
00703         if (edgesToTest.empty())
00704         {
00705             FatalErrorIn("perturb") << "oops" << abort(FatalError);
00706         }
00707 
00708         // Re intersect moved edges.
00709         intersectEdges
00710         (
00711             surf1,
00712             points1,          // surf1 meshPoints (not localPoints!)
00713             query2,
00714             surf1PointTol,
00715             edgesToTest
00716         );
00717     }
00718 
00719     return iter;
00720 }
00721 
00722 
00723 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
00724 
00725 
00726 // * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
00727 
00728 
00729 // * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
00730 
00731 
00732 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines