transformPoints: Generalised to apply a sequence of transformations

This makes usage of transformPoints the same as for
surfaceTransformPoints. Transformations are supplied as a string and are
applied in sequence.

Usage
    transformPoints "\<transformations\>" [OPTION]

    Supported transformations:
      - "translate=<translation vector>"
        Translational transformation by given vector
      - "rotate=(<n1 vector> <n2 vector>)"
        Rotational transformation from unit vector n1 to n2
      - "Rx=<angle [deg] about x-axis>"
        Rotational transformation by given angle about x-axis
      - "Ry=<angle [deg] about y-axis>"
        Rotational transformation by given angle about y-axis
      - "Rz=<angle [deg] about z-axis>"
        Rotational transformation by given angle about z-axis
      - "Ra=<axis vector> <angle [deg] about axis>"
        Rotational transformation by given angle about given axis
      - "scale=<x-y-z scaling vector>"
        Anisotropic scaling by the given vector in the x, y, z
        coordinate directions

    Example usage:
        transformPoints \
            "translate=(-0.05 -0.05 0), \
            Rz=45, \
            translate=(0.05 0.05 0)"
This commit is contained in:
Will Bainbridge
2021-05-07 16:17:26 +01:00
parent c55dceca80
commit 845d5b16e3
10 changed files with 144 additions and 240 deletions

View File

