1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "treeDataPrimitivePatch.H"
27 #include "indexedOctree.H"
28 #include "triangleFuncs.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 template<class> class FaceList,
40 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 template<class> class FaceList,
54 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
57 const pointField& points,
61 treeBoundBox bb(points[f[0]], points[f[0]]);
63 for (label fp = 1; fp < f.size(); fp++)
65 const point& p = points[f[fp]];
67 bb.min() = min(bb.min(), p);
68 bb.max() = max(bb.max(), p);
77 template<class> class FaceList,
81 void Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
86 bbs_.setSize(patch_.size());
90 bbs_[i] = calcBb(patch_.points(), patch_[i]);
96 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
98 // Construct from components
102 template<class> class FaceList,
106 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
107 treeDataPrimitivePatch
110 const PrimitivePatch<Face, FaceList, PointField, PointType>& patch
120 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
125 template<class> class FaceList,
130 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
133 pointField cc(patch_.size());
137 cc[i] = patch_[i].centre(patch_.points());
144 //- Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
145 // Only makes sense for closed surfaces.
149 template<class> class FaceList,
154 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
159 treeDataPrimitivePatch
170 // Need to determine whether sample is 'inside' or 'outside'
171 // Done by finding nearest face. This gives back a face which is
172 // guaranteed to contain nearest point. This point can be
173 // - in interior of face: compare to face normal
174 // - on edge of face: compare to edge normal
175 // - on point of face: compare to point normal
176 // Unfortunately the octree does not give us back the intersection point
177 // or where on the face it has hit so we have to recreate all that
181 // Find nearest face to sample
182 pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
184 if (info.index() == -1)
188 "treeDataPrimitivePatch::getSampleType"
189 "(indexedOctree<treeDataPrimitivePatch>&, const point&)"
190 ) << "Could not find " << sample << " in octree."
191 << abort(FatalError);
195 // Get actual intersection point on face
196 label faceI = info.index();
200 Pout<< "getSampleType : sample:" << sample
201 << " nearest face:" << faceI;
204 const pointField& points = patch_.localPoints();
205 const face& f = patch_.localFaces()[faceI];
207 // Retest to classify where on face info is. Note: could be improved. We
208 // already have point.
210 pointHit curHit = f.nearestPoint(sample, points);
211 const vector area = f.normal(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<treeDataPrimitivePatch>::getSide
236 Pout<< " -> face miss:" << curPt;
240 // 2] Check whether intersection is on one of the face vertices or
244 const scalar typDimSqr = mag(area) + VSMALL;
248 if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
250 // Face intersection point equals face vertex fp
252 // Calculate point normal (wrong: uses face normals instead of
255 return indexedOctree<treeDataPrimitivePatch>::getSide
257 patch_.pointNormals()[f[fp]],
263 const point fc(f.centre(points));
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<treeDataPrimitivePatch>::getSide
286 // 3] Get the 'real' edge the face intersection is on
289 const labelList& fEdges = patch_.faceEdges()[faceI];
291 forAll(fEdges, fEdgeI)
293 label edgeI = fEdges[fEdgeI];
294 const edge& e = patch_.edges()[edgeI];
296 pointHit edgeHit = e.line(points).nearestDist(sample);
298 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
300 // Face intersection point lies on edge e
302 // Calculate edge normal (wrong: uses face normals instead of
304 const labelList& eFaces = patch_.edgeFaces()[edgeI];
306 vector edgeNormal(vector::zero);
310 edgeNormal += patch_.faceNormal()[eFaces[i]];
315 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
316 << " comparing to edge normal:" << edgeNormal
320 // Found face intersection point on this edge. Compare to edge
322 return indexedOctree<treeDataPrimitivePatch>::getSide
332 // 4] Get the internal edge the face intersection is on
337 pointHit edgeHit = linePointRef
341 ).nearestDist(sample);
343 if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
345 // Face intersection point lies on edge between two face triangles
347 // Calculate edge normal as average of the two triangle normals
348 vector e = points[f[fp]] - fc;
349 vector ePrev = points[f[f.rcIndex(fp)]] - fc;
350 vector eNext = points[f[f.fcIndex(fp)]] - fc;
352 vector nLeft = ePrev ^ e;
353 nLeft /= mag(nLeft) + VSMALL;
355 vector nRight = e ^ eNext;
356 nRight /= mag(nRight) + VSMALL;
360 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
361 << " comparing to edge normal "
362 << 0.5*(nLeft + nRight)
366 // Found face intersection point on this edge. Compare to edge
368 return indexedOctree<treeDataPrimitivePatch>::getSide
370 0.5*(nLeft + nRight),
378 Pout<< "Did not find sample " << sample
379 << " anywhere related to nearest face " << faceI << endl
384 Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
389 // Can't determine status of sample with respect to nearest face.
391 // - tolerances are wrong. (if e.g. face has zero area)
392 // - or (more likely) surface is not closed.
394 return indexedOctree<treeDataPrimitivePatch>::UNKNOWN;
398 // Check if any point on shape is inside cubeBb.
402 template<class> class FaceList,
407 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
411 const treeBoundBox& cubeBb
414 // 1. Quick rejection: bb does not intersect face bb at all
417 if (!cubeBb.overlaps(bbs_[index]))
424 if (!cubeBb.overlaps(calcBb(patch_.points(), patch_[index])))
431 // 2. Check if one or more face points inside
433 const pointField& points = patch_.points();
434 const face& f = patch_[index];
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 = f.centre(points);
450 bool triIntersects = triangleFuncs::intersectBb
453 points[f[f.fcIndex(fp)]],
467 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
472 template<class> class FaceList,
477 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
480 const labelList& indices,
483 scalar& nearestDistSqr,
488 const pointField& points = patch_.points();
492 label index = indices[i];
494 const face& f = patch_[index];
496 pointHit nearHit = f.nearestPoint(sample, points);
497 scalar distSqr = sqr(nearHit.distance());
499 if (distSqr < nearestDistSqr)
501 nearestDistSqr = distSqr;
503 nearestPoint = nearHit.rawPoint();
512 template<class> class FaceList,
517 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
523 point& intersectionPoint
526 // Do quick rejection test
529 const treeBoundBox& faceBb = bbs_[index];
531 if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
533 // start and end in same block outside of faceBb.
538 const pointField& points = patch_.points();
539 const face& f = patch_[index];
540 const point fc = f.centre(points);
541 const vector dir(end - start);
543 pointHit inter = patch_[index].intersection
549 intersection::HALF_RAY
552 if (inter.hit() && inter.distance() <= 1)
554 // Note: no extra test on whether intersection is in front of us
555 // since using half_ray
556 intersectionPoint = inter.hitPoint();
566 // ************************************************************************* //