00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
00099 void Foam::edgeIntersections::intersectEdges
00100 (
00101 const triSurface& surf1,
00102 const pointField& points1,
00103 const triSurfaceSearch& querySurf2,
00104 const scalarField& surf1PointTol,
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
00121 const indexedOctree<treeDataTriSurface>& tree = querySurf2.tree();
00122
00123
00124 label nHits = 0;
00125
00126
00127
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
00147 const point tolVec = 1e-6*eVec;
00148
00149
00150
00151
00152
00153
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
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
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
00198 break;
00199 }
00200 else
00201 {
00202
00203 p0 = pHit.hitPoint() + tolVec;
00204
00205 if (((p0-pStart) & n) >= maxS)
00206 {
00207 break;
00208 }
00209 }
00210 }
00211 else
00212 {
00213
00214 break;
00215 }
00216 }
00217
00218
00219
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
00234
00235
00236
00237
00238
00239 bool Foam::edgeIntersections::inlinePerturb
00240 (
00241 const triSurface& surf1,
00242 const scalarField& surf1PointTol,
00243 const label edgeI,
00244 Random& rndGen,
00245 pointField& points1,
00246 boolList& affectedEdges
00247 ) const
00248 {
00249 bool hasPerturbed = false;
00250
00251
00252
00253
00254
00255 const labelList& edgeEnds = classification_[edgeI];
00256
00257 if (edgeEnds.size())
00258 {
00259 bool perturbStart = false;
00260 bool perturbEnd = false;
00261
00262
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
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
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
00319 bool Foam::edgeIntersections::rotatePerturb
00320 (
00321 const triSurface& surf1,
00322 const scalarField& surf1PointTol,
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
00343 label pointI = e[rndGen.bit()];
00344
00345
00346
00347 vector rndVec = rndGen.vector01() - vector(0.5, 0.5, 0.5);
00348
00349
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
00357 rndVec /= mag(rndVec) + VSMALL;
00358
00359
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
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
00382
00383 break;
00384 }
00385 }
00386
00387 return hasPerturbed;
00388 }
00389
00390
00391
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
00413 forAll(hits, i)
00414 {
00415 const pointIndexHit& pHit = hits[i];
00416
00417
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
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
00444 vector offset = 0.01*rndGen.scalar01()*(ctr - pHit.hitPoint());
00445
00446
00447 points1[meshPoints[e[0]]] += offset;
00448
00449
00450 const labelList& pEdges0 = surf1.pointEdges()[e[0]];
00451
00452 forAll(pEdges0, i)
00453 {
00454 affectedEdges[pEdges0[i]] = true;
00455 }
00456
00457
00458 points1[meshPoints[e[1]]] += offset;
00459
00460
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
00471 break;
00472 }
00473 }
00474
00475 return hasPerturbed;
00476 }
00477
00478
00479
00480
00481
00482 Foam::edgeIntersections::edgeIntersections()
00483 :
00484 List<List<pointIndexHit> >(),
00485 classification_()
00486 {}
00487
00488
00489
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
00504 labelList edgesToTest(surf1.nEdges());
00505
00506
00507 forAll(edgesToTest, i)
00508 {
00509 edgesToTest[i] = i;
00510 }
00511
00512
00513 intersectEdges
00514 (
00515 surf1,
00516 surf1.points(),
00517 query2,
00518 surf1PointTol,
00519 edgesToTest
00520 );
00521 }
00522
00523
00524
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
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
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
00579 labelList edgesToTest(surf1.nEdges());
00580
00581
00582 forAll(edgesToTest, i)
00583 {
00584 edgesToTest[i] = i;
00585 }
00586
00587
00588 label iter = 0;
00589
00590 for (; iter < nIters; iter++)
00591 {
00592
00593
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
00605 if (!affectedEdges[edgeI])
00606 {
00607
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
00640
00641
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
00675
00676 break;
00677 }
00678
00679
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
00701 edgesToTest.transfer(newEdgesToTest);
00702
00703 if (edgesToTest.empty())
00704 {
00705 FatalErrorIn("perturb") << "oops" << abort(FatalError);
00706 }
00707
00708
00709 intersectEdges
00710 (
00711 surf1,
00712 points1,
00713 query2,
00714 surf1PointTol,
00715 edgesToTest
00716 );
00717 }
00718
00719 return iter;
00720 }
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732