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 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -25,40 +25,42 @@ Application
transformPoints transformPoints
Description Description
Transforms the mesh points in the polyMesh directory according to the Transform (translate, rotate, scale) the mesh points, and optionally also
translate, rotate and scale options. any vector and tensor fields.
Usage 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: 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 - \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 Example usage:
Scales the points by the given vector. 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 See also
processed in the above order. Foam::transformer
surfaceTransformPoints
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -71,10 +73,9 @@ Usage
#include "pointFields.H" #include "pointFields.H"
#include "transformField.H" #include "transformField.H"
#include "transformGeometricField.H" #include "transformGeometricField.H"
#include "mathematicalConstants.H" #include "unitConversion.H"
using namespace Foam; 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()); IOobjectList objects(mesh, runTime.timeName());
// Read vol fields. // Read vol fields.
PtrList<volScalarField> vsFlds; PtrList<volScalarField> vsFlds;
readAndRotateFields(vsFlds, mesh, T, objects); readAndRotateFields(vsFlds, mesh, T, objects);
PtrList<volVectorField> vvFlds; PtrList<volVectorField> vvFlds;
readAndRotateFields(vvFlds, mesh, T, objects); readAndRotateFields(vvFlds, mesh, T, objects);
PtrList<volSphericalTensorField> vstFlds; PtrList<volSphericalTensorField> vstFlds;
readAndRotateFields(vstFlds, mesh, T, objects); readAndRotateFields(vstFlds, mesh, T, objects);
PtrList<volSymmTensorField> vsymtFlds; PtrList<volSymmTensorField> vsymtFlds;
readAndRotateFields(vsymtFlds, mesh, T, objects); readAndRotateFields(vsymtFlds, mesh, T, objects);
PtrList<volTensorField> vtFlds; PtrList<volTensorField> vtFlds;
readAndRotateFields(vtFlds, mesh, T, objects); readAndRotateFields(vtFlds, mesh, T, objects);
// Read surface fields. // Read surface fields.
PtrList<surfaceScalarField> ssFlds; PtrList<surfaceScalarField> ssFlds;
readAndRotateFields(ssFlds, mesh, T, objects); readAndRotateFields(ssFlds, mesh, T, objects);
PtrList<surfaceVectorField> svFlds; PtrList<surfaceVectorField> svFlds;
readAndRotateFields(svFlds, mesh, T, objects); readAndRotateFields(svFlds, mesh, T, objects);
PtrList<surfaceSphericalTensorField> sstFlds; PtrList<surfaceSphericalTensorField> sstFlds;
readAndRotateFields(sstFlds, mesh, T, objects); readAndRotateFields(sstFlds, mesh, T, objects);
PtrList<surfaceSymmTensorField> ssymtFlds; PtrList<surfaceSymmTensorField> ssymtFlds;
readAndRotateFields(ssymtFlds, mesh, T, objects); readAndRotateFields(ssymtFlds, mesh, T, objects);
PtrList<surfaceTensorField> stFlds; PtrList<surfaceTensorField> stFlds;
readAndRotateFields(stFlds, mesh, T, objects); 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[]) int main(int argc, char *argv[])
{ {
argList::addOption const wordList supportedTransformations
( (
"translate", {"translate", "rotate", "Rx", "Ry", "Rz", "Ra", "scale"}
"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"
); );
{
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 argList::addBoolOption
( (
"rotateFields", "rotateFields",
"read and transform vector and tensor fields too" "transform vector and tensor fields"
);
argList::addOption
(
"scale",
"vector",
"scale by the specified amount - eg, '(0.001 0.001 0.001)' for a "
"uniform [mm] to [m] scaling"
); );
#include "addRegionOption.H" #include "addRegionOption.H"
@ -189,8 +170,14 @@ int main(int argc, char *argv[])
#include "setRootCase.H" #include "setRootCase.H"
#include "createTime.H" #include "createTime.H"
const string transformationString(args[1]);
#include "createTransforms.H"
const wordList regionNames(selectRegionNames(args, runTime)); const wordList regionNames(selectRegionNames(args, runTime));
const bool doRotateFields = args.optionFound("rotateFields");
forAll(regionNames, regioni) forAll(regionNames, regioni)
{ {
const word& regionName = 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 (doRotateFields)
if (args.options().empty())
{ {
FatalErrorInFunction rotateFields(args, runTime, transforms.T());
<< "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));
} }
// Set the precision of the points data to 10 // Set the precision of the points data to 10

View File

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

View File

@ -103,80 +103,11 @@ int main(int argc, char *argv[])
const fileName surfFileName(args[2]); const fileName surfFileName(args[2]);
const fileName outFileName(args[3]); const fileName outFileName(args[3]);
#include "createTransforms.H"
Info<< "Reading surf from " << surfFileName << " ..." << nl Info<< "Reading surf from " << surfFileName << " ..." << nl
<< "Writing surf to " << outFileName << " ..." << endl; << "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); meshedSurface surf1(surfFileName);
pointField points(surf1.points()); pointField points(surf1.points());
transforms.transformPosition(points, points); transforms.transformPosition(points, points);

View File

@ -10,6 +10,6 @@ cd "${0%/*}" || exit 1
runApplication blockMesh runApplication blockMesh
runApplication topoSet runApplication topoSet
runApplication refineMesh -overwrite 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 line=${COMP_LINE}
local used=$(echo "$line" | grep -oE "\-[a-zA-Z]+ ") 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 for o in $used ; do opts="${opts/$o/}" ; done
extra="" extra=""
@ -4947,7 +4947,7 @@ _transformPoints_ ()
opts="" ; extra="-d" ;; opts="" ; extra="-d" ;;
-fileHandler) -fileHandler)
opts="uncollated collated masterUncollated" ; extra="" ;; opts="uncollated collated masterUncollated" ; extra="" ;;
-hostRoots|-libs|-region|-rollPitchYaw|-roots|-rotate|-scale|-translate|-yawPitchRoll) -hostRoots|-libs|-region|-roots)
opts="" ; extra="" ;; opts="" ; extra="" ;;
*) ;; *) ;;
esac esac

View File

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

View File

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

View File

@ -6,7 +6,7 @@ cd ${0%/*} || exit 1 # Run from this directory
runApplication blockMesh runApplication blockMesh
runApplication topoSet 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 runApplication splitMeshRegions -cellZones -defaultRegionName fluid -overwrite
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------

View File

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