plane.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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
19  for more details.
20 
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/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "plane.H"
27 #include "tensor.H"
28 #include "units.H"
29 
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
31 
33 Foam::plane::specificationNames_
34 {"planeEquation", "embeddedPoints", "pointAndNormal"};
35 
36 
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 
39 void Foam::plane::calcPntAndVec
40 (
41  const scalar a,
42  const scalar b,
43  const scalar c,
44  const scalar d
45 )
46 {
47  normal_ = vector(a, b, c);
48 
49  const scalar magNormal = mag(normal_);
50 
51  // Normalise the normal if possible. Set to invalid if not.
52  if (magNormal > 0)
53  {
54  normal_ /= magNormal;
55  }
56  else
57  {
58  normal_ = vector::zero;
59  }
60 
61  // Construct the point if possible. Set to far away if not.
62  if (magNormal > mag(d)*vSmall)
63  {
64  point_ = - d/magNormal*normal_;
65  }
66  else
67  {
68  point_ = point::max;
69  }
70 }
71 
72 
73 void Foam::plane::calcPntAndVec
74 (
75  const point& point1,
76  const point& point2,
77  const point& point3
78 )
79 {
80  normal_ = normalised((point1 - point2) ^ (point2 - point3));
81 
82  point_ = (point1 + point2 + point3)/3;
83 }
84 
85 
86 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
87 
88 Foam::plane::plane(const vector& normalVector)
89 :
90  normal_(normalised(normalVector)),
91  point_(Zero)
92 {}
93 
94 
95 Foam::plane::plane(const point& basePoint, const vector& normalVector)
96 :
97  normal_(normalised(normalVector)),
98  point_(basePoint)
99 {}
100 
101 
103 (
104  const scalar a,
105  const scalar b,
106  const scalar c,
107  const scalar d
108 )
109 {
110  calcPntAndVec(a, b, c, d);
111 }
112 
113 
115 (
116  const point& point1,
117  const point& point2,
118  const point& point3
119 )
120 {
121  calcPntAndVec(point1, point2, point3);
122 }
123 
124 
126 :
127  normal_(Zero),
128  point_(Zero)
129 {
130  specification spec;
131  bool allowSubDict;
132  if (dict.found("planeType"))
133  {
134  spec = specificationNames_.read(dict.lookup("planeType"));
135  allowSubDict = true;
136  }
137  else
138  {
139  const bool havePlaneEquation =
140  dict.found("a") || dict.found("b") ||
141  dict.found("c") || dict.found("d");
142  const bool haveEmbeddedPoints =
143  dict.found("point1") ||
144  dict.found("point2") ||
145  dict.found("point3");
146  const bool havePointAndNormal =
147  dict.found("point") || dict.found("basePoint")
148  || dict.found("normal") || dict.found("normalVector");
149  const bool haveSingleSpec =
150  havePlaneEquation + haveEmbeddedPoints + havePointAndNormal == 1;
151 
152  if (!haveSingleSpec) dict.lookup("planeType");
153 
154  spec =
155  havePlaneEquation ? specification::planeEquation
156  : haveEmbeddedPoints ? specification::embeddedPoints
157  : /* havePointAndNormal ? */ specification::pointAndNormal;
158  allowSubDict = false;
159  }
160 
161  const dictionary& subDict =
162  allowSubDict
163  ? dict
164  : dict.optionalSubDict(specificationNames_[spec] + "Dict");
165 
166  switch (spec)
167  {
168  case specification::planeEquation:
169  {
170  const scalar a = subDict.lookup<scalar>("a", units::none);
171  const scalar b = subDict.lookup<scalar>("b", units::none);
172  const scalar c = subDict.lookup<scalar>("c", units::none);
173  const scalar d = subDict.lookup<scalar>("d", units::none);
174  calcPntAndVec(a, b, c, d);
175  break;
176  }
177  case specification::embeddedPoints:
178  {
179  const point point1 = subDict.lookup<point>("point1", dimLength);
180  const point point2 = subDict.lookup<point>("point2", dimLength);
181  const point point3 = subDict.lookup<point>("point3", dimLength);
182  calcPntAndVec(point1, point2, point3);
183  break;
184  }
185  case specification::pointAndNormal:
186  {
187  point_ =
189  (
190  {"point", "basePoint"},
191  dimLength
192  );
193  normal_ =
194  normalised
195  (
197  (
198  {"normal", "normalVector"},
199  dimless
200  )
201  );
202  break;
203  }
204  }
205 
206  if (normal_ == vector::zero)
207  {
208  FatalIOErrorInFunction(subDict)
209  << "Plane normal has zero length"
210  << exit(FatalIOError);
211  }
212 
213  if (point_ == point::max)
214  {
215  FatalIOErrorInFunction(subDict)
216  << "Plane is too far from the origin"
217  << exit(FatalIOError);
218  }
219 }
220 
221 
223 :
224  normal_(normalised(vector(is))),
225  point_(is)
226 {}
227 
228 
229 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
230 
232 {
234 
235  scalar magX = mag(normal_.x());
236  scalar magY = mag(normal_.y());
237  scalar magZ = mag(normal_.z());
238 
239  if (magX > magY)
240  {
241  if (magX > magZ)
242  {
243  C[0] = 1;
244  C[1] = normal_.y()/normal_.x();
245  C[2] = normal_.z()/normal_.x();
246  }
247  else
248  {
249  C[0] = normal_.x()/normal_.z();
250  C[1] = normal_.y()/normal_.z();
251  C[2] = 1;
252  }
253  }
254  else
255  {
256  if (magY > magZ)
257  {
258  C[0] = normal_.x()/normal_.y();
259  C[1] = 1;
260  C[2] = normal_.z()/normal_.y();
261  }
262  else
263  {
264  C[0] = normal_.x()/normal_.z();
265  C[1] = normal_.y()/normal_.z();
266  C[2] = 1;
267  }
268  }
269 
270  C[3] = - C[0] * point_.x()
271  - C[1] * point_.y()
272  - C[2] * point_.z();
273 
274  return C;
275 }
276 
277 
279 {
280  // Perturb base point
281  const point& refPt = refPoint();
282 
283  // ax + by + cz + d = 0
284  FixedList<scalar, 4> plane = this->planeCoeffs();
285 
286  const scalar perturbX = refPt.x() + 1e-3;
287  const scalar perturbY = refPt.y() + 1e-3;
288  const scalar perturbZ = refPt.z() + 1e-3;
289 
290  if (mag(plane[2]) < small)
291  {
292  if (mag(plane[1]) < small)
293  {
294  const scalar x =
295  -1.0
296  *(
297  plane[3]
298  + plane[1]*perturbY
299  + plane[2]*perturbZ
300  )/plane[0];
301 
302  return point
303  (
304  x,
305  perturbY,
306  perturbZ
307  );
308  }
309 
310  const scalar y =
311  -1.0
312  *(
313  plane[3]
314  + plane[0]*perturbX
315  + plane[2]*perturbZ
316  )/plane[1];
317 
318  return point
319  (
320  perturbX,
321  y,
322  perturbZ
323  );
324  }
325  else
326  {
327  const scalar z =
328  -1.0
329  *(
330  plane[3]
331  + plane[0]*perturbX
332  + plane[1]*perturbY
333  )/plane[2];
334 
335  return point
336  (
337  perturbX,
338  perturbY,
339  z
340  );
341  }
342 }
343 
344 
346 {
347  return p - normal_*signedDistance(p);
348 }
349 
350 
351 Foam::scalar Foam::plane::distance(const point& p) const
352 {
353  return mag(signedDistance(p));
354 }
355 
356 
357 Foam::scalar Foam::plane::signedDistance(const point& p) const
358 {
359  return (p - point_) & normal_;
360 }
361 
362 
364 (
365  const point& pnt0,
366  const vector& dir
367 ) const
368 {
369  const scalar num = (point_ - pnt0) & normal_;
370  const scalar den = dir & normal_;
371 
372  return mag(den) > mag(num)*vSmall ? num/den : vGreat;
373 }
374 
375 
377 {
378  // Mathworld plane-plane intersection. Assume there is a point on the
379  // intersection line with z=0 and solve the two plane equations
380  // for that (now 2x2 equation in x and y)
381  // Better: use either z=0 or x=0 or y=0.
382 
383  const vector& n1 = normal();
384  const vector& n2 = plane2.normal();
385 
386  const point& p1 = refPoint();
387  const point& p2 = plane2.refPoint();
388 
389  scalar n1p1 = n1&p1;
390  scalar n2p2 = n2&p2;
391 
392  vector dir = n1 ^ n2;
393 
394  // Determine zeroed out direction (can be x,y or z) by looking at which
395  // has the largest component in dir.
396  scalar magX = mag(dir.x());
397  scalar magY = mag(dir.y());
398  scalar magZ = mag(dir.z());
399 
400  direction iZero, i1, i2;
401 
402  if (magX > magY)
403  {
404  if (magX > magZ)
405  {
406  iZero = 0;
407  i1 = 1;
408  i2 = 2;
409  }
410  else
411  {
412  iZero = 2;
413  i1 = 0;
414  i2 = 1;
415  }
416  }
417  else
418  {
419  if (magY > magZ)
420  {
421  iZero = 1;
422  i1 = 2;
423  i2 = 0;
424  }
425  else
426  {
427  iZero = 2;
428  i1 = 0;
429  i2 = 1;
430  }
431  }
432 
433  vector pt;
434 
435  pt[iZero] = 0;
436  pt[i1] = (n2[i2]*n1p1 - n1[i2]*n2p2) / (n1[i1]*n2[i2] - n2[i1]*n1[i2]);
437  pt[i2] = (n2[i1]*n1p1 - n1[i1]*n2p2) / (n1[i2]*n2[i1] - n1[i1]*n2[i2]);
438 
439  return ray(pt, dir);
440 }
441 
442 
444 (
445  const plane& plane2,
446  const plane& plane3
447 ) const
448 {
449  FixedList<scalar, 4> coeffs1(planeCoeffs());
450  FixedList<scalar, 4> coeffs2(plane2.planeCoeffs());
451  FixedList<scalar, 4> coeffs3(plane3.planeCoeffs());
452 
453  tensor a
454  (
455  coeffs1[0],coeffs1[1],coeffs1[2],
456  coeffs2[0],coeffs2[1],coeffs2[2],
457  coeffs3[0],coeffs3[1],coeffs3[2]
458  );
459 
460  vector b(coeffs1[3],coeffs2[3],coeffs3[3]);
461 
462  return (inv(a) & (-b));
463 }
464 
465 
467 {
468  const vector mirroredPtDir = p - nearestPoint(p);
469 
470  if ((normal() & mirroredPtDir) > 0)
471  {
472  return p - 2.0*distance(p)*normal();
473  }
474  else
475  {
476  return p + 2.0*distance(p)*normal();
477  }
478 }
479 
480 
482 {
483  writeEntry(os, "planeType", "pointAndNormal");
484  os << indent << "pointAndNormalDict" << nl
486  writeEntry(os, "point", point_);
487  writeEntry(os, "normal", normal_);
488  os << decrIndent << indent << token::END_BLOCK << endl;
489 }
490 
491 
492 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
493 
494 bool Foam::operator==(const plane& a, const plane& b)
495 {
496  if (a.point_ == b.point_ && a.normal_ == b.normal_)
497  {
498  return true;
499  }
500  else
501  {
502  return false;
503  }
504 }
505 
506 bool Foam::operator!=(const plane& a, const plane& b)
507 {
508  return !(a == b);
509 }
510 
511 
512 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
513 
515 {
516  os << a.normal_ << token::SPACE << a.point_;
517 
518  return os;
519 }
520 
521 
522 // ************************************************************************* //
scalar y
Graphite solid properties.
Definition: C.H:51
A 1D vector of objects of type <T> with a fixed size <Size>.
Definition: FixedList.H:78
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
Enum read(Istream &) const
Read a word from Istream and return the corresponding.
Definition: NamedEnum.C:55
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
static const Form zero
Definition: VectorSpace.H:118
static const Form max
Definition: VectorSpace.H:120
const Cmpt & z() const
Definition: VectorI.H:87
const Cmpt & y() const
Definition: VectorI.H:81
const Cmpt & x() const
Definition: VectorI.H:75
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
ITstream & lookupBackwardsCompatible(const wordList &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream, trying a list of keywords.
Definition: dictionary.C:680
A direction and a reference point.
Definition: plane.H:83
Geometric class that creates a 2D plane and can return the intersection point between a line and the ...
Definition: plane.H:62
const point & refPoint() const
Return the plane base point.
Definition: plane.H:189
point mirror(const point &p) const
Mirror the supplied point in the plane. Return the mirrored point.
Definition: plane.C:466
FixedList< scalar, 4 > planeCoeffs() const
Return coefficients for the plane equation, ax + by + cz + d = 0.
Definition: plane.C:231
scalar normalIntersect(const point &pnt0, const vector &dir) const
Return cut coefficient for plane and line defined by.
Definition: plane.C:364
plane(const vector &normalVector)
Construct from normal vector through the origin.
Definition: plane.C:88
scalar distance(const point &p) const
Return distance from the given point to the plane.
Definition: plane.C:351
const vector & normal() const
Return the plane normal.
Definition: plane.H:183
point aPoint() const
Return a point on the plane.
Definition: plane.C:278
void writeDict(Ostream &) const
Write to dictionary.
Definition: plane.C:481
point nearestPoint(const point &p) const
Return nearest point in the plane for the given point.
Definition: plane.C:345
ray planeIntersect(const plane &) const
Return the cutting line between this plane and another.
Definition: plane.C:376
point planePlaneIntersect(const plane &, const plane &) const
Return the cutting point between this plane and two other planes.
Definition: plane.C:444
scalar signedDistance(const point &p) const
Return signed distance from the given point to the plane.
Definition: plane.C:357
@ BEGIN_BLOCK
Definition: token.H:114
@ END_BLOCK
Definition: token.H:115
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
volScalarField & b
Definition: createFields.H:27
const dimensionedScalar c
Speed of light in a vacuum.
static const coefficient C("C", dimTemperature, 234.5)
const unitSet none
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
bool operator!=(const particle &, const particle &)
Definition: particle.C:445
const doubleScalar e
Definition: doubleScalar.H:106
const dimensionSet & dimless
Definition: dimensions.C:138
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:272
tmp< fvMatrix< Type > > operator==(const fvMatrix< Type > &, const fvMatrix< Type > &)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
const dimensionSet & dimLength
Definition: dimensions.C:141
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:265
vector point
Point is a vector.
Definition: point.H:41
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void inv(pointPatchField< tensor > &, const pointPatchField< tensor > &)
dimensionSet normalised(const dimensionSet &)
Definition: dimensionSet.C:509
IOerror FatalIOError
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:243
void writeEntry(Ostream &os, const word &key, const DimensionedFieldFunction< DimensionedFieldType > &f)
static const char nl
Definition: Ostream.H:297
uint8_t direction
Definition: direction.H:45
dictionary dict
volScalarField & p
Useful unit conversions.