1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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
25 \*----------------------------------------------------------------------------*/
27 #include "searchableSurfacesQueries.H"
30 #include "meshTools.H"
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(Foam::searchableSurfacesQueries, 0);
36 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 Foam::pointIndexHit Foam::searchableSurfacesQueries::tempFindNearest
40 const searchableSurface& surf,
42 const scalar initDistSqr
45 pointField onePoint(1, pt);
46 scalarField oneDist(1, initDistSqr);
47 List<pointIndexHit> oneHit(1);
48 surf.findNearest(onePoint, oneDist, oneHit);
53 // Calculate sum of distance to surfaces.
54 Foam::scalar Foam::searchableSurfacesQueries::sumDistSqr
56 const PtrList<searchableSurface>& allSurfaces,
57 const labelList& surfacesToTest,
58 const scalar initDistSqr,
64 forAll(surfacesToTest, testI)
66 label surfI = surfacesToTest[testI];
70 tempFindNearest(allSurfaces[surfI], pt, initDistSqr)
73 // Note: make it fall over if not hit.
74 sum += magSqr(hit.hitPoint()-pt);
80 // Reflects the point furthest away around the triangle centre by a factor fac.
81 // (triangle centre is the average of all points but the ihi. pSum is running
83 Foam::scalar Foam::searchableSurfacesQueries::tryMorphTet
85 const PtrList<searchableSurface>& allSurfaces,
86 const labelList& surfacesToTest,
87 const scalar initDistSqr,
95 scalar fac1 = (1.0-fac)/vector::nComponents;
96 scalar fac2 = fac1-fac;
98 vector ptry = pSum*fac1-p[ihi]*fac2;
100 scalar ytry = sumDistSqr(allSurfaces, surfacesToTest, initDistSqr, ptry);
105 pSum += ptry - p[ihi];
112 bool Foam::searchableSurfacesQueries::morphTet
114 const PtrList<searchableSurface>& allSurfaces,
115 const labelList& surfacesToTest,
116 const scalar initDistSqr,
117 const scalar convergenceDistSqr,
123 vector pSum = sum(p);
125 autoPtr<OFstream> str;
129 wordList names(surfacesToTest.size());
130 forAll(surfacesToTest, i)
132 names[i] = allSurfaces[surfacesToTest[i]].name();
134 Pout<< "searchableSurfacesQueries::morphTet : intersection of "
135 << names << " starting from points:" << p << endl;
136 str.reset(new OFstream("track.obj"));
137 meshTools::writeOBJ(str(), p[0]);
141 for (label iter = 0; iter < maxIter; iter++)
143 // Get the indices of lowest, highest and second-highest values.
144 label ilo, ihi, inhi;
146 labelList sortedIndices;
147 sortedOrder(y, sortedIndices);
148 ilo = sortedIndices[0];
149 ihi = sortedIndices[sortedIndices.size()-1];
150 inhi = sortedIndices[sortedIndices.size()-2];
155 Pout<< "Iteration:" << iter
156 << " lowest:" << y[ilo] << " highest:" << y[ihi]
157 << " points:" << p << endl;
159 meshTools::writeOBJ(str(), p[ilo]);
161 str()<< "l " << vertI-1 << ' ' << vertI << nl;
164 if (y[ihi] < convergenceDistSqr)
166 // Get point on 0th surface.
172 // Reflection: point furthest away gets reflected.
173 scalar ytry = tryMorphTet
177 10*y[ihi], // search box.
187 // If in right direction (y lower) expand by two.
200 else if (ytry >= y[inhi])
202 // If inside tet try contraction.
204 scalar ysave = y[ihi];
220 // Contract around lowest point.
225 p[i] = 0.5*(p[i] + p[ilo]);
242 meshTools::writeOBJ(str(), p[0]);
244 str()<< "l " << vertI-1 << ' ' << vertI << nl;
247 // Failure to converge. Return best guess so far.
248 label ilo = findMin(y);
255 //// Get all intersections (in order) for single surface.
256 //void Foam::searchableSurfacesQueries::findAllIntersections
258 // const searchableSurface& s,
259 // const pointField& start,
260 // const pointField& end,
261 // const vectorField& smallVec,
262 // List<List<pointIndexHit> >& surfaceHitInfo
265 // surfaceHitInfo.setSize(start.size());
267 // // Current start point of vector
268 // pointField p0(start);
270 // List<pointIndexHit> intersectInfo(start.size());
272 // // For test whether finished doing vector.
273 // const vectorField dirVec(end-start);
274 // const scalarField magSqrDirVec(magSqr(dirVec));
278 // // Find first intersection. Synced.
279 // s.findLine(p0, end, intersectInfo);
283 // forAll(intersectInfo, i)
285 // if (intersectInfo[i].hit())
289 // label sz = surfaceHitInfo[i].size();
290 // surfaceHitInfo[i].setSize(sz+1);
291 // surfaceHitInfo[i][sz] = intersectInfo[i];
293 // p0[i] = intersectInfo[i].hitPoint() + smallVec[i];
295 // // If beyond endpoint set to endpoint so as not to pick up
296 // // any intersections. Could instead just filter out hits.
297 // if (((p0[i]-start[i])&dirVec[i]) > magSqrDirVec[i])
304 // // Set to endpoint to stop intersection test. See above.
309 // // returnReduce(nHits) ?
318 // Given current set of hits (allSurfaces, allInfo) merge in those coming from
320 void Foam::searchableSurfacesQueries::mergeHits
323 const scalar mergeDist,
325 const label testI, // index of surface
326 const List<pointIndexHit>& surfHits, // hits on surface
328 labelList& allSurfaces,
329 List<pointIndexHit>& allInfo,
330 scalarList& allDistSqr
333 // Precalculate distances
334 scalarList surfDistSqr(surfHits.size());
337 surfDistSqr[i] = magSqr(surfHits[i].hitPoint()-start);
340 forAll(surfDistSqr, i)
342 label index = findLower(allDistSqr, surfDistSqr[i]);
344 // Check if equal to lower.
348 && (mag(allDistSqr[index]-surfDistSqr[i]) < mergeDist)
351 // Same. Do not count.
352 //Pout<< "point:" << surfHits[i].hitPoint()
353 // << " considered same as:" << allInfo[index].hitPoint()
354 // << " within tol:" << mergeDist
359 // Check if equal to higher
360 label next = index+1;
363 next < allDistSqr.size()
364 && (mag(allDistSqr[next]-surfDistSqr[i]) < mergeDist)
367 //Pout<< "point:" << surfHits[i].hitPoint()
368 // << " considered same as:" << allInfo[next].hitPoint()
369 // << " within tol:" << mergeDist
374 // Insert after index
375 label sz = allSurfaces.size();
376 allSurfaces.setSize(sz+1);
377 allInfo.setSize(allSurfaces.size());
378 allDistSqr.setSize(allSurfaces.size());
380 for (label j = sz-1; j > index; --j)
382 allSurfaces[j+1] = allSurfaces[j];
383 allInfo[j+1] = allInfo[j];
384 allDistSqr[j+1] = allDistSqr[j];
387 allSurfaces[index+1] = testI;
388 allInfo[index+1] = surfHits[i];
389 allDistSqr[index+1] = surfDistSqr[i];
396 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
398 // Find any intersection
399 void Foam::searchableSurfacesQueries::findAnyIntersection
401 const PtrList<searchableSurface>& allSurfaces,
402 const labelList& surfacesToTest,
403 const pointField& start,
404 const pointField& end,
405 labelList& hitSurfaces,
406 List<pointIndexHit>& hitInfo
409 hitSurfaces.setSize(start.size());
411 hitInfo.setSize(start.size());
414 labelList hitMap(identity(start.size()));
415 pointField p0(start);
417 List<pointIndexHit> intersectInfo(start.size());
419 forAll(surfacesToTest, testI)
421 // Do synchronised call to all surfaces.
422 allSurfaces[surfacesToTest[testI]].findLineAny(p0, p1, intersectInfo);
424 // Copy all hits into arguments, continue with misses
426 forAll(intersectInfo, i)
428 if (intersectInfo[i].hit())
430 hitInfo[hitMap[i]] = intersectInfo[i];
431 hitSurfaces[hitMap[i]] = testI;
437 hitMap[newI] = hitMap[i];
445 // All done? Note that this decision should be synchronised
452 hitMap.setSize(newI);
455 intersectInfo.setSize(newI);
460 void Foam::searchableSurfacesQueries::findAllIntersections
462 const PtrList<searchableSurface>& allSurfaces,
463 const labelList& surfacesToTest,
464 const pointField& start,
465 const pointField& end,
466 labelListList& hitSurfaces,
467 List<List<pointIndexHit> >& hitInfo
470 // Note: maybe move the single-surface all intersections test into
471 // searchable surface? Some of the tolerance issues might be
474 // 2. Currently calling searchableSurface::findLine with start==end
475 // is expected to find no intersection. Problem if it does.
477 hitSurfaces.setSize(start.size());
478 hitInfo.setSize(start.size());
480 if (surfacesToTest.empty())
485 // Test first surface
486 allSurfaces[surfacesToTest[0]].findLineAll(start, end, hitInfo);
488 // Set hitSurfaces and distance
489 List<scalarList> hitDistSqr(hitInfo.size());
490 forAll(hitInfo, pointI)
492 const List<pointIndexHit>& pHits = hitInfo[pointI];
494 labelList& pSurfaces = hitSurfaces[pointI];
495 pSurfaces.setSize(pHits.size());
498 scalarList& pDistSqr = hitDistSqr[pointI];
499 pDistSqr.setSize(pHits.size());
502 pDistSqr[i] = magSqr(pHits[i].hitPoint() - start[pointI]);
507 if (surfacesToTest.size() > 1)
509 // Small vector to increment start vector by to find next intersection
510 // along line. Constant factor added to make sure that start==end still
511 // ends iteration in findAllIntersections. Also SMALL is just slightly
513 const vectorField smallVec
515 1E2*SMALL*(end-start)
516 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
519 // Tolerance used to check whether points are equal. Note: used to
520 // compare distance^2. Note that we use the maximum possible tolerance
521 // (reached at intersections close to the end point)
522 const scalarField mergeDist(2*mag(smallVec)*mag(end-start));
524 // Test the other surfaces and merge (according to distance from start).
525 for (label testI = 1; testI < surfacesToTest.size(); testI++)
527 List<List<pointIndexHit> > surfHits;
528 allSurfaces[surfacesToTest[testI]].findLineAll
535 forAll(surfHits, pointI)
539 start[pointI], // Current segment
542 testI, // Surface and its hits
545 hitSurfaces[pointI], // Merge into overall hit info
555 //// Find intersections of edge nearest to both endpoints.
556 //void Foam::searchableSurfacesQueries::findNearestIntersection
558 // const PtrList<searchableSurface>& allSurfaces,
559 // const labelList& surfacesToTest,
560 // const pointField& start,
561 // const pointField& end,
563 // labelList& surface1,
564 // List<pointIndexHit>& hit1,
565 // labelList& surface2,
566 // List<pointIndexHit>& hit2
569 // // 1. intersection from start to end
570 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
572 // // Initialize arguments
573 // surface1.setSize(start.size());
575 // hit1.setSize(start.size());
577 // // Current end of segment to test.
578 // pointField nearest(end);
580 // List<pointIndexHit> nearestInfo(start.size());
582 // forAll(surfacesToTest, testI)
584 // // See if any intersection between start and current nearest
585 // allSurfaces[surfacesToTest[testI]].findLine
592 // forAll(nearestInfo, pointI)
594 // if (nearestInfo[pointI].hit())
596 // hit1[pointI] = nearestInfo[pointI];
597 // surface1[pointI] = testI;
598 // nearest[pointI] = hit1[pointI].hitPoint();
604 // // 2. intersection from end to last intersection
605 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
607 // // Find the nearest intersection from end to start. Note that we
608 // // initialize to the first intersection (if any).
609 // surface2 = surface1;
612 // // Set current end of segment to test.
613 // forAll(nearest, pointI)
615 // if (hit1[pointI].hit())
617 // nearest[pointI] = hit1[pointI].hitPoint();
621 // // Disable testing by setting to end.
622 // nearest[pointI] = end[pointI];
626 // forAll(surfacesToTest, testI)
628 // // See if any intersection between end and current nearest
629 // allSurfaces[surfacesToTest[i]].findLine(end, nearest, nearestInfo);
631 // forAll(nearestInfo, pointI)
633 // if (nearestInfo[pointI].hit())
635 // hit2[pointI] = nearestInfo[pointI];
636 // surface2[pointI] = testI;
637 // nearest[pointI] = hit2[pointI].hitPoint();
644 // Find nearest. Return -1 or nearest point
645 void Foam::searchableSurfacesQueries::findNearest
647 const PtrList<searchableSurface>& allSurfaces,
648 const labelList& surfacesToTest,
649 const pointField& samples,
650 const scalarField& nearestDistSqr,
651 labelList& nearestSurfaces,
652 List<pointIndexHit>& nearestInfo
656 nearestSurfaces.setSize(samples.size());
657 nearestSurfaces = -1;
658 nearestInfo.setSize(samples.size());
661 scalarField minDistSqr(nearestDistSqr);
662 List<pointIndexHit> hitInfo(samples.size());
664 forAll(surfacesToTest, testI)
666 allSurfaces[surfacesToTest[testI]].findNearest
673 // Update minDistSqr and arguments
674 forAll(hitInfo, pointI)
676 if (hitInfo[pointI].hit())
678 minDistSqr[pointI] = magSqr
680 hitInfo[pointI].hitPoint()
683 nearestInfo[pointI] = hitInfo[pointI];
684 nearestSurfaces[pointI] = testI;
691 //- Calculate point which is on a set of surfaces.
692 Foam::pointIndexHit Foam::searchableSurfacesQueries::facesIntersection
694 const PtrList<searchableSurface>& allSurfaces,
695 const labelList& surfacesToTest,
696 const scalar initDistSqr,
697 const scalar convergenceDistSqr,
701 // Get four starting points. Take these as the projection of the
702 // starting point onto the surfaces and the mid point
703 List<point> nearest(surfacesToTest.size()+1);
705 point sumNearest = vector::zero;
707 forAll(surfacesToTest, i)
711 tempFindNearest(allSurfaces[surfacesToTest[i]], start, initDistSqr)
716 nearest[i] = hit.hitPoint();
717 sumNearest += nearest[i];
723 "searchableSurfacesQueries::facesIntersection"
724 "(const labelList&, const scalar, const scalar, const point&)"
725 ) << "Did not find point within distance "
726 << initDistSqr << " of starting point " << start
728 << allSurfaces[surfacesToTest[i]].IOobject::name()
729 << abort(FatalError);
733 nearest[nearest.size()-1] = sumNearest / surfacesToTest.size();
736 // Get the sum of distances (initial evaluation)
737 List<scalar> nearestDist(nearest.size());
739 forAll(nearestDist, i)
741 nearestDist[i] = sumDistSqr
751 //- Downhill Simplex method
753 bool converged = morphTet
765 pointIndexHit intersection;
769 // Project nearest onto 0th surface.
770 intersection = tempFindNearest
772 allSurfaces[surfacesToTest[0]],
778 //if (!intersection.hit())
781 // scalar smallDist = Foam::sqr(convergenceDistSqr);
782 // nearest[0] = intersection.hitPoint();
783 // nearest[1] = nearest[0];
784 // nearest[1].x() += smallDist;
785 // nearest[2] = nearest[0];
786 // nearest[2].y() += smallDist;
787 // nearest[3] = nearest[0];
788 // nearest[3].z() += smallDist;
790 // forAll(nearestDist, i)
792 // nearestDist[i] = sumDistSqr
800 // intersection = morphTet
805 // convergenceDistSqr,
817 // ************************************************************************* //