treeDataFace.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2017-2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "treeDataFace.H"
30 #include "polyMesh.H"
31 #include "triangleFuncs.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37  defineTypeNameAndDebug(treeDataFace, 0);
38 
39  scalar treeDataFace::tolSqr = sqr(1e-6);
40 }
41 
42 
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 
45 Foam::treeBoundBox Foam::treeDataFace::calcBb(const label facei) const
46 {
47  return treeBoundBox(mesh_.points(), mesh_.faces()[facei]);
48 }
49 
50 
51 void Foam::treeDataFace::update()
52 {
53  isTreeFace_.set(faceLabels_);
54 
55  if (cacheBb_)
56  {
57  bbs_.setSize(faceLabels_.size());
58 
59  forAll(faceLabels_, i)
60  {
61  bbs_[i] = calcBb(faceLabels_[i]);
62  }
63  }
64 }
65 
66 
67 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
68 
70 (
71  const bool cacheBb,
72  const primitiveMesh& mesh,
73  const labelUList& faceLabels
74 )
75 :
76  mesh_(mesh),
77  faceLabels_(faceLabels),
78  isTreeFace_(mesh.nFaces(), false),
79  cacheBb_(cacheBb)
80 {
81  update();
82 }
83 
84 
86 (
87  const bool cacheBb,
88  const primitiveMesh& mesh,
89  labelList&& faceLabels
90 )
91 :
92  mesh_(mesh),
93  faceLabels_(std::move(faceLabels)),
94  isTreeFace_(mesh.nFaces(), false),
95  cacheBb_(cacheBb)
96 {
97  update();
98 }
99 
100 
102 (
103  const bool cacheBb,
104  const primitiveMesh& mesh
105 )
106 :
107  mesh_(mesh),
108  faceLabels_(identity(mesh_.nFaces())),
109  isTreeFace_(mesh.nFaces(), false),
110  cacheBb_(cacheBb)
111 {
112  update();
113 }
114 
115 
117 (
118  const bool cacheBb,
119  const polyPatch& patch
120 )
121 :
122  mesh_(patch.boundaryMesh().mesh()),
123  faceLabels_
124  (
125  identity(patch.size(), patch.start())
126  ),
127  isTreeFace_(mesh_.nFaces(), false),
128  cacheBb_(cacheBb)
129 {
130  update();
131 }
132 
133 
135 (
136  const indexedOctree<treeDataFace>& tree
137 )
138 :
139  tree_(tree)
140 {}
141 
142 
144 (
145  const indexedOctree<treeDataFace>& tree
146 )
147 :
148  tree_(tree)
149 {}
150 
151 
152 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
153 
155 {
156  pointField cc(faceLabels_.size());
157 
158  forAll(faceLabels_, i)
159  {
160  cc[i] = mesh_.faceCentres()[faceLabels_[i]];
161  }
162 
163  return cc;
164 }
165 
166 
168 (
169  const indexedOctree<treeDataFace>& oc,
170  const point& sample
171 ) const
172 {
173  // Need to determine whether sample is 'inside' or 'outside'
174  // Done by finding nearest face. This gives back a face which is
175  // guaranteed to contain nearest point. This point can be
176  // - in interior of face: compare to face normal
177  // - on edge of face: compare to edge normal
178  // - on point of face: compare to point normal
179  // Unfortunately the octree does not give us back the intersection point
180  // or where on the face it has hit so we have to recreate all that
181  // information.
182 
183 
184  // Find nearest face to sample
185  pointIndexHit info = oc.findNearest(sample, sqr(GREAT));
186 
187  if (info.index() == -1)
188  {
190  << "Could not find " << sample << " in octree."
191  << abort(FatalError);
192  }
193 
194 
195  // Get actual intersection point on face
196  label facei = faceLabels_[info.index()];
197 
198  if (debug & 2)
199  {
200  Pout<< "getSampleType : sample:" << sample
201  << " nearest face:" << facei;
202  }
203 
204  const pointField& points = mesh_.points();
205 
206  // Retest to classify where on face info is. Note: could be improved. We
207  // already have point.
208 
209  const face& f = mesh_.faces()[facei];
210  const vector& area = mesh_.faceAreas()[facei];
211  const point& fc = mesh_.faceCentres()[facei];
212 
213  pointHit curHit = f.nearestPoint(sample, points);
214  const point& curPt = curHit.rawPoint();
215 
216  //
217  // 1] Check whether sample is above face
218  //
219 
220  if (curHit.hit())
221  {
222  // Nearest point inside face. Compare to face normal.
223 
224  if (debug & 2)
225  {
226  Pout<< " -> face hit:" << curPt
227  << " comparing to face normal " << area << endl;
228  }
229  return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
230  }
231 
232  if (debug & 2)
233  {
234  Pout<< " -> face miss:" << curPt;
235  }
236 
237  //
238  // 2] Check whether intersection is on one of the face vertices or
239  // face centre
240  //
241 
242  const scalar typDimSqr = mag(area) + VSMALL;
243 
244  forAll(f, fp)
245  {
246  if ((magSqr(points[f[fp]] - curPt)/typDimSqr) < tolSqr)
247  {
248  // Face intersection point equals face vertex fp
249 
250  // Calculate point normal (wrong: uses face normals instead of
251  // triangle normals)
252  const labelList& pFaces = mesh_.pointFaces()[f[fp]];
253 
254  vector pointNormal(Zero);
255 
256  for (const label facei : pFaces)
257  {
258  if (isTreeFace_.test(facei))
259  {
260  pointNormal += normalised(mesh_.faceAreas()[facei]);
261  }
262  }
263 
264  if (debug & 2)
265  {
266  Pout<< " -> face point hit :" << points[f[fp]]
267  << " point normal:" << pointNormal
268  << " distance:"
269  << magSqr(points[f[fp]] - curPt)/typDimSqr << endl;
270  }
272  (
273  pointNormal,
274  sample - curPt
275  );
276  }
277  }
278  if ((magSqr(fc - curPt)/typDimSqr) < tolSqr)
279  {
280  // Face intersection point equals face centre. Normal at face centre
281  // is already average of face normals
282 
283  if (debug & 2)
284  {
285  Pout<< " -> centre hit:" << fc
286  << " distance:" << magSqr(fc - curPt)/typDimSqr << endl;
287  }
288 
289  return indexedOctree<treeDataFace>::getSide(area, sample - curPt);
290  }
291 
292 
293 
294  //
295  // 3] Get the 'real' edge the face intersection is on
296  //
297 
298  const labelList& myEdges = mesh_.faceEdges()[facei];
299 
300  forAll(myEdges, myEdgeI)
301  {
302  const edge& e = mesh_.edges()[myEdges[myEdgeI]];
303 
304  pointHit edgeHit =
306  (
307  points[e.start()],
308  points[e.end()]
309  ).nearestDist(sample);
310 
311 
312  if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
313  {
314  // Face intersection point lies on edge e
315 
316  // Calculate edge normal (wrong: uses face normals instead of
317  // triangle normals)
318  const labelList& eFaces = mesh_.edgeFaces()[myEdges[myEdgeI]];
319 
320  vector edgeNormal(Zero);
321 
322  for (const label facei : eFaces)
323  {
324  if (isTreeFace_.test(facei))
325  {
326  edgeNormal += normalised(mesh_.faceAreas()[facei]);
327  }
328  }
329 
330  if (debug & 2)
331  {
332  Pout<< " -> real edge hit point:" << edgeHit.rawPoint()
333  << " comparing to edge normal:" << edgeNormal
334  << endl;
335  }
336 
337  // Found face intersection point on this edge. Compare to edge
338  // normal
340  (
341  edgeNormal,
342  sample - curPt
343  );
344  }
345  }
346 
347 
348  //
349  // 4] Get the internal edge the face intersection is on
350  //
351 
352  forAll(f, fp)
353  {
355  (
356  points[f[fp]],
357  fc
358  ).nearestDist(sample);
359 
360  if ((magSqr(edgeHit.rawPoint() - curPt)/typDimSqr) < tolSqr)
361  {
362  // Face intersection point lies on edge between two face triangles
363 
364  // Calculate edge normal as average of the two triangle normals
365  vector e = points[f[fp]] - fc;
366  vector ePrev = points[f[f.rcIndex(fp)]] - fc;
367  vector eNext = points[f[f.fcIndex(fp)]] - fc;
368 
369  vector nLeft = normalised(ePrev ^ e);
370  vector nRight = normalised(e ^ eNext);
371 
372  if (debug & 2)
373  {
374  Pout<< " -> internal edge hit point:" << edgeHit.rawPoint()
375  << " comparing to edge normal "
376  << 0.5*(nLeft + nRight)
377  << endl;
378  }
379 
380  // Found face intersection point on this edge. Compare to edge
381  // normal
383  (
384  0.5*(nLeft + nRight),
385  sample - curPt
386  );
387  }
388  }
389 
390  if (debug & 2)
391  {
392  Pout<< "Did not find sample " << sample
393  << " anywhere related to nearest face " << facei << endl
394  << "Face:";
395 
396  forAll(f, fp)
397  {
398  Pout<< " vertex:" << f[fp] << " coord:" << points[f[fp]]
399  << endl;
400  }
401  }
402 
403  // Can't determine status of sample with respect to nearest face.
404  // Either
405  // - tolerances are wrong. (if e.g. face has zero area)
406  // - or (more likely) surface is not closed.
407 
408  return volumeType::UNKNOWN;
409 }
410 
411 
412 // Check if any point on shape is inside cubeBb.
414 (
415  const label index,
416  const treeBoundBox& cubeBb
417 ) const
418 {
419  // 1. Quick rejection: bb does not intersect face bb at all
420  if (cacheBb_)
421  {
422  if (!cubeBb.overlaps(bbs_[index]))
423  {
424  return false;
425  }
426  }
427  else
428  {
429  if (!cubeBb.overlaps(calcBb(faceLabels_[index])))
430  {
431  return false;
432  }
433  }
434 
435  const pointField& points = mesh_.points();
436 
437 
438  // 2. Check if one or more face points inside
439  label facei = faceLabels_[index];
440 
441  const face& f = mesh_.faces()[facei];
442  if (cubeBb.containsAny(points, f))
443  {
444  return true;
445  }
446 
447  // 3. Difficult case: all points are outside but connecting edges might
448  // go through cube. Use triangle-bounding box intersection.
449  const point& fc = mesh_.faceCentres()[facei];
450 
451  forAll(f, fp)
452  {
453  bool triIntersects = triangleFuncs::intersectBb
454  (
455  points[f[fp]],
456  points[f[f.fcIndex(fp)]],
457  fc,
458  cubeBb
459  );
460 
461  if (triIntersects)
462  {
463  return true;
464  }
465  }
466 
467  return false;
468 }
469 
470 
471 void Foam::treeDataFace::findNearestOp::operator()
472 (
473  const labelUList& indices,
474  const point& sample,
475 
476  scalar& nearestDistSqr,
477  label& minIndex,
478  point& nearestPoint
479 ) const
480 {
481  const treeDataFace& shape = tree_.shapes();
482 
483  for (const label index : indices)
484  {
485  const face& f = shape.mesh().faces()[shape.faceLabels()[index]];
486 
487  pointHit nearHit = f.nearestPoint(sample, shape.mesh().points());
488  scalar distSqr = sqr(nearHit.distance());
489 
490  if (distSqr < nearestDistSqr)
491  {
492  nearestDistSqr = distSqr;
493  minIndex = index;
494  nearestPoint = nearHit.rawPoint();
495  }
496  }
497 }
498 
499 
500 void Foam::treeDataFace::findNearestOp::operator()
501 (
502  const labelUList& indices,
503  const linePointRef& ln,
504 
505  treeBoundBox& tightest,
506  label& minIndex,
507  point& linePoint,
508  point& nearestPoint
509 ) const
510 {
512 }
513 
514 
515 bool Foam::treeDataFace::findIntersectOp::operator()
516 (
517  const label index,
518  const point& start,
519  const point& end,
520  point& intersectionPoint
521 ) const
522 {
523  const treeDataFace& shape = tree_.shapes();
524 
525  // Do quick rejection test
526  if (shape.cacheBb_)
527  {
528  const treeBoundBox& faceBb = shape.bbs_[index];
529 
530  if ((faceBb.posBits(start) & faceBb.posBits(end)) != 0)
531  {
532  // start and end in same block outside of faceBb.
533  return false;
534  }
535  }
536 
537  const label facei = shape.faceLabels_[index];
538 
539  const vector dir(end - start);
540 
541  pointHit inter = shape.mesh_.faces()[facei].intersection
542  (
543  start,
544  dir,
545  shape.mesh_.faceCentres()[facei],
546  shape.mesh_.points(),
548  );
549 
550  if (inter.hit() && inter.distance() <= 1)
551  {
552  // Note: no extra test on whether intersection is in front of us
553  // since using half_ray
554  intersectionPoint = inter.hitPoint();
555  return true;
556  }
557 
558  return false;
559 }
560 
561 
562 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::treeBoundBox::overlaps
bool overlaps(const boundBox &bb) const
Overlaps other bounding box?
Definition: boundBoxI.H:221
Foam::PointIndexHit::index
label index() const
Return index.
Definition: PointIndexHit.H:113
Foam::PointHit::hit
bool hit() const
Is there a hit.
Definition: PointHit.H:124
Foam::intersection::HALF_RAY
Definition: intersection.H:75
Foam::primitiveMesh::points
virtual const pointField & points() const =0
Return mesh points.
update
mesh update()
Foam::PointHit< point >
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::primitiveMesh::faces
virtual const faceList & faces() const =0
Return faces.
Foam::boundBox::containsAny
bool containsAny(const UList< point > &points) const
Contains any of the points? (inside or on edge)
Definition: boundBox.C:249
Foam::primitiveMesh::nFaces
label nFaces() const
Number of mesh faces.
Definition: primitiveMeshI.H:90
Foam::PointHit::rawPoint
const Point & rawPoint() const
Return point with no checking.
Definition: PointHit.H:162
Foam::treeBoundBox
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:87
Foam::treeDataFace::getVolumeType
volumeType getVolumeType(const indexedOctree< treeDataFace > &, const point &) const
Get type (inside,outside,mixed,unknown) of point w.r.t. surface.
Definition: treeDataFace.C:168
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::treeDataFace::faceLabels
const labelList & faceLabels() const
Definition: treeDataFace.H:179
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
polyMesh.H
Foam::treeDataFace::mesh
const primitiveMesh & mesh() const
Definition: treeDataFace.H:184
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
treeDataFace.H
Foam::triangleFuncs::intersectBb
static bool intersectBb(const point &p0, const point &p1, const point &p2, const treeBoundBox &cubeBb)
Does triangle intersect bounding box.
Definition: triangleFuncs.C:176
Foam::treeBoundBox::posBits
direction posBits(const point &pt) const
Position of point relative to bounding box.
Definition: treeBoundBox.C:391
NotImplemented
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:436
Foam::PointIndexHit
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:55
Foam::PointHit::distance
scalar distance() const
Return distance to hit.
Definition: PointHit.H:143
Foam::volumeType
An enumeration wrapper for classification of a location as being inside/outside of a volume.
Definition: volumeType.H:60
pFaces
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
Foam::Field< vector >
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:67
Foam::volumeType::UNKNOWN
Unknown state.
Definition: volumeType.H:67
Foam::indexedOctree
Non-pointer based hierarchical recursive searching.
Definition: treeDataEdge.H:50
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
triangleFuncs.H
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:483
Foam::treeDataFace::shapePoints
pointField shapePoints() const
Definition: treeDataFace.C:154
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::treeDataFace::overlaps
bool overlaps(const label index, const treeBoundBox &sampleBb) const
Does (bb of) shape at index overlap bb.
Definition: treeDataFace.C:414
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::Vector< scalar >
Foam::indexedOctree::getSide
static volumeType getSide(const vector &outsideNormal, const vector &vec)
Helper function to return the side. Returns outside if.
Definition: indexedOctree.C:470
Foam::List< label >
Foam::treeDataFace
Encapsulation of data needed to search for faces.
Definition: treeDataFace.H:59
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:144
Foam::UList< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::line
A line primitive.
Definition: line.H:59
Foam::fieldTypes::area
const wordList area
Standard area field types (scalar, vector, tensor, etc)
Foam::ln
bool ln(const fileName &src, const fileName &dst)
Create a softlink. dst should not exist. Returns true if successful.
Definition: MSwindows.C:915
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::treeDataFace::findNearestOp::findNearestOp
findNearestOp(const indexedOctree< treeDataFace > &tree)
Definition: treeDataFace.C:135
Foam::treeDataFace::treeDataFace
treeDataFace(const bool cacheBb, const primitiveMesh &mesh, const labelUList &faceLabels)
Construct from mesh, copying subset of faces.
Definition: treeDataFace.C:70
Foam::line::nearestDist
PointHit< Point > nearestDist(const Point &p) const
Return nearest distance to line from a given point.
Definition: lineI.H:130
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::PointHit::hitPoint
const Point & hitPoint() const
Return hit point.
Definition: PointHit.H:130
Foam::treeDataFace::findIntersectOp::findIntersectOp
findIntersectOp(const indexedOctree< treeDataFace > &tree)
Definition: treeDataFace.C:144
Foam::primitiveMesh
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:78