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 "treeDataFace.H"
29 #include "triangleFuncs.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 defineTypeNameAndDebug(Foam::treeDataFace, 0);
35 Foam::scalar Foam::treeDataFace::tolSqr = sqr(1E-6);
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 Foam::treeBoundBox Foam::treeDataFace::calcBb(const label faceI) const
42 const pointField& points = mesh_.points();
44 const face& f = mesh_.faces()[faceI];
46 treeBoundBox bb(points[f[0]], points[f[0]]);
48 for (label fp = 1; fp < f.size(); fp++)
50 const point& p = points[f[fp]];
52 bb.min() = min(bb.min(), p);
53 bb.max() = max(bb.max(), p);
59 void Foam::treeDataFace::update()
61 forAll(faceLabels_, i)
63 isTreeFace_.set(faceLabels_[i], 1);
68 bbs_.setSize(faceLabels_.size());
70 forAll(faceLabels_, i)
72 bbs_[i] = calcBb(faceLabels_[i]);
78 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
80 // Construct from components
81 Foam::treeDataFace::treeDataFace
84 const primitiveMesh& mesh,
85 const labelList& faceLabels
89 faceLabels_(faceLabels),
90 isTreeFace_(mesh.nFaces(), 0),
97 Foam::treeDataFace::treeDataFace
100 const primitiveMesh& mesh
104 faceLabels_(identity(mesh_.nFaces())),
105 isTreeFace_(mesh.nFaces(), 0),
112 Foam::treeDataFace::treeDataFace
115 const polyPatch& patch
118 mesh_(patch.boundaryMesh().mesh()),
121 identity(patch.size())
124 isTreeFace_(mesh_.nFaces(), 0),
131 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
133 Foam::pointField Foam::treeDataFace::points() const
135 pointField cc(faceLabels_.size());
137 forAll(faceLabels_, i)
139 cc[i] = mesh_.faceCentres()[faceLabels_[i]];
146 //- Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
147 // Only makes sense for closed surfaces.
148 Foam::label Foam::treeDataFace::getVolumeType
150 const indexedOctree<treeDataFace>& oc,
154 // Need to determine whether sample is 'inside' or 'outside'
155 // Done by finding nearest face. This gives back a face which is
156 // guaranteed to contain nearest point. This point can be
157 // - in interior of face: compare to face normal
158 // - on edge of face: compare to edge normal
159 // - on point of face: compare to point normal
160 // Unfortunately the octree does not give us back the intersection point
161 // or where on the face it has hit so we have to recreate all that
165 // Find nearest face to sample
166 pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
168 if (info.index() == -1)
172 "treeDataFace::getSampleType"
173 "(indexedOctree<treeDataFace>&, const point&)"
174 ) << "Could not find " << sample << " in octree."
175 << abort(FatalError);
179 // Get actual intersection point on face
180 label faceI = faceLabels_[info.index()];
184 Pout<< "getSampleType : sample:" << sample
185 << " nearest face:" << faceI;
188 const pointField& points = mesh_.points();
190 // Retest to classify where on face info is. Note: could be improved. We
191 // already have point.
193 const face& f = mesh_.faces()[faceI];
194 const vector& area = mesh_.faceAreas()[faceI];
195 const point& fc = mesh_.faceCentres()[faceI];
197 pointHit curHit = f.nearestPoint(sample, points);
198 const point& curPt = curHit.rawPoint();
201 // 1] Check whether sample is above face
206 // Nearest point inside face. Compare to face normal.
210 Pout<< " -> face hit:" << curPt
211 << " comparing to face normal " << area << endl;
213 return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
218 Pout<< " -> face miss:" << curPt;
222 // 2] Check whether intersection is on one of the face vertices or
226 const scalar typDimSqr = mag(area) + VSMALL;
230 if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
232 // Face intersection point equals face vertex fp
234 // Calculate point normal (wrong: uses face normals instead of
236 const labelList& pFaces = mesh_.pointFaces()[f[fp]];
238 vector pointNormal(vector::zero);
242 if (isTreeFace_.get(pFaces[i]) == 1)
244 vector n = mesh_.faceAreas()[pFaces[i]];
245 n /= mag(n) + VSMALL;
253 Pout<< " -> face point hit :" << points[f[fp]]
254 << " point normal:" << pointNormal
256 << magSqr(points[f[fp]] - curPt)/typDimSqr << endl;
258 return indexedOctree<treeDataFace>::getSide
265 if ((magSqr(fc - curPt)/typDimSqr) < tolSqr)
267 // Face intersection point equals face centre. Normal at face centre
268 // is already average of face normals
272 Pout<< " -> centre hit:" << fc
273 << " distance:" << magSqr(fc - curPt)/typDimSqr << endl;
276 return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
282 // 3] Get the 'real' edge the face intersection is on
285 const labelList& myEdges = mesh_.faceEdges()[faceI];
287 forAll(myEdges, myEdgeI)
289 const edge& e = mesh_.edges()[myEdges[myEdgeI]];
292 line<point, const point&>
296 ).nearestDist(sample);
299 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
301 // Face intersection point lies on edge e
303 // Calculate edge normal (wrong: uses face normals instead of
305 const labelList& eFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
307 vector edgeNormal(vector::zero);
311 if (isTreeFace_.get(eFaces[i]) == 1)
313 vector n = mesh_.faceAreas()[eFaces[i]];
314 n /= mag(n) + VSMALL;
322 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
323 << " comparing to edge normal:" << edgeNormal
327 // Found face intersection point on this edge. Compare to edge
329 return indexedOctree<treeDataFace>::getSide
339 // 4] Get the internal edge the face intersection is on
344 pointHit edgeHit = line<point, const point&>
348 ).nearestDist(sample);
350 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
352 // Face intersection point lies on edge between two face triangles
354 // Calculate edge normal as average of the two triangle normals
355 vector e = points[f[fp]] - fc;
356 vector ePrev = points[f[f.rcIndex(fp)]] - fc;
357 vector eNext = points[f[f.fcIndex(fp)]] - fc;
359 vector nLeft = ePrev ^ e;
360 nLeft /= mag(nLeft) + VSMALL;
362 vector nRight = e ^ eNext;
363 nRight /= mag(nRight) + VSMALL;
367 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
368 << " comparing to edge normal "
369 << 0.5*(nLeft + nRight)
373 // Found face intersection point on this edge. Compare to edge
375 return indexedOctree<treeDataFace>::getSide
377 0.5*(nLeft + nRight),
385 Pout<< "Did not find sample " << sample
386 << " anywhere related to nearest face " << faceI << endl
391 Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
396 // Can't determine status of sample with respect to nearest face.
398 // - tolerances are wrong. (if e.g. face has zero area)
399 // - or (more likely) surface is not closed.
401 return indexedOctree<treeDataFace>::UNKNOWN;
405 // Check if any point on shape is inside cubeBb.
406 bool Foam::treeDataFace::overlaps
409 const treeBoundBox& cubeBb
412 // 1. Quick rejection: bb does not intersect face bb at all
415 if (!cubeBb.overlaps(bbs_[index]))
422 if (!cubeBb.overlaps(calcBb(faceLabels_[index])))
428 const pointField& points = mesh_.points();
431 // 2. Check if one or more face points inside
432 label faceI = faceLabels_[index];
434 const face& f = mesh_.faces()[faceI];
438 if (cubeBb.contains(points[f[fp]]))
444 // 3. Difficult case: all points are outside but connecting edges might
445 // go through cube. Use triangle-bounding box intersection.
446 const point& fc = mesh_.faceCentres()[faceI];
450 bool triIntersects = triangleFuncs::intersectBb
453 points[f[f.fcIndex(fp)]],
467 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
469 void Foam::treeDataFace::findNearest
471 const labelList& indices,
474 scalar& nearestDistSqr,
481 label index = indices[i];
483 const face& f = mesh_.faces()[faceLabels_[index]];
485 pointHit nearHit = f.nearestPoint(sample, mesh_.points());
486 scalar distSqr = sqr(nearHit.distance());
488 if (distSqr < nearestDistSqr)
490 nearestDistSqr = distSqr;
492 nearestPoint = nearHit.rawPoint();
498 bool Foam::treeDataFace::intersects
503 point& intersectionPoint
506 // Do quick rejection test
509 const treeBoundBox& faceBb = bbs_[index];
511 if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
513 // start and end in same block outside of faceBb.
518 label faceI = faceLabels_[index];
520 const vector dir(end - start);
522 pointHit inter = mesh_.faces()[faceI].fastIntersection
526 mesh_.faceCentres()[faceI],
528 intersection::HALF_RAY
531 if (inter.hit() && inter.distance() <= 1)
533 // Note: no extra test on whether intersection is in front of us
534 // since using half_ray
535 intersectionPoint = inter.hitPoint();
545 // ************************************************************************* //