1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*----------------------------------------------------------------------------*/
26 #include "searchableSurfacesQueries.H"
29 #include "meshTools.H"
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 defineTypeNameAndDebug(Foam::searchableSurfacesQueries, 0);
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
37 Foam::pointIndexHit Foam::searchableSurfacesQueries::tempFindNearest
39 const searchableSurface& surf,
41 const scalar initDistSqr
44 pointField onePoint(1, pt);
45 scalarField oneDist(1, initDistSqr);
46 List<pointIndexHit> oneHit(1);
47 surf.findNearest(onePoint, oneDist, oneHit);
52 // Calculate sum of distance to surfaces.
53 Foam::scalar Foam::searchableSurfacesQueries::sumDistSqr
55 const PtrList<searchableSurface>& allSurfaces,
56 const labelList& surfacesToTest,
57 const scalar initDistSqr,
63 forAll(surfacesToTest, testI)
65 label surfI = surfacesToTest[testI];
69 tempFindNearest(allSurfaces[surfI], pt, initDistSqr)
72 // Note: make it fall over if not hit.
73 sum += magSqr(hit.hitPoint()-pt);
79 // Reflects the point furthest away around the triangle centre by a factor fac.
80 // (triangle centre is the average of all points but the ihi. pSum is running
82 Foam::scalar Foam::searchableSurfacesQueries::tryMorphTet
84 const PtrList<searchableSurface>& allSurfaces,
85 const labelList& surfacesToTest,
86 const scalar initDistSqr,
94 scalar fac1 = (1.0-fac)/vector::nComponents;
95 scalar fac2 = fac1-fac;
97 vector ptry = pSum*fac1-p[ihi]*fac2;
99 scalar ytry = sumDistSqr(allSurfaces, surfacesToTest, initDistSqr, ptry);
104 pSum += ptry - p[ihi];
111 bool Foam::searchableSurfacesQueries::morphTet
113 const PtrList<searchableSurface>& allSurfaces,
114 const labelList& surfacesToTest,
115 const scalar initDistSqr,
116 const scalar convergenceDistSqr,
122 vector pSum = sum(p);
124 autoPtr<OFstream> str;
128 wordList names(surfacesToTest.size());
129 forAll(surfacesToTest, i)
131 names[i] = allSurfaces[surfacesToTest[i]].name();
133 Pout<< "searchableSurfacesQueries::morphTet : intersection of "
134 << names << " starting from points:" << p << endl;
135 str.reset(new OFstream("track.obj"));
136 meshTools::writeOBJ(str(), p[0]);
140 for (label iter = 0; iter < maxIter; iter++)
142 // Get the indices of lowest, highest and second-highest values.
143 label ilo, ihi, inhi;
145 labelList sortedIndices;
146 sortedOrder(y, sortedIndices);
147 ilo = sortedIndices[0];
148 ihi = sortedIndices[sortedIndices.size()-1];
149 inhi = sortedIndices[sortedIndices.size()-2];
154 Pout<< "Iteration:" << iter
155 << " lowest:" << y[ilo] << " highest:" << y[ihi]
156 << " points:" << p << endl;
158 meshTools::writeOBJ(str(), p[ilo]);
160 str()<< "l " << vertI-1 << ' ' << vertI << nl;
163 if (y[ihi] < convergenceDistSqr)
165 // Get point on 0th surface.
171 // Reflection: point furthest away gets reflected.
172 scalar ytry = tryMorphTet
176 10*y[ihi], // search box.
186 // If in right direction (y lower) expand by two.
199 else if (ytry >= y[inhi])
201 // If inside tet try contraction.
203 scalar ysave = y[ihi];
219 // Contract around lowest point.
224 p[i] = 0.5*(p[i] + p[ilo]);
241 meshTools::writeOBJ(str(), p[0]);
243 str()<< "l " << vertI-1 << ' ' << vertI << nl;
246 // Failure to converge. Return best guess so far.
247 label ilo = findMin(y);
254 //// Get all intersections (in order) for single surface.
255 //void Foam::searchableSurfacesQueries::findAllIntersections
257 // const searchableSurface& s,
258 // const pointField& start,
259 // const pointField& end,
260 // const vectorField& smallVec,
261 // List<List<pointIndexHit> >& surfaceHitInfo
264 // surfaceHitInfo.setSize(start.size());
266 // // Current start point of vector
267 // pointField p0(start);
269 // List<pointIndexHit> intersectInfo(start.size());
271 // // For test whether finished doing vector.
272 // const vectorField dirVec(end-start);
273 // const scalarField magSqrDirVec(magSqr(dirVec));
277 // // Find first intersection. Synced.
278 // s.findLine(p0, end, intersectInfo);
282 // forAll(intersectInfo, i)
284 // if (intersectInfo[i].hit())
288 // label sz = surfaceHitInfo[i].size();
289 // surfaceHitInfo[i].setSize(sz+1);
290 // surfaceHitInfo[i][sz] = intersectInfo[i];
292 // p0[i] = intersectInfo[i].hitPoint() + smallVec[i];
294 // // If beyond endpoint set to endpoint so as not to pick up
295 // // any intersections. Could instead just filter out hits.
296 // if (((p0[i]-start[i])&dirVec[i]) > magSqrDirVec[i])
303 // // Set to endpoint to stop intersection test. See above.
308 // // returnReduce(nHits) ?
317 // Given current set of hits (allSurfaces, allInfo) merge in those coming from
319 void Foam::searchableSurfacesQueries::mergeHits
322 const scalar mergeDist,
324 const label testI, // index of surface
325 const List<pointIndexHit>& surfHits, // hits on surface
327 labelList& allSurfaces,
328 List<pointIndexHit>& allInfo,
329 scalarList& allDistSqr
332 // Precalculate distances
333 scalarList surfDistSqr(surfHits.size());
336 surfDistSqr[i] = magSqr(surfHits[i].hitPoint()-start);
339 forAll(surfDistSqr, i)
341 label index = findLower(allDistSqr, surfDistSqr[i]);
343 // Check if equal to lower.
347 && (mag(allDistSqr[index]-surfDistSqr[i]) < mergeDist)
350 // Same. Do not count.
351 //Pout<< "point:" << surfHits[i].hitPoint()
352 // << " considered same as:" << allInfo[index].hitPoint()
353 // << " within tol:" << mergeDist
358 // Check if equal to higher
359 label next = index+1;
362 next < allDistSqr.size()
363 && (mag(allDistSqr[next]-surfDistSqr[i]) < mergeDist)
366 //Pout<< "point:" << surfHits[i].hitPoint()
367 // << " considered same as:" << allInfo[next].hitPoint()
368 // << " within tol:" << mergeDist
373 // Insert after index
374 label sz = allSurfaces.size();
375 allSurfaces.setSize(sz+1);
376 allInfo.setSize(allSurfaces.size());
377 allDistSqr.setSize(allSurfaces.size());
379 for (label j = sz-1; j > index; --j)
381 allSurfaces[j+1] = allSurfaces[j];
382 allInfo[j+1] = allInfo[j];
383 allDistSqr[j+1] = allDistSqr[j];
386 allSurfaces[index+1] = testI;
387 allInfo[index+1] = surfHits[i];
388 allDistSqr[index+1] = surfDistSqr[i];
395 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
397 // Find any intersection
398 void Foam::searchableSurfacesQueries::findAnyIntersection
400 const PtrList<searchableSurface>& allSurfaces,
401 const labelList& surfacesToTest,
402 const pointField& start,
403 const pointField& end,
404 labelList& hitSurfaces,
405 List<pointIndexHit>& hitInfo
408 hitSurfaces.setSize(start.size());
410 hitInfo.setSize(start.size());
413 labelList hitMap(identity(start.size()));
414 pointField p0(start);
416 List<pointIndexHit> intersectInfo(start.size());
418 forAll(surfacesToTest, testI)
420 // Do synchronised call to all surfaces.
421 allSurfaces[surfacesToTest[testI]].findLineAny(p0, p1, intersectInfo);
423 // Copy all hits into arguments, continue with misses
425 forAll(intersectInfo, i)
427 if (intersectInfo[i].hit())
429 hitInfo[hitMap[i]] = intersectInfo[i];
430 hitSurfaces[hitMap[i]] = testI;
436 hitMap[newI] = hitMap[i];
444 // All done? Note that this decision should be synchronised
451 hitMap.setSize(newI);
454 intersectInfo.setSize(newI);
459 void Foam::searchableSurfacesQueries::findAllIntersections
461 const PtrList<searchableSurface>& allSurfaces,
462 const labelList& surfacesToTest,
463 const pointField& start,
464 const pointField& end,
465 labelListList& hitSurfaces,
466 List<List<pointIndexHit> >& hitInfo
469 // Note: maybe move the single-surface all intersections test into
470 // searchable surface? Some of the tolerance issues might be
473 // 2. Currently calling searchableSurface::findLine with start==end
474 // is expected to find no intersection. Problem if it does.
476 hitSurfaces.setSize(start.size());
477 hitInfo.setSize(start.size());
479 if (surfacesToTest.empty())
484 // Test first surface
485 allSurfaces[surfacesToTest[0]].findLineAll(start, end, hitInfo);
487 // Set hitSurfaces and distance
488 List<scalarList> hitDistSqr(hitInfo.size());
489 forAll(hitInfo, pointI)
491 const List<pointIndexHit>& pHits = hitInfo[pointI];
493 labelList& pSurfaces = hitSurfaces[pointI];
494 pSurfaces.setSize(pHits.size());
497 scalarList& pDistSqr = hitDistSqr[pointI];
498 pDistSqr.setSize(pHits.size());
501 pDistSqr[i] = magSqr(pHits[i].hitPoint() - start[pointI]);
506 if (surfacesToTest.size() > 1)
508 // Small vector to increment start vector by to find next intersection
509 // along line. Constant factor added to make sure that start==end still
510 // ends iteration in findAllIntersections. Also SMALL is just slightly
512 const vectorField smallVec
514 1E2*SMALL*(end-start)
515 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
518 // Tolerance used to check whether points are equal. Note: used to
519 // compare distance^2. Note that we use the maximum possible tolerance
520 // (reached at intersections close to the end point)
521 const scalarField mergeDist(2*mag(smallVec)*mag(end-start));
523 // Test the other surfaces and merge (according to distance from start).
524 for (label testI = 1; testI < surfacesToTest.size(); testI++)
526 List<List<pointIndexHit> > surfHits;
527 allSurfaces[surfacesToTest[testI]].findLineAll
534 forAll(surfHits, pointI)
538 start[pointI], // Current segment
541 testI, // Surface and its hits
544 hitSurfaces[pointI], // Merge into overall hit info
554 //// Find intersections of edge nearest to both endpoints.
555 //void Foam::searchableSurfacesQueries::findNearestIntersection
557 // const PtrList<searchableSurface>& allSurfaces,
558 // const labelList& surfacesToTest,
559 // const pointField& start,
560 // const pointField& end,
562 // labelList& surface1,
563 // List<pointIndexHit>& hit1,
564 // labelList& surface2,
565 // List<pointIndexHit>& hit2
568 // // 1. intersection from start to end
569 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571 // // Initialize arguments
572 // surface1.setSize(start.size());
574 // hit1.setSize(start.size());
576 // // Current end of segment to test.
577 // pointField nearest(end);
579 // List<pointIndexHit> nearestInfo(start.size());
581 // forAll(surfacesToTest, testI)
583 // // See if any intersection between start and current nearest
584 // allSurfaces[surfacesToTest[testI]].findLine
591 // forAll(nearestInfo, pointI)
593 // if (nearestInfo[pointI].hit())
595 // hit1[pointI] = nearestInfo[pointI];
596 // surface1[pointI] = testI;
597 // nearest[pointI] = hit1[pointI].hitPoint();
603 // // 2. intersection from end to last intersection
604 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
606 // // Find the nearest intersection from end to start. Note that we
607 // // initialize to the first intersection (if any).
608 // surface2 = surface1;
611 // // Set current end of segment to test.
612 // forAll(nearest, pointI)
614 // if (hit1[pointI].hit())
616 // nearest[pointI] = hit1[pointI].hitPoint();
620 // // Disable testing by setting to end.
621 // nearest[pointI] = end[pointI];
625 // forAll(surfacesToTest, testI)
627 // // See if any intersection between end and current nearest
628 // allSurfaces[surfacesToTest[i]].findLine(end, nearest, nearestInfo);
630 // forAll(nearestInfo, pointI)
632 // if (nearestInfo[pointI].hit())
634 // hit2[pointI] = nearestInfo[pointI];
635 // surface2[pointI] = testI;
636 // nearest[pointI] = hit2[pointI].hitPoint();
643 // Find nearest. Return -1 or nearest point
644 void Foam::searchableSurfacesQueries::findNearest
646 const PtrList<searchableSurface>& allSurfaces,
647 const labelList& surfacesToTest,
648 const pointField& samples,
649 const scalarField& nearestDistSqr,
650 labelList& nearestSurfaces,
651 List<pointIndexHit>& nearestInfo
655 nearestSurfaces.setSize(samples.size());
656 nearestSurfaces = -1;
657 nearestInfo.setSize(samples.size());
660 scalarField minDistSqr(nearestDistSqr);
661 List<pointIndexHit> hitInfo(samples.size());
663 forAll(surfacesToTest, testI)
665 allSurfaces[surfacesToTest[testI]].findNearest
672 // Update minDistSqr and arguments
673 forAll(hitInfo, pointI)
675 if (hitInfo[pointI].hit())
677 minDistSqr[pointI] = magSqr
679 hitInfo[pointI].hitPoint()
682 nearestInfo[pointI] = hitInfo[pointI];
683 nearestSurfaces[pointI] = testI;
690 //- Calculate point which is on a set of surfaces.
691 Foam::pointIndexHit Foam::searchableSurfacesQueries::facesIntersection
693 const PtrList<searchableSurface>& allSurfaces,
694 const labelList& surfacesToTest,
695 const scalar initDistSqr,
696 const scalar convergenceDistSqr,
700 // Get four starting points. Take these as the projection of the
701 // starting point onto the surfaces and the mid point
702 List<point> nearest(surfacesToTest.size()+1);
704 point sumNearest = vector::zero;
706 forAll(surfacesToTest, i)
710 tempFindNearest(allSurfaces[surfacesToTest[i]], start, initDistSqr)
715 nearest[i] = hit.hitPoint();
716 sumNearest += nearest[i];
722 "searchableSurfacesQueries::facesIntersection"
723 "(const labelList&, const scalar, const scalar, const point&)"
724 ) << "Did not find point within distance "
725 << initDistSqr << " of starting point " << start
727 << allSurfaces[surfacesToTest[i]].IOobject::name()
728 << abort(FatalError);
732 nearest.last() = sumNearest / surfacesToTest.size();
735 // Get the sum of distances (initial evaluation)
736 List<scalar> nearestDist(nearest.size());
738 forAll(nearestDist, i)
740 nearestDist[i] = sumDistSqr
750 //- Downhill Simplex method
752 bool converged = morphTet
764 pointIndexHit intersection;
768 // Project nearest onto 0th surface.
769 intersection = tempFindNearest
771 allSurfaces[surfacesToTest[0]],
777 //if (!intersection.hit())
780 // scalar smallDist = Foam::sqr(convergenceDistSqr);
781 // nearest[0] = intersection.hitPoint();
782 // nearest[1] = nearest[0];
783 // nearest[1].x() += smallDist;
784 // nearest[2] = nearest[0];
785 // nearest[2].y() += smallDist;
786 // nearest[3] = nearest[0];
787 // nearest[3].z() += smallDist;
789 // forAll(nearestDist, i)
791 // nearestDist[i] = sumDistSqr
799 // intersection = morphTet
804 // convergenceDistSqr,
816 // ************************************************************************* //