@ -0,0 +1,72 @@
transformer transforms;
{
wordReList simpleTransformations;
List<Tuple2<word, string>> transformations;
dictArgList(transformationString, simpleTransformations, transformations);
forAll(transformations, i)
{
if (transformations[i].first() == "translate")
{
const vector v(IStringStream(transformations[i].second())());
transforms = transformer::translation(v) & transforms;
}
else if (transformations[i].first() == "rotate")
{
Pair<vector> n1n2(IStringStream(transformations[i].second())());
n1n2[0] /= mag(n1n2[0]);
n1n2[1] /= mag(n1n2[1]);
transforms =
transformer::rotation(rotationTensor(n1n2[0], n1n2[1]))
& transforms;
}
else if (transformations[i].first() == "Rx")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Rx(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Ry")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Ry(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Rz")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Rz(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Ra")
{
IStringStream istr(transformations[i].second());
const vector v(istr);
const scalar a(readScalar(istr));
transforms = transformer::rotation(Ra(v, degToRad(a))) & transforms;
}
else if (transformations[i].first() == "scale")
{
const vector v(IStringStream(transformations[i].second())());
transforms =
transformer::scaling(diagTensor(v.x(), v.y(), v.z()))
& transforms;
}
else
{
args.printUsage();
FatalErrorInFunction
<< "Unknown transformation " << transformations[i].first()
<< exit(FatalError);
}
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -25,40 +25,42 @@ Application
transformPoints
Description
Transforms the mesh points in the polyMesh directory according to the
translate, rotate and scale options.
Transform (translate, rotate, scale) the mesh points, and optionally also
any vector and tensor fields.
Usage
\b transformPoints [OPTION]
\b transformPoints "\<transformations\>" [OPTION]
Supported transformations:
- \par translate=<translation vector>
Translational transformation by given vector
- \par rotate=(\<n1 vector\> \<n2 vector\>)
Rotational transformation from unit vector n1 to n2
- \par Rx=\<angle [deg] about x-axis\>
Rotational transformation by given angle about x-axis
- \par Ry=\<angle [deg] about y-axis\>
Rotational transformation by given angle about y-axis
- \par Rz=\<angle [deg] about z-axis\>
Rotational transformation by given angle about z-axis
- \par Ra=\<axis vector\> \<angle [deg] about axis\>
Rotational transformation by given angle about given axis
- \par scale=\<x-y-z scaling vector\>
Anisotropic scaling by the given vector in the x, y, z
coordinate directions
Options:
- \par -translate \<vector\> \n
Translates the points by the given vector.
- \par -rotate (\<vector\> \<vector\>) \n
Rotates the points from the first vector to the second.
- \par -yawPitchRoll (\<yawdegrees\> \<pitchdegrees\> \<rolldegrees\>) \n
Alternative rotation specification:
yaw (rotation about z)
pitch (rotation about y)
roll (rotation about x)
- \par -rollPitchYaw (\<rolldegrees\> \<pitchdegrees\> \<yawdegrees\>) \n
Alternative rotation specification:
roll (rotation about x)
pitch (rotation about y)
yaw (rotation about z)
- \par -rotateFields \n
In combination with \a -rotate, \a -yawPitchRoll or \a -rollPitchYaw
additionally transform vector and tensor fields.
Additionally transform vector and tensor fields.
- \par -scale \<vector\> \n
Scales the points by the given vector.
Example usage:
transformPoints \
"translate=(-0.05 -0.05 0), \
Rz=45, \
translate=(0.05 0.05 0)"
Any or all of the three transformation option types may be specified and are
processed in the above order.
See also
Foam::transformer
surfaceTransformPoints
\*---------------------------------------------------------------------------*/
@ -71,10 +73,9 @@ Usage
#include "pointFields.H"
#include "transformField.H"
#include "transformGeometricField.H"
#include "mathematicalConstants.H"
#include "unitConversion.H"
using namespace Foam;
using namespace Foam::constant::mathematical;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -105,36 +106,26 @@ void rotateFields(const argList& args, const Time& runTime, const tensor& T)
IOobjectList objects(mesh, runTime.timeName());
// Read vol fields.
PtrList<volScalarField> vsFlds;
readAndRotateFields(vsFlds, mesh, T, objects);
PtrList<volVectorField> vvFlds;
readAndRotateFields(vvFlds, mesh, T, objects);
PtrList<volSphericalTensorField> vstFlds;
readAndRotateFields(vstFlds, mesh, T, objects);
PtrList<volSymmTensorField> vsymtFlds;
readAndRotateFields(vsymtFlds, mesh, T, objects);
PtrList<volTensorField> vtFlds;
readAndRotateFields(vtFlds, mesh, T, objects);
// Read surface fields.
PtrList<surfaceScalarField> ssFlds;
readAndRotateFields(ssFlds, mesh, T, objects);
PtrList<surfaceVectorField> svFlds;
readAndRotateFields(svFlds, mesh, T, objects);
PtrList<surfaceSphericalTensorField> sstFlds;
readAndRotateFields(sstFlds, mesh, T, objects);
PtrList<surfaceSymmTensorField> ssymtFlds;
readAndRotateFields(ssymtFlds, mesh, T, objects);
PtrList<surfaceTensorField> stFlds;
readAndRotateFields(stFlds, mesh, T, objects);
@ -146,42 +137,32 @@ void rotateFields(const argList& args, const Time& runTime, const tensor& T)
int main(int argc, char *argv[])
{
argList::addOption
const wordList supportedTransformations
(
"translate",
"vector",
"translate by the specified <vector> - eg, '(1 0 0)'"
);
argList::addOption
(
"rotate",
"(vectorA vectorB)",
"transform in terms of a rotation between <vectorA> and <vectorB> "
"- eg, '( (1 0 0) (0 0 1) )'"
);
argList::addOption
(
"rollPitchYaw",
"vector",
"transform in terms of '(roll pitch yaw)' in degrees"
);
argList::addOption
(
"yawPitchRoll",
"vector",
"transform in terms of '(yaw pitch roll)' in degrees"
{"translate", "rotate", "Rx", "Ry", "Rz", "Ra", "scale"}
);
{
OStringStream supportedTransformationsStr;
supportedTransformationsStr << supportedTransformations << endl;
argList::addNote
(
"Transforms a mesh e.g.\n"
"transformPoints "
"\"translate=(-0.586 0 -0.156), "
"Ry=3.485, "
"translate=(0.586 0 0.156)\"\n\n"
"Supported transformations " + supportedTransformationsStr.str()
);
}
argList::validArgs.append("transformations");
argList::addBoolOption
(
"rotateFields",
"read and transform vector and tensor fields too"
);
argList::addOption
(
"scale",
"vector",
"scale by the specified amount - eg, '(0.001 0.001 0.001)' for a "
"uniform [mm] to [m] scaling"
"transform vector and tensor fields"
);
#include "addRegionOption.H"
@ -189,8 +170,14 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
#include "createTime.H"
const string transformationString(args[1]);
#include "createTransforms.H"
const wordList regionNames(selectRegionNames(args, runTime));
const bool doRotateFields = args.optionFound("rotateFields");
forAll(regionNames, regioni)
{
const word& regionName = regionNames[regioni];
@ -212,98 +199,11 @@ int main(int argc, char *argv[])
)
);
const bool doRotateFields = args.optionFound("rotateFields");
transforms.transformPosition(points, points);
// this is not actually stringent enough:
if (args.options().empty())
if (doRotateFields)
{
FatalErrorInFunction
<< "No options supplied, please use one or more of "
"-translate, -rotate or -scale options."
<< exit(FatalError);
}
vector v;
if (args.optionReadIfPresent("translate", v))
{
Info<< "Translating points by " << v << endl;
points += v;
}
if (args.optionFound("rotate"))
{
Pair<vector> n1n2
(
args.optionLookup("rotate")()
);
n1n2[0] /= mag(n1n2[0]);
n1n2[1] /= mag(n1n2[1]);
tensor T = rotationTensor(n1n2[0], n1n2[1]);
Info<< "Rotating points by " << T << endl;
points = transform(T, points);
if (doRotateFields)
{
rotateFields(args, runTime, T);
}
}
else if (args.optionReadIfPresent("rollPitchYaw", v))
{
Info<< "Rotating points by" << nl
<< " roll " << v.x() << nl
<< " pitch " << v.y() << nl
<< " yaw " << v.z() << nl;
// Convert to radians
v *= pi/180.0;
quaternion R(quaternion::rotationSequence::XYZ, v);
Info<< "Rotating points by quaternion " << R << endl;
points = transform(R, points);
if (doRotateFields)
{
rotateFields(args, runTime, R.R());
}
}
else if (args.optionReadIfPresent("yawPitchRoll", v))
{
Info<< "Rotating points by" << nl
<< " yaw " << v.x() << nl
<< " pitch " << v.y() << nl
<< " roll " << v.z() << nl;
// Convert to radians
v *= pi/180.0;
scalar yaw = v.x();
scalar pitch = v.y();
scalar roll = v.z();
quaternion R = quaternion(vector(0, 0, 1), yaw);
R *= quaternion(vector(0, 1, 0), pitch);
R *= quaternion(vector(1, 0, 0), roll);
Info<< "Rotating points by quaternion " << R << endl;
points = transform(R, points);
if (doRotateFields)
{
rotateFields(args, runTime, R.R());
}
}
if (args.optionReadIfPresent("scale", v))
{
Info<< "Scaling points by " << v << endl;
points.replace(vector::X, v.x()*points.component(vector::X));
points.replace(vector::Y, v.y()*points.component(vector::Y));
points.replace(vector::Z, v.z()*points.component(vector::Z));
rotateFields(args, runTime, transforms.T());
}
// Set the precision of the points data to 10

View File

@ -1,5 +1,6 @@
EXE_INC = \
-I$(LIB_SRC)/surfMesh/lnInclude
-I$(LIB_SRC)/surfMesh/lnInclude \
-I$(FOAM_UTILITIES)/mesh/manipulation/transformPoints
EXE_LIBS = \
-lsurfMesh

View File

@ -103,80 +103,11 @@ int main(int argc, char *argv[])
const fileName surfFileName(args[2]);
const fileName outFileName(args[3]);
#include "createTransforms.H"
Info<< "Reading surf from " << surfFileName << " ..." << nl
<< "Writing surf to " << outFileName << " ..." << endl;
wordReList simpleTransformations;
List<Tuple2<word, string>> transformations;
dictArgList(transformationString, simpleTransformations, transformations);
transformer transforms;
forAll(transformations, i)
{
if (transformations[i].first() == "translate")
{
const vector v(IStringStream(transformations[i].second())());
transforms = transformer::translation(v) & transforms;
}
else if (transformations[i].first() == "rotate")
{
Pair<vector> n1n2(IStringStream(transformations[i].second())());
n1n2[0] /= mag(n1n2[0]);
n1n2[1] /= mag(n1n2[1]);
transforms =
transformer::rotation(rotationTensor(n1n2[0], n1n2[1]))
& transforms;
}
else if (transformations[i].first() == "Rx")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Rx(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Ry")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Ry(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Rz")
{
const scalar a
(
readScalar(IStringStream(transformations[i].second())())
);
transforms = transformer::rotation(Rz(degToRad(a))) & transforms;
}
else if (transformations[i].first() == "Ra")
{
IStringStream istr(transformations[i].second());
const vector v(istr);
const scalar a(readScalar(istr));
transforms = transformer::rotation(Ra(v, degToRad(a))) & transforms;
}
else if (transformations[i].first() == "scale")
{
const vector v(IStringStream(transformations[i].second())());
transforms =
transformer::scaling(diagTensor(v.x(), v.y(), v.z()))
& transforms;
}
else
{
args.printUsage();
FatalErrorInFunction
<< "Unknown transformation " << transformations[i].first()
<< exit(FatalError);
}
}
meshedSurface surf1(surfFileName);
pointField points(surf1.points());
transforms.transformPosition(points, points);

View File

@ -10,6 +10,6 @@ cd "${0%/*}" || exit 1
runApplication blockMesh
runApplication topoSet
runApplication refineMesh -overwrite
runApplication transformPoints -scale "(0.01 0.01 0.01)"
runApplication transformPoints "scale=(0.01 0.01 0.01)"
#------------------------------------------------------------------------------

View File

@ -4937,7 +4937,7 @@ _transformPoints_ ()
local line=${COMP_LINE}
local used=$(echo "$line" | grep -oE "\-[a-zA-Z]+ ")
opts="-allRegions -case -doc -fileHandler -help -hostRoots -libs -noFunctionObjects -parallel -region -rollPitchYaw -roots -rotate -rotateFields -scale -srcDoc -translate -yawPitchRoll"
opts="-allRegions -case -doc -fileHandler -help -hostRoots -libs -noFunctionObjects -parallel -region -roots -rotateFields -srcDoc"
for o in $used ; do opts="${opts/$o/}" ; done
extra=""
@ -4947,7 +4947,7 @@ _transformPoints_ ()
opts="" ; extra="-d" ;;
-fileHandler)
opts="uncollated collated masterUncollated" ; extra="" ;;
-hostRoots|-libs|-region|-rollPitchYaw|-roots|-rotate|-scale|-translate|-yawPitchRoll)
-hostRoots|-libs|-region|-roots)
opts="" ; extra="" ;;
*) ;;
esac

