ENH: additional options for transformPoints and surfaceRefineRedGreen

- add -recentre option to shift points according to the bounding box
  centre before performing other operations

- add -auto-origin to use the bounding box centre as the origin for
  rotations. Has lower priority than the -origin option.

- surfaceTransformPoints now has distinct -read-scale, -write-scale
  options (as per surfaceMeshConvert). Silently accepts -scale as
  equivalent to -write-scale, for backwards compatibility and
  similarity with transformPoints

- add -steps option for surfaceRefineRedGreen for successive
  refinement
This commit is contained in:
Mark Olesen
2020-10-22 13:00:48 +02:00
parent 4f84aa5362
commit 51b2490258
5 changed files with 325 additions and 103 deletions

View File

@ -41,11 +41,14 @@ Usage
Specify the time to search from and apply the transformation Specify the time to search from and apply the transformation
(default is latest) (default is latest)
-recentre
Recentre using the bounding box centre before other operations
-translate vector -translate vector
Translates the points by the given vector before rotations Translate the points by the given vector before rotations
-rotate (vector vector) -rotate (vector vector)
Rotates the points from the first vector to the second, Rotate the points from the first vector to the second
-rotate-angle (vector angle) -rotate-angle (vector angle)
Rotate angle degrees about vector axis. Rotate angle degrees about vector axis.
@ -54,7 +57,7 @@ Usage
or -rollPitchYaw (rolldegrees pitchdegrees yawdegrees) or -rollPitchYaw (rolldegrees pitchdegrees yawdegrees)
-scale scalar|vector -scale scalar|vector
Scales the points by the given scalar or vector. Scale the points by the given scalar or vector on output.
The any or all of the three options may be specified and are processed The any or all of the three options may be specified and are processed
in the above order. in the above order.
@ -150,6 +153,85 @@ void rotateFields(const argList& args, const Time& runTime, const tensor& T)
} }
// Retrieve scaling option
// - size 0 : no scaling
// - size 1 : uniform scaling
// - size 3 : non-uniform scaling
List<scalar> getScalingOpt(const word& optName, const argList& args)
{
// readListIfPresent handles single or multiple values
// - accept 1 or 3 values
List<scalar> scaling;
args.readListIfPresent(optName, scaling);
if (scaling.size() == 1)
{
// Uniform scaling
}
else if (scaling.size() == 3)
{
// Non-uniform, but may actually be uniform
if
(
equal(scaling[0], scaling[1])
&& equal(scaling[0], scaling[2])
)
{
scaling.resize(1);
}
}
else if (!scaling.empty())
{
FatalError
<< "Incorrect number of components, must be 1 or 3." << nl
<< " -" << optName << ' ' << args[optName].c_str() << endl
<< exit(FatalError);
}
if (scaling.size() == 1 && equal(scaling[0], 1))
{
// Scale factor 1 == no scaling
scaling.clear();
}
for (const scalar scale : scaling)
{
if (scale <= 0)
{
FatalError
<< "Invalid scaling value, must be positive." << nl
<< " -" << optName << ' ' << args[optName].c_str() << endl
<< exit(FatalError);
}
}
return scaling;
}
void applyScaling(pointField& points, const List<scalar>& scaling)
{
if (scaling.size() == 1)
{
Info<< "Scaling points uniformly by " << scaling[0] << nl;
points *= scaling[0];
}
else if (scaling.size() == 3)
{
Info<< "Scaling points by ("
<< scaling[0] << ' '
<< scaling[1] << ' '
<< scaling[2] << ')' << nl;
points.replace(vector::X, scaling[0]*points.component(vector::X));
points.replace(vector::Y, scaling[1]*points.component(vector::Y));
points.replace(vector::Z, scaling[2]*points.component(vector::Z));
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -165,11 +247,21 @@ int main(int argc, char *argv[])
"Specify the time to search from and apply the transformation" "Specify the time to search from and apply the transformation"
" (default is latest)" " (default is latest)"
); );
argList::addBoolOption
(
"recentre",
"Recentre the bounding box before other operations"
);
argList::addOption argList::addOption
( (
"translate", "translate",
"vector", "vector",
"Translate by specified <vector> - eg, '(1 0 0)' before rotations" "Translate by specified <vector> before rotations"
);
argList::addBoolOption
(
"auto-origin",
"Use bounding box centre as origin for rotations"
); );
argList::addOption argList::addOption
( (
@ -214,6 +306,9 @@ int main(int argc, char *argv[])
"use either '(0.001 0.001 0.001)' or simply '0.001'" "use either '(0.001 0.001 0.001)' or simply '0.001'"
); );
// Compatibility with surfaceTransformPoints
argList::addOptionCompat("scale", {"write-scale", 0});
#include "addRegionOption.H" #include "addRegionOption.H"
#include "setRootCase.H" #include "setRootCase.H"
@ -223,6 +318,7 @@ int main(int argc, char *argv[])
{ {
const List<word> operationNames const List<word> operationNames
{ {
"recentre",
"translate", "translate",
"rotate", "rotate",
"rotate-angle", "rotate-angle",
@ -286,16 +382,31 @@ int main(int argc, char *argv[])
) )
); );
// Begin operations
vector v; vector v;
if (args.found("recentre"))
{
v = boundBox(points).centre();
Info<< "Adjust centre " << v << " -> (0 0 0)" << endl;
points -= v;
}
if (args.readIfPresent("translate", v)) if (args.readIfPresent("translate", v))
{ {
Info<< "Translating points by " << v << endl; Info<< "Translating points by " << v << endl;
points += v; points += v;
} }
vector origin; vector origin;
const bool useOrigin = args.readIfPresent("origin", origin); bool useOrigin = args.readIfPresent("origin", origin);
if (args.found("auto-origin") && !useOrigin)
{
useOrigin = true;
origin = boundBox(points).centre();
}
if (useOrigin) if (useOrigin)
{ {
Info<< "Set origin for rotations to " << origin << endl; Info<< "Set origin for rotations to " << origin << endl;
@ -328,8 +439,8 @@ int main(int argc, char *argv[])
args.lookup("rotate-angle")() args.lookup("rotate-angle")()
); );
const vector& axis = rotAxisAngle.first(); const vector& axis = rotAxisAngle.first();
const scalar& angle = rotAxisAngle.second(); const scalar angle = rotAxisAngle.second();
Info<< "Rotating points " << nl Info<< "Rotating points " << nl
<< " about " << axis << nl << " about " << axis << nl
@ -380,35 +491,8 @@ int main(int argc, char *argv[])
} }
} }
List<scalar> scaling; // Output scaling
if (args.readListIfPresent("scale", scaling)) applyScaling(points, getScalingOpt("scale", args));
{
// readListIfPresent handles single or multiple values
if (scaling.size() == 1)
{
Info<< "Scaling points uniformly by " << scaling[0] << nl;
points *= scaling[0];
}
else if (scaling.size() == 3)
{
Info<< "Scaling points by ("
<< scaling[0] << " "
<< scaling[1] << " "
<< scaling[2] << ")" << nl;
points.replace(vector::X, scaling[0]*points.component(vector::X));
points.replace(vector::Y, scaling[1]*points.component(vector::Y));
points.replace(vector::Z, scaling[2]*points.component(vector::Z));
}
else
{
FatalError
<< "-scale with 1 or 3 components only" << nl
<< "given: " << args["scale"] << endl
<< exit(FatalError);
}
}
if (useOrigin) if (useOrigin)
{ {

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -63,33 +64,52 @@ int main(int argc, char *argv[])
argList::noParallel(); argList::noParallel();
argList::addArgument("input", "The input surface file"); argList::addArgument("input", "The input surface file");
argList::addArgument("output", "The output surface file"); argList::addArgument("output", "The output surface file");
argList::addOption
(
"steps",
"N",
"Number of refinement steps (default: 1)"
);
argList args(argc, argv); argList args(argc, argv);
const fileName surfFileName = args[1]; const fileName surfFileName(args[1]);
const fileName outFileName = args[2]; const fileName outFileName(args[2]);
Info<< "Reading surface from " << surfFileName << " ..." << endl; Info<< "Reading surface from " << surfFileName << " ..." << endl;
triSurface surf1(surfFileName); triSurface surf(surfFileName);
// Refine Info<< "Original surface:" << nl
triSurface surf2 = triSurfaceTools::redGreenRefine << " triangles :" << surf.size() << nl
( << " vertices(used):" << surf.nPoints() << endl;
surf1,
identity(surf1.size()) //Hack: refine all
);
Info<< "Original surface:" << endl
<< " triangles :" << surf1.size() << endl
<< " vertices(used):" << surf1.nPoints() << endl
<< "Refined surface:" << endl
<< " triangles :" << surf2.size() << endl
<< " vertices(used):" << surf2.nPoints() << endl << endl;
Info<< "Writing refined surface to " << outFileName << " ..." << endl; const label nsteps =
args.getCheckOrDefault<label>("steps", 1, labelMinMax::ge(1));
surf2.write(outFileName);
Info<< "Refining " << nsteps << " times" << flush;
for (label step = 0; step < nsteps; ++step)
{
Info<< '.' << flush;
surf = triSurfaceTools::redGreenRefine
(
surf,
identity(surf.size()) // Refine all
);
}
Info<< endl;
Info<< "Refined surface:" << nl
<< " triangles :" << surf.size() << nl
<< " vertices(used):" << surf.nPoints() << endl;
Info<< nl
<< "Writing refined surface to " << outFileName << " ..." << endl;
surf.write(outFileName);
Info<< "End\n" << endl; Info<< "End\n" << endl;

View File

@ -93,6 +93,84 @@ static bool hasReadWriteTypes(const word& readType, const word& writeType)
} }
// Retrieve scaling option
// - size 0 : no scaling
// - size 1 : uniform scaling
// - size 3 : non-uniform scaling
List<scalar> getScalingOpt(const word& optName, const argList& args)
{
// readListIfPresent handles single or multiple values
// - accept 1 or 3 values
List<scalar> scaling;
args.readListIfPresent(optName, scaling);
if (scaling.size() == 1)
{
// Uniform scaling
}
else if (scaling.size() == 3)
{
// Non-uniform, but may actually be uniform
if
(
equal(scaling[0], scaling[1])
&& equal(scaling[0], scaling[2])
)
{
scaling.resize(1);
}
}
else if (!scaling.empty())
{
FatalError
<< "Incorrect number of components, must be 1 or 3." << nl
<< " -" << optName << ' ' << args[optName].c_str() << endl
<< exit(FatalError);
}
if (scaling.size() == 1 && equal(scaling[0], 1))
{
// Scale factor 1 == no scaling
scaling.clear();
}
for (const scalar scale : scaling)
{
if (scale <= 0)
{
FatalError
<< "Invalid scaling value, must be positive." << nl
<< " -" << optName << ' ' << args[optName].c_str() << endl
<< exit(FatalError);
}
}
return scaling;
}
void applyScaling(pointField& points, const List<scalar>& scaling)
{
if (scaling.size() == 1)
{
Info<< "Scaling points uniformly by " << scaling[0] << nl;
points *= scaling[0];
}
else if (scaling.size() == 3)
{
Info<< "Scaling points by ("
<< scaling[0] << ' '
<< scaling[1] << ' '
<< scaling[2] << ')' << nl;
points.replace(vector::X, scaling[0]*points.component(vector::X));
points.replace(vector::Y, scaling[1]*points.component(vector::Y));
points.replace(vector::Z, scaling[2]*points.component(vector::Z));
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -106,11 +184,21 @@ int main(int argc, char *argv[])
argList::noParallel(); argList::noParallel();
argList::addArgument("input", "The input surface file"); argList::addArgument("input", "The input surface file");
argList::addArgument("output", "The output surface file"); argList::addArgument("output", "The output surface file");
argList::addBoolOption
(
"recentre",
"Recentre the bounding box before other operations"
);
argList::addOption argList::addOption
( (
"translate", "translate",
"vector", "vector",
"Translate by specified <vector> - eg, '(1 0 0)' before rotations" "Translate by specified <vector> before rotations"
);
argList::addBoolOption
(
"auto-origin",
"Use bounding box centre as origin for rotations"
); );
argList::addOption argList::addOption
( (
@ -144,10 +232,15 @@ int main(int argc, char *argv[])
); );
argList::addOption argList::addOption
( (
"scale", "read-scale",
"scalar | vector", "scalar | vector",
"Scale by the specified amount - Eg, for uniform [mm] to [m] scaling " "Uniform or non-uniform input scaling"
"use either '(0.001 0.001 0.001)' or simply '0.001'" );
argList::addOption
(
"write-scale",
"scalar | vector",
"Uniform or non-uniform output scaling"
); );
argList::addOption argList::addOption
( (
@ -162,18 +255,23 @@ int main(int argc, char *argv[])
"Output format (default: use file extension)" "Output format (default: use file extension)"
); );
// Backward compatibility and with transformPoints
argList::addOptionCompat("write-scale", {"scale", -2006});
argList args(argc, argv); argList args(argc, argv);
// Verify that an operation has been specified // Verify that an operation has been specified
{ {
const List<word> operationNames const List<word> operationNames
{ {
"recentre",
"translate", "translate",
"rotate", "rotate",
"rotate-angle", "rotate-angle",
"rollPitchYaw", "rollPitchYaw",
"yawPitchRoll", "yawPitchRoll",
"scale" "read-scale",
"write-scale"
}; };
if (!args.count(operationNames)) if (!args.count(operationNames))
@ -225,16 +323,34 @@ int main(int argc, char *argv[])
pointField points(surf1.points()); pointField points(surf1.points());
// Begin operations
// Input scaling
applyScaling(points, getScalingOpt("read-scale", args));
vector v; vector v;
if (args.found("recentre"))
{
v = boundBox(points).centre();
Info<< "Adjust centre " << v << " -> (0 0 0)" << endl;
points -= v;
}
if (args.readIfPresent("translate", v)) if (args.readIfPresent("translate", v))
{ {
Info<< "Translating points by " << v << endl; Info<< "Translating points by " << v << endl;
points += v; points += v;
} }
vector origin(Zero); vector origin;
const bool useOrigin = args.readIfPresent("origin", origin); bool useOrigin = args.readIfPresent("origin", origin);
if (args.found("auto-origin") && !useOrigin)
{
useOrigin = true;
origin = boundBox(points).centre();
}
if (useOrigin) if (useOrigin)
{ {
Info<< "Set origin for rotations to " << origin << endl; Info<< "Set origin for rotations to " << origin << endl;
@ -262,8 +378,8 @@ int main(int argc, char *argv[])
args.lookup("rotate-angle")() args.lookup("rotate-angle")()
); );
const vector& axis = rotAxisAngle.first(); const vector& axis = rotAxisAngle.first();
const scalar& angle = rotAxisAngle.second(); const scalar angle = rotAxisAngle.second();
Info<< "Rotating points " << nl Info<< "Rotating points " << nl
<< " about " << axis << nl << " about " << axis << nl
@ -299,44 +415,8 @@ int main(int argc, char *argv[])
points = transform(rot, points); points = transform(rot, points);
} }
List<scalar> scaling; // Output scaling
if (args.readListIfPresent("scale", scaling)) applyScaling(points, getScalingOpt("write-scale", args));
{
// readListIfPresent handles single or multiple values
if
(
scaling.size() == 1
||
(
scaling.size() == 3
&& equal(scaling[0], scaling[1])
&& equal(scaling[0], scaling[2])
)
)
{
Info<< "Scaling points uniformly by " << scaling[0] << nl;
points *= scaling[0];
}
else if (scaling.size() == 3)
{
Info<< "Scaling points by ("
<< scaling[0] << ' '
<< scaling[1] << ' '
<< scaling[2] << ')' << nl;
points.replace(vector::X, scaling[0]*points.component(vector::X));
points.replace(vector::Y, scaling[1]*points.component(vector::Y));
points.replace(vector::Z, scaling[2]*points.component(vector::Z));
}
else
{
FatalError
<< "-scale with 1 or 3 components only" << nl
<< "given: " << args["scale"] << endl
<< exit(FatalError);
}
}
if (useOrigin) if (useOrigin)
{ {

View File

@ -0,0 +1,11 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions
#------------------------------------------------------------------------------
cleanCase
rm -f constant/triSurface/inlet_sample*.obj
rm -f constant/triSurface/oversized_sample.obj
#------------------------------------------------------------------------------

View File

@ -0,0 +1,27 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
#------------------------------------------------------------------------------
runApplication blockMesh
# Extract some faces for sampling
runApplication surfaceMeshExtract \
-patches inlet -time 0 \
constant/triSurface/inlet_sample0.obj
# Recentre and inflate
runApplication surfaceTransformPoints \
-recentre \
-scale 3.5 \
constant/triSurface/inlet_sample0.obj \
constant/triSurface/inlet_sample1.obj
# Finer mesh
runApplication surfaceRefineRedGreen \
constant/triSurface/inlet_sample1.obj \
constant/triSurface/oversized_sample.obj
runApplication $(getApplication)
#------------------------------------------------------------------------------