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 "octreeDataFace.H"
27 #include "labelList.H"
30 #include "polyPatch.H"
31 #include "triangleFuncs.H"
32 #include "linePointRef.H"
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 defineTypeNameAndDebug(Foam::octreeDataFace, 0);
38 Foam::scalar Foam::octreeDataFace::tol(1E-6);
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 void Foam::octreeDataFace::calcBb()
45 allBb_.setSize(meshFaces_.size());
46 allBb_ = treeBoundBox::invertedBox;
51 treeBoundBox& myBb = allBb_[i];
53 const face& f = mesh_.faces()[meshFaces_[i]];
55 forAll(f, faceVertexI)
57 const point& coord = mesh_.points()[f[faceVertexI]];
59 myBb.min() = min(myBb.min(), coord);
60 myBb.max() = max(myBb.max(), coord);
66 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
68 // Construct from selected mesh faces
69 Foam::octreeDataFace::octreeDataFace
71 const primitiveMesh& mesh,
72 const labelList& meshFaces,
73 const treeBoundBoxList& allBb
77 meshFaces_(meshFaces),
82 // Construct from selected mesh faces. Bounding box calculated.
83 Foam::octreeDataFace::octreeDataFace
85 const primitiveMesh& mesh,
86 const labelList& meshFaces
90 meshFaces_(meshFaces),
91 allBb_(meshFaces_.size())
93 // Generate tight fitting bounding box
98 // Construct from selected mesh faces
99 Foam::octreeDataFace::octreeDataFace
101 const primitiveMesh& mesh,
102 const UList<const labelList*>& meshFaceListPtrs,
103 const UList<const treeBoundBoxList*>& bbListPtrs
112 forAll(meshFaceListPtrs, listI)
114 faceI += meshFaceListPtrs[listI]->size();
117 meshFaces_.setSize(faceI);
118 allBb_.setSize(faceI);
122 forAll(meshFaceListPtrs, listI)
124 const labelList& meshFaces = *meshFaceListPtrs[listI];
125 const treeBoundBoxList& allBb = *bbListPtrs[listI];
127 forAll(meshFaces, meshFaceI)
129 meshFaces_[faceI] = meshFaces[meshFaceI];
130 allBb_[faceI] = allBb[meshFaceI];
137 // Construct from selected mesh faces. Bounding box calculated.
138 Foam::octreeDataFace::octreeDataFace
140 const primitiveMesh& mesh,
141 const UList<const labelList*>& meshFaceListPtrs
149 forAll(meshFaceListPtrs, listI)
151 faceI += meshFaceListPtrs[listI]->size();
154 meshFaces_.setSize(faceI);
158 forAll(meshFaceListPtrs, listI)
160 const labelList& meshFaces = *meshFaceListPtrs[listI];
162 forAll(meshFaces, meshFaceI)
164 meshFaces_[faceI++] = meshFaces[meshFaceI];
168 // Generate tight fitting bounding box
173 // Construct from all faces in polyPatch. Bounding box calculated.
174 Foam::octreeDataFace::octreeDataFace(const polyPatch& patch)
176 mesh_(patch.boundaryMesh().mesh()),
177 meshFaces_(patch.size())
179 forAll(patch, patchFaceI)
181 meshFaces_[patchFaceI] = patch.start() + patchFaceI;
184 // Generate tight fitting bounding box
189 // Construct from primitiveMesh. Inserts all boundary faces.
190 Foam::octreeDataFace::octreeDataFace(const primitiveMesh& mesh)
197 meshFaces_.setSize(mesh_.nFaces() - mesh_.nInternalFaces());
199 // Set info for all boundary faces.
200 label boundaryFaceI = 0;
202 for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
204 meshFaces_[boundaryFaceI++] = faceI;
207 // Generate tight fitting bounding box
213 Foam::octreeDataFace::octreeDataFace(const octreeDataFace& shapes)
215 mesh_(shapes.mesh()),
216 meshFaces_(shapes.meshFaces()),
217 allBb_(shapes.allBb())
221 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
223 Foam::octreeDataFace::~octreeDataFace()
227 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
229 Foam::label Foam::octreeDataFace::getSampleType
231 const octree<octreeDataFace>& oc,
235 // Need to determine whether sample is 'inside' or 'outside'
236 // Done by finding nearest face. This gives back a face which is
237 // guaranteed to contain nearest point. This point can be
238 // - in interior of face: compare to face normal
239 // - on edge of face: compare to edge normal
240 // - on point of face: compare to point normal
241 // Unfortunately the octree does not give us back the intersection point
242 // or where on the face it has hit so we have to recreate all that
245 treeBoundBox tightest(treeBoundBox::greatBox);
246 scalar tightestDist(treeBoundBox::great);
247 // Find nearest face to sample
248 label index = oc.findNearest(sample, tightest, tightestDist);
254 "octreeDataFace::getSampleType"
255 "(octree<octreeDataFace>&, const point&)"
256 ) << "Could not find " << sample << " in octree."
257 << abort(FatalError);
261 // Get actual intersection point on face
262 label faceI = meshFaces_[index];
266 Pout<< "getSampleType : sample:" << sample
267 << " nearest face:" << faceI;
270 const face& f = mesh_.faces()[faceI];
272 const pointField& points = mesh_.points();
274 pointHit curHit = f.nearestPoint(sample, points);
277 // 1] Check whether sample is above face
282 // Simple case. Compare to face normal.
286 Pout<< " -> face hit:" << curHit.hitPoint()
287 << " comparing to face normal " << mesh_.faceAreas()[faceI]
290 return octree<octreeDataFace>::getVolType
292 mesh_.faceAreas()[faceI],
293 sample - curHit.hitPoint()
299 Pout<< " -> face miss:" << curHit.missPoint();
303 // 2] Check whether intersection is on one of the face vertices or
307 scalar typDim = sqrt(mag(mesh_.faceAreas()[faceI])) + VSMALL;
311 if ((mag(points[f[fp]] - curHit.missPoint())/typDim) < tol)
313 // Face intersection point equals face vertex fp
315 // Calculate point normal (wrong: uses face normals instead of
317 const labelList& myFaces = mesh_.pointFaces()[f[fp]];
319 vector pointNormal(vector::zero);
321 forAll(myFaces, myFaceI)
323 if (myFaces[myFaceI] >= mesh_.nInternalFaces())
325 vector n = mesh_.faceAreas()[myFaces[myFaceI]];
326 n /= mag(n) + VSMALL;
334 Pout<< " -> face point hit :" << points[f[fp]]
335 << " point normal:" << pointNormal
337 << mag(points[f[fp]] - curHit.missPoint())/typDim
340 return octree<octreeDataFace>::getVolType
343 sample - curHit.missPoint()
347 if ((mag(mesh_.faceCentres()[faceI] - curHit.missPoint())/typDim) < tol)
349 // Face intersection point equals face centre. Normal at face centre
350 // is already average of face normals
354 Pout<< " -> centre hit:" << mesh_.faceCentres()[faceI]
356 << mag(mesh_.faceCentres()[faceI] - curHit.missPoint())/typDim
360 return octree<octreeDataFace>::getVolType
362 mesh_.faceAreas()[faceI],
363 sample - curHit.missPoint()
369 // 3] Get the 'real' edge the face intersection is on
372 const labelList& myEdges = mesh_.faceEdges()[faceI];
374 forAll(myEdges, myEdgeI)
376 const edge& e = mesh_.edges()[myEdges[myEdgeI]];
378 pointHit edgeHit = line<point, const point&>
382 ).nearestDist(sample);
385 if ((mag(edgeHit.rawPoint() - curHit.missPoint())/typDim) < tol)
387 // Face intersection point lies on edge e
389 // Calculate edge normal (wrong: uses face normals instead of
391 const labelList& myFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
393 vector edgeNormal(vector::zero);
395 forAll(myFaces, myFaceI)
397 if (myFaces[myFaceI] >= mesh_.nInternalFaces())
399 vector n = mesh_.faceAreas()[myFaces[myFaceI]];
400 n /= mag(n) + VSMALL;
408 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
409 << " comparing to edge normal:" << edgeNormal
413 // Found face intersection point on this edge. Compare to edge
415 return octree<octreeDataFace>::getVolType
418 sample - curHit.missPoint()
425 // 4] Get the internal edge the face intersection is on
431 line<point, const point&>
434 mesh_.faceCentres()[faceI]
435 ).nearestDist(sample);
437 if ((mag(edgeHit.rawPoint() - curHit.missPoint())/typDim) < tol)
439 // Face intersection point lies on edge between two face triangles
441 // Calculate edge normal as average of the two triangle normals
442 const label fpPrev = f.rcIndex(fp);
443 const label fpNext = f.fcIndex(fp);
445 vector e = points[f[fp]] - mesh_.faceCentres()[faceI];
446 vector ePrev = points[f[fpPrev]] - mesh_.faceCentres()[faceI];
447 vector eNext = points[f[fpNext]] - mesh_.faceCentres()[faceI];
449 vector nLeft = ePrev ^ e;
450 nLeft /= mag(nLeft) + VSMALL;
452 vector nRight = e ^ eNext;
453 nRight /= mag(nRight) + VSMALL;
457 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
458 << " comparing to edge normal "
459 << 0.5*(nLeft + nRight)
463 // Found face intersection point on this edge. Compare to edge
465 return octree<octreeDataFace>::getVolType
467 0.5*(nLeft + nRight),
468 sample - curHit.missPoint()
475 Pout<< "Did not find sample " << sample
476 << " anywhere related to nearest face " << faceI << endl
481 Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
486 // Can't determine status of sample with respect to nearest face.
488 // - tolerances are wrong. (if e.g. face has zero area)
489 // - or (more likely) surface is not closed.
491 return octree<octreeDataFace>::UNKNOWN;
495 bool Foam::octreeDataFace::overlaps
498 const treeBoundBox& sampleBb
501 //return sampleBb.overlaps(allBb_[index]);
503 //- Exact test of face intersecting bb
505 // 1. Quick rejection: bb does not intersect face bb at all
506 if (!sampleBb.overlaps(allBb_[index]))
511 // 2. Check if one or more face points inside
512 label faceI = meshFaces_[index];
514 const face& f = mesh_.faces()[faceI];
516 const pointField& points = mesh_.points();
517 if (sampleBb.containsAny(points, f))
522 // 3. Difficult case: all points are outside but connecting edges might
523 // go through cube. Use triangle-bounding box intersection.
524 const point& fc = mesh_.faceCentres()[faceI];
528 const label fp1 = f.fcIndex(fp);
530 bool triIntersects = triangleFuncs::intersectBb
547 bool Foam::octreeDataFace::contains(const label, const point&) const
551 "octreeDataFace::contains(const label, const point&)"
557 bool Foam::octreeDataFace::intersects
562 point& intersectionPoint
565 label faceI = meshFaces_[index];
567 const face& f = mesh_.faces()[faceI];
569 const vector dir(end - start);
571 // Disable picking up intersections behind us.
572 scalar oldTol = intersection::setPlanarTol(0.0);
574 pointHit inter = f.ray
579 intersection::HALF_RAY,
583 intersection::setPlanarTol(oldTol);
585 if (inter.hit() && inter.distance() <= mag(dir))
587 intersectionPoint = inter.hitPoint();
598 bool Foam::octreeDataFace::findTightest
602 treeBoundBox& tightest
605 // Get furthest away vertex
607 allBb_[index].calcExtremities(sample, myNear, myFar);
609 const point dist = myFar - sample;
610 scalar myFarDist = mag(dist);
612 point tightestNear, tightestFar;
613 tightest.calcExtremities(sample, tightestNear, tightestFar);
615 scalar tightestFarDist = mag(tightestFar - sample);
617 if (tightestFarDist < myFarDist)
619 // Keep current tightest.
624 // Construct bb around sample and myFar
625 const point dist2(fabs(dist.x()), fabs(dist.y()), fabs(dist.z()));
627 tightest.min() = sample - dist2;
628 tightest.max() = sample + dist2;
635 // Determine numerical value of sign of sample compared to shape at index
636 Foam::scalar Foam::octreeDataFace::calcSign
643 label faceI = meshFaces_[index];
645 n = mesh_.faceAreas()[faceI];
647 n /= mag(n) + VSMALL;
649 vector vec = sample - mesh_.faceCentres()[faceI];
651 vec /= mag(vec) + VSMALL;
657 // Calculate nearest point on/in shapei
658 Foam::scalar Foam::octreeDataFace::calcNearest
665 label faceI = meshFaces_[index];
667 const face& f = mesh_.faces()[faceI];
669 pointHit nearHit = f.nearestPoint(sample, mesh_.points());
671 nearest = nearHit.rawPoint();
675 const point& ctr = mesh_.faceCentres()[faceI];
677 scalar sign = mesh_.faceAreas()[faceI] & (sample - nearest);
679 Pout<< "octreeDataFace::calcNearest : "
680 << "sample:" << sample
681 << " index:" << index
682 << " faceI:" << faceI
685 << " nearest point:" << nearest
686 << " distance to face:" << nearHit.distance()
689 return nearHit.distance();
693 // Calculate nearest point on/in shapei
694 Foam::scalar Foam::octreeDataFace::calcNearest
697 const linePointRef& ln,
704 "octreeDataFace::calcNearest(const label, const linePointRef&"
711 void Foam::octreeDataFace::write(Ostream& os, const label index) const
713 os << meshFaces_[index] << " " << allBb_[index];
717 // ************************************************************************* //