View File

@ -10,7 +10,7 @@ cp $FOAM_TUTORIALS/resources/geometry/NACA0012.obj.gz constant/geometry/
application="$(getApplication)"
runApplication blockMesh
runApplication transformPoints -scale "(1 0 1)"
runApplication transformPoints "scale=(1 0 1)"
runApplication extrudeMesh
runApplication $application

View File

@ -10,7 +10,7 @@ cp $FOAM_TUTORIALS/resources/geometry/NACA0012.obj.gz constant/geometry/
application="$(getApplication)"
runApplication blockMesh
runApplication transformPoints -scale "(1 0 1)"
runApplication transformPoints "scale=(1 0 1)"
runApplication extrudeMesh
runApplication $application

View File

@ -6,7 +6,7 @@ cd ${0%/*} || exit 1 # Run from this directory
runApplication blockMesh
runApplication topoSet
runApplication transformPoints -scale "(0.01 0.01 0.01)"
runApplication transformPoints "scale=(0.01 0.01 0.01)"
runApplication splitMeshRegions -cellZones -defaultRegionName fluid -overwrite
#------------------------------------------------------------------------------

View File

@ -8,7 +8,7 @@ cd ${0%/*} || exit 1 # Run from this directory
application=$(getApplication)
runApplication blockMesh
runApplication transformPoints -scale '(1.6666 1 1)'
runApplication transformPoints "scale=(1.6666 1 1)"
runApplication mirrorMesh -dict mirrorMeshDict.x -overwrite
rm log.mirrorMesh