Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / applications / utilities / surface / surfaceToPatch / treeDataPrimitivePatch.C
blob7b3a555ebb85ea1c1b3d31adf9982178adb21454
1 /*---------------------------------------------------------------------------*\
2   =========                 |
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 -------------------------------------------------------------------------------
8 License
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 * * * * * * * * * * * * * //
32 template
34     class Face,
35     template<class> class FaceList,
36     class PointField,
37     class PointType
39 Foam::scalar
40 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
41 tolSqr = sqr(1E-6);
44 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
46 template
48     class Face,
49     template<class> class FaceList,
50     class PointField,
51     class PointType
53 Foam::treeBoundBox
54 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
55 calcBb
57     const pointField& points,
58     const face& f
61     treeBoundBox bb(points[f[0]], points[f[0]]);
63     for (label fp = 1; fp < f.size(); fp++)
64     {
65         const point& p = points[f[fp]];
67         bb.min() = min(bb.min(), p);
68         bb.max() = max(bb.max(), p);
69     }
70     return bb;
74 template
76     class Face,
77     template<class> class FaceList,
78     class PointField,
79     class PointType
81 void Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
82 update()
84     if (cacheBb_)
85     {
86         bbs_.setSize(patch_.size());
88         forAll(patch_, i)
89         {
90             bbs_[i] = calcBb(patch_.points(), patch_[i]);
91         }
92     }
96 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
98 // Construct from components
99 template
101     class Face,
102     template<class> class FaceList,
103     class PointField,
104     class PointType
106 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
107 treeDataPrimitivePatch
109     const bool cacheBb,
110     const PrimitivePatch<Face, FaceList, PointField, PointType>& patch
113     patch_(patch),
114     cacheBb_(cacheBb)
116     update();
120 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
122 template
124     class Face,
125     template<class> class FaceList,
126     class PointField,
127     class PointType
129 Foam::pointField
130 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
131 points() const
133     pointField cc(patch_.size());
135     forAll(patch_, i)
136     {
137         cc[i] = patch_[i].centre(patch_.points());
138     }
140     return cc;
144 //- Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
145 //  Only makes sense for closed surfaces.
146 template
148     class Face,
149     template<class> class FaceList,
150     class PointField,
151     class PointType
153 Foam::label
154 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
155 getVolumeType
157     const indexedOctree
158     <
159         treeDataPrimitivePatch
160         <
161             Face,
162             FaceList,
163             PointField,
164             PointType
165         >
166     >& oc,
167     const point& sample
168 ) const
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
178     // information.
181     // Find nearest face to sample
182     pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
184     if (info.index() == -1)
185     {
186         FatalErrorIn
187         (
188             "treeDataPrimitivePatch::getSampleType"
189             "(indexedOctree<treeDataPrimitivePatch>&, const point&)"
190         )   << "Could not find " << sample << " in octree."
191             << abort(FatalError);
192     }
195     // Get actual intersection point on face
196     label faceI = info.index();
198     if (debug & 2)
199     {
200         Pout<< "getSampleType : sample:" << sample
201             << " nearest face:" << faceI;
202     }
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();
214     //
215     // 1] Check whether sample is above face
216     //
218     if (curHit.hit())
219     {
220         // Nearest point inside face. Compare to face normal.
222         if (debug & 2)
223         {
224             Pout<< " -> face hit:" << curPt
225                 << " comparing to face normal " << area << endl;
226         }
227         return indexedOctree<treeDataPrimitivePatch>::getSide
228         (
229             area,
230             sample - curPt
231         );
232     }
234     if (debug & 2)
235     {
236         Pout<< " -> face miss:" << curPt;
237     }
239     //
240     // 2] Check whether intersection is on one of the face vertices or
241     //    face centre
242     //
244     const scalar typDimSqr = mag(area) + VSMALL;
246     forAll(f, fp)
247     {
248         if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
249         {
250             // Face intersection point equals face vertex fp
252             // Calculate point normal (wrong: uses face normals instead of
253             // triangle normals)
255             return indexedOctree<treeDataPrimitivePatch>::getSide
256             (
257                 patch_.pointNormals()[f[fp]],
258                 sample - curPt
259             );
260         }
261     }
263     const point fc(f.centre(points));
265     if ((magSqr(fc - curPt)/typDimSqr) < tolSqr)
266     {
267         // Face intersection point equals face centre. Normal at face centre
268         // is already average of face normals
270         if (debug & 2)
271         {
272             Pout<< " -> centre hit:" << fc
273                 << " distance:" << magSqr(fc - curPt)/typDimSqr << endl;
274         }
276         return indexedOctree<treeDataPrimitivePatch>::getSide
277         (
278             area,
279             sample - curPt
280         );
281     }
285     //
286     // 3] Get the 'real' edge the face intersection is on
287     //
289     const labelList& fEdges = patch_.faceEdges()[faceI];
291     forAll(fEdges, fEdgeI)
292     {
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)
299         {
300             // Face intersection point lies on edge e
302             // Calculate edge normal (wrong: uses face normals instead of
303             // triangle normals)
304             const labelList& eFaces = patch_.edgeFaces()[edgeI];
306             vector edgeNormal(vector::zero);
308             forAll(eFaces, i)
309             {
310                 edgeNormal += patch_.faceNormal()[eFaces[i]];
311             }
313             if (debug & 2)
314             {
315                 Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
316                     << " comparing to edge normal:" << edgeNormal
317                     << endl;
318             }
320             // Found face intersection point on this edge. Compare to edge
321             // normal
322             return indexedOctree<treeDataPrimitivePatch>::getSide
323             (
324                 edgeNormal,
325                 sample - curPt
326             );
327         }
328     }
331     //
332     // 4] Get the internal edge the face intersection is on
333     //
335     forAll(f, fp)
336     {
337         pointHit edgeHit = linePointRef
338         (
339             points[f[fp]],
340             fc
341         ).nearestDist(sample);
343         if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
344         {
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;
358             if (debug & 2)
359             {
360                 Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
361                     << " comparing to edge normal "
362                     << 0.5*(nLeft + nRight)
363                     << endl;
364             }
366             // Found face intersection point on this edge. Compare to edge
367             // normal
368             return indexedOctree<treeDataPrimitivePatch>::getSide
369             (
370                 0.5*(nLeft + nRight),
371                 sample - curPt
372             );
373         }
374     }
376     if (debug & 2)
377     {
378         Pout<< "Did not find sample " << sample
379             << " anywhere related to nearest face " << faceI << endl
380             << "Face:";
382         forAll(f, fp)
383         {
384             Pout<< "    vertex:" << f[fp] << "  coord:" << points[f[fp]]
385                 << endl;
386         }
387     }
389     // Can't determine status of sample with respect to nearest face.
390     // Either
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.
399 template
401     class Face,
402     template<class> class FaceList,
403     class PointField,
404     class PointType
406 bool
407 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
408 overlaps
410     const label index,
411     const treeBoundBox& cubeBb
412 ) const
414     // 1. Quick rejection: bb does not intersect face bb at all
415     if (cacheBb_)
416     {
417         if (!cubeBb.overlaps(bbs_[index]))
418         {
419             return false;
420         }
421     }
422     else
423     {
424         if (!cubeBb.overlaps(calcBb(patch_.points(), patch_[index])))
425         {
426             return false;
427         }
428     }
431     // 2. Check if one or more face points inside
433     const pointField& points = patch_.points();
434     const face& f = patch_[index];
436     forAll(f, fp)
437     {
438         if (cubeBb.contains(points[f[fp]]))
439         {
440             return true;
441         }
442     }
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);
448     forAll(f, fp)
449     {
450         bool triIntersects = triangleFuncs::intersectBb
451         (
452             points[f[fp]],
453             points[f[f.fcIndex(fp)]],
454             fc,
455             cubeBb
456         );
458         if (triIntersects)
459         {
460             return true;
461         }
462     }
463     return false;
467 // Calculate nearest point to sample. Updates (if any) nearestDistSqr, minIndex,
468 // nearestPoint.
469 template
471     class Face,
472     template<class> class FaceList,
473     class PointField,
474     class PointType
476 void
477 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
478 findNearest
480     const labelList& indices,
481     const point& sample,
483     scalar& nearestDistSqr,
484     label& minIndex,
485     point& nearestPoint
486 ) const
488     const pointField& points = patch_.points();
490     forAll(indices, i)
491     {
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)
500         {
501             nearestDistSqr = distSqr;
502             minIndex = index;
503             nearestPoint = nearHit.rawPoint();
504         }
505     }
509 template
511     class Face,
512     template<class> class FaceList,
513     class PointField,
514     class PointType
516 bool
517 Foam::treeDataPrimitivePatch<Face, FaceList, PointField, PointType>::
518 intersects
520     const label index,
521     const point& start,
522     const point& end,
523     point& intersectionPoint
524 ) const
526     // Do quick rejection test
527     if (cacheBb_)
528     {
529         const treeBoundBox& faceBb = bbs_[index];
531         if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
532         {
533             // start and end in same block outside of faceBb.
534             return false;
535         }
536     }
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
544     (
545         start,
546         dir,
547         fc,
548         points,
549         intersection::HALF_RAY
550     );
552     if (inter.hit() && inter.distance() <= 1)
553     {
554         // Note: no extra test on whether intersection is in front of us
555         // since using half_ray
556         intersectionPoint = inter.hitPoint();
557         return true;
558     }
559     else
560     {
561         return false;
562     }
566 // ************************************************************************* //