surfaceTransformPoints.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-2022 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 Application
28  surfaceTransformPoints
29 
30 Group
31  grpSurfaceUtilities
32 
33 Description
34  Transform (scale/rotate) a surface.
35  Like transformPoints but for surfaces.
36 
37  The rollPitchYaw and yawPitchRoll options take three angles (degrees)
38  that describe the intrinsic Euler rotation.
39 
40  rollPitchYaw
41  - roll (rotation about X) followed by
42  - pitch (rotation about Y) followed by
43  - yaw (rotation about Z)
44 
45  yawPitchRoll
46  - yaw (rotation about Z) followed by
47  - pitch (rotation about Y) followed by
48  - roll (rotation about X)
49 
50 \*---------------------------------------------------------------------------*/
51 
52 #include "argList.H"
53 #include "Fstream.H"
54 #include "boundBox.H"
55 #include "transformField.H"
56 #include "Pair.H"
57 #include "Tuple2.H"
58 #include "axisAngleRotation.H"
60 #include "MeshedSurfaces.H"
61 
62 using namespace Foam;
63 using namespace Foam::coordinateRotations;
64 
65 static word getExtension(const fileName& name)
66 {
67  return
68  (
69  name.has_ext("gz")
70  ? name.stem().ext()
71  : name.ext()
72  );
73 }
74 
75 
76 // Non-short-circuiting check to get all warnings
77 static bool hasReadWriteTypes(const word& readType, const word& writeType)
78 {
79  volatile bool good = true;
80 
81  if (!meshedSurface::canReadType(readType, true))
82  {
83  good = false;
84  }
85 
86  if (!meshedSurface::canWriteType(writeType, true))
87  {
88  good = false;
89  }
90 
91  return good;
92 }
93 
94 
95 // Retrieve scaling option
96 // - size 0 : no scaling
97 // - size 1 : uniform scaling
98 // - size 3 : non-uniform scaling
99 List<scalar> getScalingOpt(const word& optName, const argList& args)
100 {
101  // readListIfPresent handles single or multiple values
102  // - accept 1 or 3 values
103 
104  List<scalar> scaling;
105  args.readListIfPresent(optName, scaling);
106 
107  if (scaling.size() == 1)
108  {
109  // Uniform scaling
110  }
111  else if (scaling.size() == 3)
112  {
113  // Non-uniform, but may actually be uniform
114  if
115  (
116  equal(scaling[0], scaling[1])
117  && equal(scaling[0], scaling[2])
118  )
119  {
120  scaling.resize(1);
121  }
122  }
123  else if (!scaling.empty())
124  {
125  FatalError
126  << "Incorrect number of components, must be 1 or 3." << nl
127  << " -" << optName << ' ' << args[optName].c_str() << endl
128  << exit(FatalError);
129  }
130 
131  if (scaling.size() == 1 && equal(scaling[0], 1))
132  {
133  // Scale factor 1 == no scaling
134  scaling.clear();
135  }
136 
137  // Zero and negative scaling are permitted
138 
139  return scaling;
140 }
141 
142 
143 void applyScaling(pointField& points, const List<scalar>& scaling)
144 {
145  if (scaling.size() == 1)
146  {
147  Info<< "Scaling points uniformly by " << scaling[0] << nl;
148  points *= scaling[0];
149  }
150  else if (scaling.size() == 3)
151  {
152  const vector factor(scaling[0], scaling[1], scaling[2]);
153  Info<< "Scaling points by " << factor << nl;
154  cmptMultiply(points, points, factor);
155  }
156 }
157 
158 
159 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
160 
161 int main(int argc, char *argv[])
162 {
164  (
165  "Transform (translate / rotate / scale) surface points.\n"
166  "Like transformPoints but for surfaces.\n"
167  "Note: roll=rotate about x, pitch=rotate about y, yaw=rotate about z"
168  );
170  argList::addArgument("input", "The input surface file");
171  argList::addArgument("output", "The output surface file");
173  (
174  "recentre",
175  "Recentre the bounding box before other operations"
176  );
178  (
179  "translate",
180  "vector",
181  "Translate by specified <vector> before rotations"
182  );
184  (
185  "auto-centre",
186  "Use bounding box centre as centre for rotations"
187  );
189  (
190  "centre",
191  "point",
192  "Use specified <point> as centre for rotations"
193  );
194  argList::addOptionCompat("auto-centre", {"auto-origin", 2206});
195  argList::addOptionCompat("centre", {"origin", 2206});
196 
198  (
199  "rotate",
200  "(vectorA vectorB)",
201  "Rotate from <vectorA> to <vectorB> - eg, '((1 0 0) (0 0 1))'"
202  );
204  (
205  "rotate-angle",
206  "(vector angle)",
207  "Rotate <angle> degrees about <vector> - eg, '((1 0 0) 45)'"
208  );
210  (
211  "rotate-x", "deg",
212  "Rotate (degrees) about x-axis"
213  );
215  (
216  "rotate-y", "deg",
217  "Rotate (degrees) about y-axis"
218  );
220  (
221  "rotate-z", "deg",
222  "Rotate (degrees) about z-axis"
223  );
225  (
226  "rollPitchYaw",
227  "vector",
228  "Rotate by '(roll pitch yaw)' degrees"
229  );
231  (
232  "yawPitchRoll",
233  "vector",
234  "Rotate by '(yaw pitch roll)' degrees"
235  );
237  (
238  "read-scale",
239  "scalar | vector",
240  "Uniform or non-uniform input scaling"
241  );
243  (
244  "write-scale",
245  "scalar | vector",
246  "Uniform or non-uniform output scaling"
247  );
249  (
250  "read-format",
251  "type",
252  "Input format (default: use file extension)"
253  );
255  (
256  "write-format",
257  "type",
258  "Output format (default: use file extension)"
259  );
260 
261  // Backward compatibility and with transformPoints
262  argList::addOptionCompat("write-scale", {"scale", -2006});
263 
264  argList args(argc, argv);
265 
266  // Verify that an operation has been specified
267  {
268  const List<word> operationNames
269  ({
270  "recentre",
271  "translate",
272  "rotate",
273  "rotate-angle",
274  "rotate-x",
275  "rotate-y",
276  "rotate-z",
277  "rollPitchYaw",
278  "yawPitchRoll",
279  "read-scale",
280  "write-scale"
281  });
282 
283  if (!args.count(operationNames))
284  {
285  FatalError
286  << "No operation supplied, "
287  << "use at least one of the following:" << nl
288  << " ";
289 
290  for (const auto& opName : operationNames)
291  {
292  FatalError
293  << " -" << opName;
294  }
295 
296  FatalError
297  << nl << exit(FatalError);
298  }
299  }
300 
301  const auto importName = args.get<fileName>(1);
302  const auto exportName = args.get<fileName>(2);
303 
304  const word readFileType
305  (
306  args.getOrDefault<word>("read-format", getExtension(importName))
307  );
308 
309  const word writeFileType
310  (
311  args.getOrDefault<word>("write-format", getExtension(exportName))
312  );
313 
314 
315  // Check that reading/writing is supported
316  if (!hasReadWriteTypes(readFileType, writeFileType))
317  {
318  FatalError
319  << "Unsupported file format(s)" << nl
320  << exit(FatalError);
321  }
322 
323 
324  Info<< "Reading surf from " << importName << " ..." << nl
325  << "Writing surf to " << exportName << " ..." << endl;
326 
327 
328  meshedSurface surf1(importName, readFileType);
329 
330  pointField points(surf1.points());
331 
332 
333  // Begin operations
334 
335  // Input scaling
336  applyScaling(points, getScalingOpt("read-scale", args));
337 
338  vector v;
339  if (args.found("recentre"))
340  {
341  v = boundBox(points).centre();
342  Info<< "Adjust centre " << v << " -> (0 0 0)" << endl;
343  points -= v;
344  }
345 
346  if (args.readIfPresent("translate", v))
347  {
348  Info<< "Translating points by " << v << endl;
349  points += v;
350  }
351 
352  vector rotationCentre;
353  bool useRotationCentre = args.readIfPresent("centre", rotationCentre);
354  if (args.found("auto-centre") && !useRotationCentre)
355  {
356  useRotationCentre = true;
357  rotationCentre = boundBox(points).centre();
358  }
359 
360  if (useRotationCentre)
361  {
362  Info<< "Set centre of rotation to " << rotationCentre << endl;
363  points -= rotationCentre;
364  }
365 
366 
367  // Get a rotation specification
368 
369  tensor rot(Zero);
370  bool useRotation(false);
371 
372  if (args.found("rotate"))
373  {
374  Pair<vector> n1n2
375  (
376  args.lookup("rotate")()
377  );
378  n1n2[0].normalise();
379  n1n2[1].normalise();
380 
381  rot = rotationTensor(n1n2[0], n1n2[1]);
382  useRotation = true;
383  }
384  else if (args.found("rotate-angle"))
385  {
386  const Tuple2<vector, scalar> rotAxisAngle
387  (
388  args.lookup("rotate-angle")()
389  );
390 
391  const vector& axis = rotAxisAngle.first();
392  const scalar angle = rotAxisAngle.second();
393 
394  Info<< "Rotating points " << nl
395  << " about " << axis << nl
396  << " angle " << angle << nl;
397 
398  rot = axisAngle::rotation(axis, angle, true);
399  useRotation = true;
400  }
401  else if (args.found("rotate-x"))
402  {
403  const scalar angle = args.get<scalar>("rotate-x");
404 
405  Info<< "Rotating points about x-axis: " << angle << nl;
406 
407  rot = axisAngle::rotation(vector::X, angle, true);
408  useRotation = true;
409  }
410  else if (args.found("rotate-y"))
411  {
412  const scalar angle = args.get<scalar>("rotate-y");
413 
414  Info<< "Rotating points about y-axis: " << angle << nl;
415 
416  rot = axisAngle::rotation(vector::Y, angle, true);
417  useRotation = true;
418  }
419  else if (args.found("rotate-z"))
420  {
421  const scalar angle = args.get<scalar>("rotate-z");
422 
423  Info<< "Rotating points about z-axis: " << angle << nl;
424 
425  rot = axisAngle::rotation(vector::Z, angle, true);
426  useRotation = true;
427  }
428  else if (args.readIfPresent("rollPitchYaw", v))
429  {
430  Info<< "Rotating points by" << nl
431  << " roll " << v.x() << nl
432  << " pitch " << v.y() << nl
433  << " yaw " << v.z() << nl;
434 
435  rot = euler::rotation(euler::eulerOrder::ROLL_PITCH_YAW, v, true);
436  useRotation = true;
437  }
438  else if (args.readIfPresent("yawPitchRoll", v))
439  {
440  Info<< "Rotating points by" << nl
441  << " yaw " << v.x() << nl
442  << " pitch " << v.y() << nl
443  << " roll " << v.z() << nl;
444 
445  rot = euler::rotation(euler::eulerOrder::YAW_PITCH_ROLL, v, true);
446  useRotation = true;
447  }
448 
449  if (useRotation)
450  {
451  Info<< "Rotating points by " << rot << endl;
452  transform(points, rot, points);
453  }
454 
455  if (useRotationCentre)
456  {
457  Info<< "Unset centre of rotation from " << rotationCentre << endl;
458  points += rotationCentre;
459  }
460 
461  // Output scaling
462  applyScaling(points, getScalingOpt("write-scale", args));
463 
464  surf1.movePoints(points);
465  surf1.write(exportName, writeFileType);
466 
467  Info<< "End\n" << endl;
468 
469  return 0;
470 }
471 
472 
473 // ************************************************************************* //
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition: label.H:164
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:374
static void noParallel()
Remove the parallel options.
Definition: argList.C:584
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:418
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:300
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from vector n1 to n2.
Definition: transform.H:47
word ext() const
Return file name extension (part after last .)
Definition: wordI.H:171
Spatial transformation functions for primitive fields.
Namespace for coordinate system rotations.
Definition: axesRotation.C:30
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: instant.H:46
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
bool has_ext() const
Various checks for extensions.
Definition: stringI.H:43
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
A class for handling words, derived from Foam::string.
Definition: word.H:63
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:385
ITstream lookup(const word &optName) const
Return an input stream from the named option.
Definition: argListI.H:177
dimensioned< Type > cmptMultiply(const dimensioned< Type > &, const dimensioned< Type > &)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
bool readListIfPresent(const word &optName, List< T > &list) const
If named option is present, get a List of values treating a single entry like a list of size 1...
Definition: argListI.H:387
static bool canWriteType(const word &fileType, bool verbose=false)
Can we write this file format? Also checks proxy types.
Definition: MeshedSurface.C:70
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
static tensor rotation(const vector &angles, bool degrees=false)
Rotation tensor calculated for the intrinsic Euler angles in z-x-z order.
static bool canReadType(const word &fileType, bool verbose=false)
Can we read this file format? Also checks friend types.
Definition: MeshedSurface.C:53
PtrList< volScalarField > & Y
static tensor rotation(const vector &axis, const scalar angle, bool degrees=false)
The rotation tensor for given axis/angle.
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
messageStream Info
Information stream (stdout output on master, null elsewhere)
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:316
point centre() const
The centre (midpoint) of the bounding box.
Definition: boundBoxI.H:186
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
Foam::argList args(argc, argv)
Tensor of scalars, i.e. Tensor<scalar>.
label count(const UList< word > &optionNames) const
Return how many of the specified options were used.
Definition: argList.C:2114
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127