1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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/>.
26 \*---------------------------------------------------------------------------*/
28 #include "octreeDataFaceList.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 defineTypeNameAndDebug(Foam::octreeDataFaceList, 0);
35 Foam::scalar Foam::octreeDataFaceList::tol = 1E-6;
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 void Foam::octreeDataFaceList::calcBb()
42 allBb_.setSize(faceLabels_.size());
45 vector(GREAT, GREAT, GREAT),
46 vector(-GREAT, -GREAT, -GREAT)
49 forAll (faceLabels_, faceLabelI)
51 label faceI = faceLabels_[faceLabelI];
54 treeBoundBox& myBb = allBb_[faceLabelI];
56 const face& f = mesh_.localFaces()[faceI];
60 const point& coord = mesh_.localPoints()[f[fp]];
62 myBb.min() = min(myBb.min(), coord);
63 myBb.max() = max(myBb.max(), coord);
68 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
70 // Construct from all faces in bMesh
71 Foam::octreeDataFaceList::octreeDataFaceList(const bMesh& mesh)
74 faceLabels_(mesh_.size()),
77 forAll(faceLabels_, faceI)
79 faceLabels_[faceI] = faceI;
82 // Generate tight fitting bounding box
87 // Construct from selected faces in bMesh
88 Foam::octreeDataFaceList::octreeDataFaceList
91 const labelList& faceLabels
95 faceLabels_(faceLabels),
96 allBb_(faceLabels.size())
98 // Generate tight fitting bounding box
105 Foam::octreeDataFaceList::octreeDataFaceList(const octreeDataFaceList& shapes)
107 mesh_(shapes.mesh()),
108 faceLabels_(shapes.faceLabels()),
109 allBb_(shapes.allBb())
113 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
115 Foam::octreeDataFaceList::~octreeDataFaceList()
119 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122 Foam::label Foam::octreeDataFaceList::getSampleType
124 const octree<octreeDataFaceList>& oc,
128 // Need to determine whether sample is 'inside' or 'outside'
129 // Done by finding nearest face. This gives back a face which is
130 // guaranteed to contain nearest point. This point can be
131 // - in interior of face: compare to face normal
132 // - on edge of face: compare to edge normal
133 // - on point of face: compare to point normal
134 // Unfortunately the octree does not give us back the intersection point
135 // or where on the face it has hit so we have to recreate all that
139 // Find nearest face to sample
140 treeBoundBox tightest(treeBoundBox::greatBox);
142 scalar tightestDist = GREAT;
144 label index = oc.findNearest(sample, tightest, tightestDist);
150 "octreeDataFaceList::getSampleType"
151 "(octree<octreeDataFaceList>&, const point&)"
152 ) << "Could not find " << sample << " in octree."
153 << abort(FatalError);
156 label faceI = faceLabels_[index];
158 // Get actual intersection point on face
162 Pout<< "getSampleType : sample:" << sample
163 << " nearest face:" << faceI;
166 const face& f = mesh_.localFaces()[faceI];
168 const pointField& points = mesh_.localPoints();
170 pointHit curHit = f.nearestPoint(sample, points);
173 // 1] Check whether sample is above face
178 // Simple case. Compare to face normal.
182 Pout<< " -> face hit:" << curHit.hitPoint()
183 << " comparing to face normal " << mesh_.faceNormals()[faceI]
186 return octree<octreeDataFaceList>::getVolType
188 mesh_.faceNormals()[faceI],
189 sample - curHit.hitPoint()
195 Pout<< " -> face miss:" << curHit.missPoint();
199 // 2] Check whether intersection is on one of the face vertices or
203 // typical dimension as sqrt of face area.
204 scalar typDim = sqrt(mag(f.normal(points))) + VSMALL;
208 if ((mag(points[f[fp]] - curHit.missPoint())/typDim) < tol)
210 // Face intersection point equals face vertex fp
214 Pout<< " -> face point hit :" << points[f[fp]]
215 << " point normal:" << mesh_.pointNormals()[f[fp]]
217 << mag(points[f[fp]] - curHit.missPoint())/typDim
220 return octree<octreeDataFaceList>::getVolType
222 mesh_.pointNormals()[f[fp]],
223 sample - curHit.missPoint()
229 point ctr(f.centre(points));
231 if ((mag(ctr - curHit.missPoint())/typDim) < tol)
233 // Face intersection point equals face centre. Normal at face centre
234 // is already average of face normals
238 Pout<< " -> centre hit:" << ctr
240 << mag(ctr - curHit.missPoint())/typDim
244 return octree<octreeDataFaceList>::getVolType
246 mesh_.faceNormals()[faceI],
247 sample - curHit.missPoint()
253 // 3] Get the 'real' edge the face intersection is on
256 const labelList& myEdges = mesh_.faceEdges()[faceI];
258 forAll(myEdges, myEdgeI)
260 const edge& e = mesh_.edges()[myEdges[myEdgeI]];
263 line<point, const point&>
267 ).nearestDist(sample);
272 edgePoint = edgeHit.hitPoint();
276 edgePoint = edgeHit.missPoint();
280 if ((mag(edgePoint - curHit.missPoint())/typDim) < tol)
282 // Face intersection point lies on edge e
284 // Calculate edge normal (wrong: uses face normals instead of
286 const labelList& myFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
288 vector edgeNormal(vector::zero);
290 forAll(myFaces, myFaceI)
292 edgeNormal += mesh_.faceNormals()[myFaces[myFaceI]];
297 Pout<< " -> real edge hit point:" << edgePoint
298 << " comparing to edge normal:" << edgeNormal
302 // Found face intersection point on this edge. Compare to edge
304 return octree<octreeDataFaceList>::getVolType
307 sample - curHit.missPoint()
314 // 4] Get the internal edge (vertex - faceCentre) the face intersection
321 line<point, const point&>
325 ).nearestDist(sample);
330 edgePoint = edgeHit.hitPoint();
334 edgePoint = edgeHit.missPoint();
337 if ((mag(edgePoint - curHit.missPoint())/typDim) < tol)
339 // Face intersection point lies on edge between two face triangles
341 // Calculate edge normal as average of the two triangle normals
342 label fpPrev = f.rcIndex(fp);
343 label fpNext = f.fcIndex(fp);
345 vector e = points[f[fp]] - ctr;
346 vector ePrev = points[f[fpPrev]] - ctr;
347 vector eNext = points[f[fpNext]] - ctr;
349 vector nLeft = ePrev ^ e;
350 nLeft /= mag(nLeft) + VSMALL;
352 vector nRight = e ^ eNext;
353 nRight /= mag(nRight) + VSMALL;
357 Pout<< " -> internal edge hit point:" << edgePoint
358 << " comparing to edge normal "
359 << 0.5*(nLeft + nRight)
363 // Found face intersection point on this edge. Compare to edge
365 return octree<octreeDataFaceList>::getVolType
367 0.5*(nLeft + nRight),
368 sample - curHit.missPoint()
375 Pout<< "Did not find sample " << sample
376 << " anywhere related to nearest face " << faceI << endl
381 Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
386 // Can't determine status of sample with respect to nearest face.
388 // - tolerances are wrong. (if e.g. face has zero area)
389 // - or (more likely) surface is not closed.
391 return octree<octreeDataFaceList>::UNKNOWN;
395 bool Foam::octreeDataFaceList::overlaps
398 const treeBoundBox& sampleBb
401 return sampleBb.overlaps(allBb_[index]);
405 bool Foam::octreeDataFaceList::contains
413 "octreeDataFaceList::contains(const label, const point&)"
419 bool Foam::octreeDataFaceList::intersects
424 point& intersectionPoint
427 label faceI = faceLabels_[index];
429 const face& f = mesh_.localFaces()[faceI];
431 const vector dir(end - start);
433 // Disable picking up intersections behind us.
434 scalar oldTol = intersection::setPlanarTol(0.0);
442 intersection::HALF_RAY,
446 intersection::setPlanarTol(oldTol);
448 if (inter.hit() && inter.distance() <= mag(dir))
450 intersectionPoint = inter.hitPoint();
461 bool Foam::octreeDataFaceList::findTightest
465 treeBoundBox& tightest
468 // Get nearest and furthest away vertex
470 allBb_[index].calcExtremities(sample, myNear, myFar);
472 const point dist = myFar - sample;
473 scalar myFarDist = mag(dist);
475 point tightestNear, tightestFar;
476 tightest.calcExtremities(sample, tightestNear, tightestFar);
478 scalar tightestFarDist = mag(tightestFar - sample);
480 if (tightestFarDist < myFarDist)
482 // Keep current tightest.
487 // Construct bb around sample and myFar
488 const point dist2(fabs(dist.x()), fabs(dist.y()), fabs(dist.z()));
490 tightest.min() = sample - dist2;
491 tightest.max() = sample + dist2;
498 // Determine numerical value of sign of sample compared to shape at index
499 Foam::scalar Foam::octreeDataFaceList::calcSign
506 label faceI = faceLabels_[index];
508 const face& f = mesh_.localFaces()[faceI];
510 point ctr = f.centre(mesh_.localPoints());
512 vector vec = sample - ctr;
514 vec /= mag(vec) + VSMALL;
516 return mesh_.faceNormals()[faceI] & vec;
520 // Calculate nearest point on/in shapei
521 Foam::scalar Foam::octreeDataFaceList::calcNearest
528 label faceI = faceLabels_[index];
530 const face& f = mesh_.localFaces()[faceI];
532 pointHit nearHit = f.nearestPoint(sample, mesh_.localPoints());
536 nearest = nearHit.hitPoint();
540 nearest = nearHit.missPoint();
545 point ctr = f.centre(mesh_.localPoints());
547 scalar sign = mesh_.faceNormals()[faceI] & (sample - nearest);
549 Pout<< "octreeDataFaceList::calcNearest : "
550 << "sample:" << sample
551 << " faceI:" << faceI
554 << " nearest point:" << nearest
555 << " distance to face:" << nearHit.distance()
558 return nearHit.distance();
562 void Foam::octreeDataFaceList::write
568 os << faceLabels_[index] << " " << allBb_[index];
572 // ************************************************************************* //