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 "treeDataFace.H"
28 #include "triangleFuncs.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 defineTypeNameAndDebug(Foam::treeDataFace, 0);
34 Foam::scalar Foam::treeDataFace::tolSqr = sqr(1E-6);
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 Foam::treeBoundBox Foam::treeDataFace::calcBb(const label faceI) const
41 const pointField& points = mesh_.points();
43 const face& f = mesh_.faces()[faceI];
45 treeBoundBox bb(points[f[0]], points[f[0]]);
47 for (label fp = 1; fp < f.size(); fp++)
49 const point& p = points[f[fp]];
51 bb.min() = min(bb.min(), p);
52 bb.max() = max(bb.max(), p);
58 void Foam::treeDataFace::update()
60 forAll(faceLabels_, i)
62 isTreeFace_.set(faceLabels_[i], 1);
67 bbs_.setSize(faceLabels_.size());
69 forAll(faceLabels_, i)
71 bbs_[i] = calcBb(faceLabels_[i]);
77 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
79 Foam::treeDataFace::treeDataFace
82 const primitiveMesh& mesh,
83 const labelUList& faceLabels
87 faceLabels_(faceLabels),
88 isTreeFace_(mesh.nFaces(), 0),
95 Foam::treeDataFace::treeDataFace
98 const primitiveMesh& mesh,
99 const Xfer<labelList>& faceLabels
103 faceLabels_(faceLabels),
104 isTreeFace_(mesh.nFaces(), 0),
111 Foam::treeDataFace::treeDataFace
114 const primitiveMesh& mesh
118 faceLabels_(identity(mesh_.nFaces())),
119 isTreeFace_(mesh.nFaces(), 0),
126 Foam::treeDataFace::treeDataFace
129 const polyPatch& patch
132 mesh_(patch.boundaryMesh().mesh()),
135 identity(patch.size())
138 isTreeFace_(mesh_.nFaces(), 0),
145 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
147 Foam::pointField Foam::treeDataFace::shapePoints() const
149 pointField cc(faceLabels_.size());
151 forAll(faceLabels_, i)
153 cc[i] = mesh_.faceCentres()[faceLabels_[i]];
160 //- Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
161 // Only makes sense for closed surfaces.
162 Foam::label Foam::treeDataFace::getVolumeType
164 const indexedOctree<treeDataFace>& oc,
168 // Need to determine whether sample is 'inside' or 'outside'
169 // Done by finding nearest face. This gives back a face which is
170 // guaranteed to contain nearest point. This point can be
171 // - in interior of face: compare to face normal
172 // - on edge of face: compare to edge normal
173 // - on point of face: compare to point normal
174 // Unfortunately the octree does not give us back the intersection point
175 // or where on the face it has hit so we have to recreate all that
179 // Find nearest face to sample
180 pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
182 if (info.index() == -1)
186 "treeDataFace::getSampleType"
187 "(indexedOctree<treeDataFace>&, const point&)"
188 ) << "Could not find " << sample << " in octree."
189 << abort(FatalError);
193 // Get actual intersection point on face
194 label faceI = faceLabels_[info.index()];
198 Pout<< "getSampleType : sample:" << sample
199 << " nearest face:" << faceI;
202 const pointField& points = mesh_.points();
204 // Retest to classify where on face info is. Note: could be improved. We
205 // already have point.
207 const face& f = mesh_.faces()[faceI];
208 const vector& area = mesh_.faceAreas()[faceI];
209 const point& fc = mesh_.faceCentres()[faceI];
211 pointHit curHit = f.nearestPoint(sample, points);
212 const point& curPt = curHit.rawPoint();
215 // 1] Check whether sample is above face
220 // Nearest point inside face. Compare to face normal.
224 Pout<< " -> face hit:" << curPt
225 << " comparing to face normal " << area << endl;
227 return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
232 Pout<< " -> face miss:" << curPt;
236 // 2] Check whether intersection is on one of the face vertices or
240 const scalar typDimSqr = mag(area) + VSMALL;
244 if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
246 // Face intersection point equals face vertex fp
248 // Calculate point normal (wrong: uses face normals instead of
250 const labelList& pFaces = mesh_.pointFaces()[f[fp]];
252 vector pointNormal(vector::zero);
256 if (isTreeFace_.get(pFaces[i]) == 1)
258 vector n = mesh_.faceAreas()[pFaces[i]];
259 n /= mag(n) + VSMALL;
267 Pout<< " -> face point hit :" << points[f[fp]]
268 << " point normal:" << pointNormal
270 << magSqr(points[f[fp]] - curPt)/typDimSqr << endl;
272 return indexedOctree<treeDataFace>::getSide
279 if ((magSqr(fc - curPt)/typDimSqr) < tolSqr)
281 // Face intersection point equals face centre. Normal at face centre
282 // is already average of face normals
286 Pout<< " -> centre hit:" << fc
287 << " distance:" << magSqr(fc - curPt)/typDimSqr << endl;
290 return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
296 // 3] Get the 'real' edge the face intersection is on
299 const labelList& myEdges = mesh_.faceEdges()[faceI];
301 forAll(myEdges, myEdgeI)
303 const edge& e = mesh_.edges()[myEdges[myEdgeI]];
306 line<point, const point&>
310 ).nearestDist(sample);
313 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
315 // Face intersection point lies on edge e
317 // Calculate edge normal (wrong: uses face normals instead of
319 const labelList& eFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
321 vector edgeNormal(vector::zero);
325 if (isTreeFace_.get(eFaces[i]) == 1)
327 vector n = mesh_.faceAreas()[eFaces[i]];
328 n /= mag(n) + VSMALL;
336 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
337 << " comparing to edge normal:" << edgeNormal
341 // Found face intersection point on this edge. Compare to edge
343 return indexedOctree<treeDataFace>::getSide
353 // 4] Get the internal edge the face intersection is on
358 pointHit edgeHit = line<point, const point&>
362 ).nearestDist(sample);
364 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
366 // Face intersection point lies on edge between two face triangles
368 // Calculate edge normal as average of the two triangle normals
369 vector e = points[f[fp]] - fc;
370 vector ePrev = points[f[f.rcIndex(fp)]] - fc;
371 vector eNext = points[f[f.fcIndex(fp)]] - fc;
373 vector nLeft = ePrev ^ e;
374 nLeft /= mag(nLeft) + VSMALL;
376 vector nRight = e ^ eNext;
377 nRight /= mag(nRight) + VSMALL;
381 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
382 << " comparing to edge normal "
383 << 0.5*(nLeft + nRight)
387 // Found face intersection point on this edge. Compare to edge
389 return indexedOctree<treeDataFace>::getSide
391 0.5*(nLeft + nRight),
399 Pout<< "Did not find sample " << sample
400 << " anywhere related to nearest face " << faceI << endl
405 Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
410 // Can't determine status of sample with respect to nearest face.
412 // - tolerances are wrong. (if e.g. face has zero area)
413 // - or (more likely) surface is not closed.
415 return indexedOctree<treeDataFace>::UNKNOWN;
419 // Check if any point on shape is inside cubeBb.
420 bool Foam::treeDataFace::overlaps
423 const treeBoundBox& cubeBb
426 // 1. Quick rejection: bb does not intersect face bb at all
429 if (!cubeBb.overlaps(bbs_[index]))
436 if (!cubeBb.overlaps(calcBb(faceLabels_[index])))
442 const pointField& points = mesh_.points();
445 // 2. Check if one or more face points inside
446 label faceI = faceLabels_[index];
448 const face& f = mesh_.faces()[faceI];
449 if (cubeBb.containsAny(points, f))
454 // 3. Difficult case: all points are outside but connecting edges might
455 // go through cube. Use triangle-bounding box intersection.
456 const point& fc = mesh_.faceCentres()[faceI];
460 bool triIntersects = triangleFuncs::intersectBb
463 points[f[f.fcIndex(fp)]],
477 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
479 void Foam::treeDataFace::findNearest
481 const labelUList& indices,
484 scalar& nearestDistSqr,
491 const label index = indices[i];
493 const face& f = mesh_.faces()[faceLabels_[index]];
495 pointHit nearHit = f.nearestPoint(sample, mesh_.points());
496 scalar distSqr = sqr(nearHit.distance());
498 if (distSqr < nearestDistSqr)
500 nearestDistSqr = distSqr;
502 nearestPoint = nearHit.rawPoint();
508 bool Foam::treeDataFace::intersects
513 point& intersectionPoint
516 // Do quick rejection test
519 const treeBoundBox& faceBb = bbs_[index];
521 if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
523 // start and end in same block outside of faceBb.
528 const label faceI = faceLabels_[index];
530 const vector dir(end - start);
532 pointHit inter = mesh_.faces()[faceI].intersection
536 mesh_.faceCentres()[faceI],
538 intersection::HALF_RAY
541 if (inter.hit() && inter.distance() <= 1)
543 // Note: no extra test on whether intersection is in front of us
544 // since using half_ray
545 intersectionPoint = inter.hitPoint();
555 // ************************************************************************* //