WorldCoordinatesToParametricCoordinates functions
The general polygon version is not implemented yet because I need to change the way it is interpolated. To get wedge to work correctly, I had to change the interpolation slightly there. Previously the interpolation had a singularity at the tip.
This commit is contained in:
parent
936bbd33d0
commit
5bcad152e0
@ -147,16 +147,20 @@ VTKM_EXEC_EXPORT
|
||||
vtkm::Vec<typename FieldVecType::ComponentType,8>
|
||||
PermutePyramidToHex(const FieldVecType &field)
|
||||
{
|
||||
vtkm::Vec<typename FieldVecType::ComponentType,8> hexField;
|
||||
typedef typename FieldVecType::ComponentType T;
|
||||
|
||||
vtkm::Vec<T,8> hexField;
|
||||
|
||||
T baseCenter = T(0.25f)*(field[0]+field[1]+field[2]+field[3]);
|
||||
|
||||
hexField[0] = field[0];
|
||||
hexField[1] = field[1];
|
||||
hexField[2] = field[2];
|
||||
hexField[3] = field[3];
|
||||
hexField[4] = field[4];
|
||||
hexField[5] = field[4];
|
||||
hexField[6] = field[4];
|
||||
hexField[7] = field[4];
|
||||
hexField[4] = field[4]+(field[0]-baseCenter);
|
||||
hexField[5] = field[4]+(field[1]-baseCenter);
|
||||
hexField[6] = field[4]+(field[2]-baseCenter);
|
||||
hexField[7] = field[4]+(field[3]-baseCenter);
|
||||
|
||||
return hexField;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ NewtonsMethod(JacobianFunctor jacobianEvaluator,
|
||||
vtkm::Vec<ScalarType,Size> desiredFunctionOutput,
|
||||
vtkm::Vec<ScalarType,Size> initialGuess
|
||||
= vtkm::Vec<ScalarType,Size>(ScalarType(0)),
|
||||
ScalarType convergeDifference = 1e-3,
|
||||
ScalarType convergeDifference = ScalarType(1e-3),
|
||||
vtkm::IdComponent maxIterations = 10)
|
||||
{
|
||||
typedef vtkm::Vec<ScalarType,Size> VectorType;
|
||||
|
@ -23,7 +23,10 @@
|
||||
#include <vtkm/CellShape.h>
|
||||
#include <vtkm/Math.h>
|
||||
#include <vtkm/exec/Assert.h>
|
||||
#include <vtkm/exec/CellDerivative.h>
|
||||
#include <vtkm/exec/CellInterpolate.h>
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/exec/NewtonsMethod.h>
|
||||
|
||||
namespace vtkm {
|
||||
namespace exec {
|
||||
@ -554,6 +557,520 @@ ParametricCoordinatesPoint(vtkm::IdComponent numPoints,
|
||||
return pcoords;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename WorldCoordVector, typename PCoordType, typename CellShapeTag>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
ParametricCoordinatesToWorldCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const vtkm::Vec<PCoordType,3> &pcoords,
|
||||
CellShapeTag shape,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
return vtkm::exec::CellInterpolate(pointWCoords, pcoords, shape, worklet);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename WorldCoordVector, typename CellShapeTag>
|
||||
class JacobianFunctorQuad
|
||||
{
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,2> Vector2;
|
||||
typedef vtkm::Matrix<T,2,2> Matrix2x2;
|
||||
typedef vtkm::exec::internal::Space2D<T> SpaceType;
|
||||
|
||||
const WorldCoordVector *PointWCoords;
|
||||
const SpaceType *Space;
|
||||
|
||||
public:
|
||||
VTKM_EXEC_EXPORT
|
||||
JacobianFunctorQuad(
|
||||
const WorldCoordVector *pointWCoords,
|
||||
const SpaceType *space)
|
||||
: PointWCoords(pointWCoords), Space(space)
|
||||
{ }
|
||||
|
||||
VTKM_EXEC_EXPORT
|
||||
Matrix2x2 operator()(const Vector2 &pcoords) const
|
||||
{
|
||||
Matrix2x2 jacobian;
|
||||
vtkm::exec::internal::JacobianFor2DCell(
|
||||
*this->PointWCoords,
|
||||
vtkm::Vec<T,3>(pcoords[0],pcoords[1],0),
|
||||
*this->Space,
|
||||
jacobian,
|
||||
CellShapeTag());
|
||||
return jacobian;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WorldCoordVector, typename CellShapeTag>
|
||||
class CoordinatesFunctorQuad
|
||||
{
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,2> Vector2;
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
typedef vtkm::exec::internal::Space2D<T> SpaceType;
|
||||
|
||||
const WorldCoordVector *PointWCoords;
|
||||
const SpaceType *Space;
|
||||
const vtkm::exec::FunctorBase *Worklet;
|
||||
|
||||
public:
|
||||
VTKM_EXEC_EXPORT
|
||||
CoordinatesFunctorQuad(
|
||||
const WorldCoordVector *pointWCoords,
|
||||
const SpaceType *space,
|
||||
const vtkm::exec::FunctorBase *worklet)
|
||||
: PointWCoords(pointWCoords), Space(space), Worklet(worklet)
|
||||
{ }
|
||||
|
||||
VTKM_EXEC_EXPORT
|
||||
Vector2 operator()(Vector2 pcoords) const {
|
||||
Vector3 pcoords3D(pcoords[0], pcoords[1], 0);
|
||||
Vector3 wcoords =
|
||||
vtkm::exec::ParametricCoordinatesToWorldCoordinates(
|
||||
*this->PointWCoords, pcoords3D, CellShapeTag(), *this->Worklet);
|
||||
return this->Space->ConvertCoordToSpace(wcoords);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WorldCoordVector, typename CellShapeTag>
|
||||
class JacobianFunctor3DCell
|
||||
{
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
typedef vtkm::Matrix<T,3,3> Matrix3x3;
|
||||
|
||||
const WorldCoordVector *PointWCoords;
|
||||
|
||||
public:
|
||||
VTKM_EXEC_EXPORT
|
||||
JacobianFunctor3DCell(
|
||||
const WorldCoordVector *pointWCoords)
|
||||
: PointWCoords(pointWCoords)
|
||||
{ }
|
||||
|
||||
VTKM_EXEC_EXPORT
|
||||
Matrix3x3 operator()(const Vector3 &pcoords) const
|
||||
{
|
||||
Matrix3x3 jacobian;
|
||||
vtkm::exec::internal::JacobianFor3DCell(*this->PointWCoords,
|
||||
pcoords,
|
||||
jacobian,
|
||||
CellShapeTag());
|
||||
return jacobian;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WorldCoordVector, typename CellShapeTag>
|
||||
class CoordinatesFunctor3DCell
|
||||
{
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
|
||||
const WorldCoordVector *PointWCoords;
|
||||
const vtkm::exec::FunctorBase *Worklet;
|
||||
|
||||
public:
|
||||
VTKM_EXEC_EXPORT
|
||||
CoordinatesFunctor3DCell(const WorldCoordVector *pointWCoords,
|
||||
const vtkm::exec::FunctorBase *worklet)
|
||||
: PointWCoords(pointWCoords), Worklet(worklet)
|
||||
{ }
|
||||
|
||||
VTKM_EXEC_EXPORT
|
||||
Vector3 operator()(Vector3 pcoords) const {
|
||||
return
|
||||
vtkm::exec::ParametricCoordinatesToWorldCoordinates(
|
||||
*this->PointWCoords, pcoords, CellShapeTag(), *this->Worklet);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WorldCoordVector, typename CellShapeTag>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates3D(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
CellShapeTag,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
return vtkm::exec::NewtonsMethod(
|
||||
JacobianFunctor3DCell<WorldCoordVector,CellShapeTag>(&pointWCoords),
|
||||
CoordinatesFunctor3DCell<WorldCoordVector,CellShapeTag>(&pointWCoords, &worklet),
|
||||
wcoords,
|
||||
typename WorldCoordVector::ComponentType(0.5f,0.5f,0.5f));
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagGeneric shape,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
switch (shape.Id)
|
||||
{
|
||||
vtkmGenericCellShapeMacro(
|
||||
return WorldCoordinatesToParametricCoordinates(pointWCoords,
|
||||
wcoords,
|
||||
CellShapeTag(),
|
||||
worklet));
|
||||
default:
|
||||
worklet.RaiseError("Unknown cell shape sent to world 2 parametric.");
|
||||
return typename WorldCoordVector::ComponentType();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &,
|
||||
const typename WorldCoordVector::ComponentType &,
|
||||
vtkm::CellShapeTagEmpty,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
worklet.RaiseError("Attempted to find point coordinates in empty cell.");
|
||||
return typename WorldCoordVector::ComponentType();
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &,
|
||||
vtkm::CellShapeTagVertex,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 3, worklet);
|
||||
return typename WorldCoordVector::ComponentType(0, 0, 0);
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagLine,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 2, worklet);
|
||||
|
||||
// Because this is a line, there is only one vaild parametric coordinate. Let
|
||||
// vec be the vector from the first point to the second point
|
||||
// (pointWCoords[1] - pointWCoords[0]), which is the direction of the line.
|
||||
// dot(vec,wcoords-pointWCoords[0])/mag(vec) is the orthoginal projection of
|
||||
// wcoords on the line and represents the distance between the orthoginal
|
||||
// projection and pointWCoords[0]. The parametric coordinate is the fraction
|
||||
// of this over the length of the segment, which is mag(vec). Thus, the
|
||||
// parametric coordinate is dot(vec,wcoords-pointWCoords[0])/mag(vec)^2.
|
||||
|
||||
typedef typename WorldCoordVector::ComponentType Vector3;
|
||||
typedef typename Vector3::ComponentType T;
|
||||
|
||||
Vector3 vec = pointWCoords[1] - pointWCoords[0];
|
||||
T numerator = vtkm::dot(vec, wcoords - pointWCoords[0]);
|
||||
T denominator = vtkm::MagnitudeSquared(vec);
|
||||
|
||||
return Vector3(numerator/denominator, 0, 0);
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagTriangle,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 3, worklet);
|
||||
|
||||
// We will solve the world to parametric coordinates problem geometrically.
|
||||
// Consider the parallelogram formed by wcoords and p0 of the triangle and
|
||||
// the two adjacent edges. This parallelogram is equivalent to the
|
||||
// axis-aligned rectangle anchored at the origin of parametric space.
|
||||
//
|
||||
// p2 |\ (1,0) |\ //
|
||||
// | \ | \ //
|
||||
// | \ | \ //
|
||||
// | \ | \ //
|
||||
// | \ | \ //
|
||||
// | \ | (u,v) \ //
|
||||
// | --- \ |-------* \ //
|
||||
// | ---*wcoords | | \ //
|
||||
// | | \ | | \ //
|
||||
// p0 *--- | \ (0,0) *------------------\ (1,0) //
|
||||
// ---| \ //
|
||||
// x-- \ //
|
||||
// --- \ //
|
||||
// ---\ p1 //
|
||||
//
|
||||
// In this diagram, the distance between p0 and the point marked x divided by
|
||||
// the length of the edge it is on is equal, by proportionality, to the u
|
||||
// parametric coordiante. (The v coordinate follows the other edge
|
||||
// accordingly.) Thus, if we can find the interesection at x (or more
|
||||
// specifically the distance between p0 and x), then we can find that
|
||||
// parametric coordinate.
|
||||
//
|
||||
// Because the triangle is in 3-space, we are actually going to intersect the
|
||||
// edge with a plane that is parallel to the opposite edge of p0 and
|
||||
// perpendicular to the triangle. This is partially because it is easy to
|
||||
// find the intersection between a plane and a line and partially because the
|
||||
// computation will work for points not on the plane. (The result is
|
||||
// equivalent to a point projected on the plane.)
|
||||
//
|
||||
// First, we define an implicit plane as:
|
||||
//
|
||||
// dot((p - wcoords), planeNormal) = 0
|
||||
//
|
||||
// where planeNormal is the normal to the plane (easily computed from the
|
||||
// triangle), and p is any point in the plane. Next, we define the parametric
|
||||
// form of the line:
|
||||
//
|
||||
// p(d) = (p1 - p0)d + p0
|
||||
//
|
||||
// Where d is the fraction of distance from p0 toward p1. Note that d is
|
||||
// actually equal to the parametric coordinate we are trying to find. Once we
|
||||
// compute it, we are done. We can skip the part about finding the actual
|
||||
// coordinates of the intersection.
|
||||
//
|
||||
// Solving for the interesection is as simple as substituting the line's
|
||||
// definition of p(d) into p for the plane equation. With some basic algebra
|
||||
// you get:
|
||||
//
|
||||
// d = dot((wcoords - p0), planeNormal)/dot((p1-p0), planeNormal)
|
||||
//
|
||||
// From here, the u coordiante is simply d. The v coordinate follows
|
||||
// similarly.
|
||||
//
|
||||
|
||||
typedef typename WorldCoordVector::ComponentType Vector3;
|
||||
typedef typename Vector3::ComponentType T;
|
||||
|
||||
Vector3 pcoords(T(0));
|
||||
Vector3 triangleNormal =
|
||||
vtkm::TriangleNormal(pointWCoords[0], pointWCoords[1], pointWCoords[2]);
|
||||
|
||||
for (vtkm::IdComponent dimension = 0; dimension < 2; dimension++)
|
||||
{
|
||||
Vector3 p0 = pointWCoords[0];
|
||||
Vector3 p1 = pointWCoords[dimension+1];
|
||||
Vector3 p2 = pointWCoords[2-dimension];
|
||||
Vector3 planeNormal = vtkm::Cross(triangleNormal, p2-p0);
|
||||
|
||||
T d = vtkm::dot(wcoords - p0, planeNormal)/vtkm::dot(p1 - p0, planeNormal);
|
||||
|
||||
pcoords[dimension] = d;
|
||||
}
|
||||
|
||||
return pcoords;
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &vtkmNotUsed(pointWCoords),
|
||||
const typename WorldCoordVector::ComponentType &vtkmNotUsed(wcoords),
|
||||
vtkm::CellShapeTagPolygon,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
worklet.RaiseError("Not implemented yet.");
|
||||
return typename WorldCoordVector::ComponentType();
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagPixel,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 4, worklet);
|
||||
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,2> Vector2;
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
|
||||
// We have an underdetermined system in 3D, so create a 2D space in the
|
||||
// plane that the polygon sits.
|
||||
vtkm::exec::internal::Space2D<T> space(
|
||||
pointWCoords[0], pointWCoords[1], pointWCoords[3]);
|
||||
|
||||
Vector2 pcoords =
|
||||
vtkm::exec::NewtonsMethod(
|
||||
detail::JacobianFunctorQuad<WorldCoordVector,vtkm::CellShapeTagPixel>(&pointWCoords, &space),
|
||||
detail::CoordinatesFunctorQuad<WorldCoordVector,vtkm::CellShapeTagPixel>(&pointWCoords, &space, &worklet),
|
||||
space.ConvertCoordToSpace(wcoords),
|
||||
Vector2(0.5f, 0.5f));
|
||||
|
||||
return Vector3(pcoords[0], pcoords[1], 0);
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagQuad,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 4, worklet);
|
||||
|
||||
typedef typename WorldCoordVector::ComponentType::ComponentType T;
|
||||
typedef vtkm::Vec<T,2> Vector2;
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
|
||||
// We have an underdetermined system in 3D, so create a 2D space in the
|
||||
// plane that the polygon sits.
|
||||
vtkm::exec::internal::Space2D<T> space(
|
||||
pointWCoords[0], pointWCoords[1], pointWCoords[3]);
|
||||
|
||||
Vector2 pcoords =
|
||||
vtkm::exec::NewtonsMethod(
|
||||
detail::JacobianFunctorQuad<WorldCoordVector,vtkm::CellShapeTagQuad>(&pointWCoords, &space),
|
||||
detail::CoordinatesFunctorQuad<WorldCoordVector,vtkm::CellShapeTagQuad>(&pointWCoords, &space, &worklet),
|
||||
space.ConvertCoordToSpace(wcoords),
|
||||
Vector2(0.5f, 0.5f));
|
||||
|
||||
return Vector3(pcoords[0], pcoords[1], 0);
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagTetra,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 4, worklet);
|
||||
|
||||
// We solve the world to parametric coordinates problem for tetrahedra
|
||||
// similarly to that for triangles. Before understanding this code, you
|
||||
// should understand the triangle code. Go ahead. Read it now.
|
||||
//
|
||||
// The tetrahedron code is an obvious extension of the triangle code by
|
||||
// considering the parallelpiped formed by wcoords and p0 of the triangle
|
||||
// and the three adjacent faces. This parallelpiped is equivalent to the
|
||||
// axis-aligned cuboid anchored at the origin of parametric space.
|
||||
//
|
||||
// Just like the triangle, we compute the parametric coordinate for each axis
|
||||
// by intersecting a plane with each edge emanating from p0. The plane is
|
||||
// defined by the one that goes through wcoords (duh) and is parallel to the
|
||||
// plane formed by the other two edges emanating from p0 (as dictated by the
|
||||
// aforementioned parallelpiped).
|
||||
//
|
||||
// In review, by parameterizing the line by fraction of distance the distance
|
||||
// from p0 to the adjacent point (which is itself the parametric coordinate
|
||||
// we are after), we get the following definition for the intersection.
|
||||
//
|
||||
// d = dot((wcoords - p0), planeNormal)/dot((p1-p0), planeNormal)
|
||||
//
|
||||
|
||||
typedef typename WorldCoordVector::ComponentType Vector3;
|
||||
typedef typename Vector3::ComponentType T;
|
||||
|
||||
Vector3 pcoords;
|
||||
|
||||
const Vector3 vec0 = pointWCoords[1] - pointWCoords[0];
|
||||
const Vector3 vec1 = pointWCoords[2] - pointWCoords[0];
|
||||
const Vector3 vec2 = pointWCoords[3] - pointWCoords[0];
|
||||
const Vector3 coordVec = wcoords - pointWCoords[0];
|
||||
|
||||
Vector3 planeNormal = vtkm::Cross(vec1, vec2);
|
||||
pcoords[0] = vtkm::dot(coordVec, planeNormal)/vtkm::dot(vec0, planeNormal);
|
||||
|
||||
planeNormal = vtkm::Cross(vec0, vec2);
|
||||
pcoords[1] = vtkm::dot(coordVec, planeNormal)/vtkm::dot(vec1, planeNormal);
|
||||
|
||||
planeNormal = vtkm::Cross(vec0, vec1);
|
||||
pcoords[2] = vtkm::dot(coordVec, planeNormal)/vtkm::dot(vec2, planeNormal);
|
||||
|
||||
return pcoords;
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagVoxel,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 8, worklet);
|
||||
|
||||
return detail::WorldCoordinatesToParametricCoordinates3D(
|
||||
pointWCoords, wcoords, vtkm::CellShapeTagVoxel(), worklet);
|
||||
}
|
||||
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagHexahedron,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 8, worklet);
|
||||
|
||||
return detail::WorldCoordinatesToParametricCoordinates3D(
|
||||
pointWCoords, wcoords, vtkm::CellShapeTagHexahedron(), worklet);
|
||||
}
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagWedge,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 6, worklet);
|
||||
|
||||
return detail::WorldCoordinatesToParametricCoordinates3D(
|
||||
pointWCoords, wcoords, vtkm::CellShapeTagWedge(), worklet);
|
||||
}
|
||||
|
||||
|
||||
template<typename WorldCoordVector>
|
||||
VTKM_EXEC_EXPORT
|
||||
typename WorldCoordVector::ComponentType
|
||||
WorldCoordinatesToParametricCoordinates(
|
||||
const WorldCoordVector &pointWCoords,
|
||||
const typename WorldCoordVector::ComponentType &wcoords,
|
||||
vtkm::CellShapeTagPyramid,
|
||||
const vtkm::exec::FunctorBase &worklet)
|
||||
{
|
||||
VTKM_ASSERT_EXEC(pointWCoords.GetNumberOfComponents() == 5, worklet);
|
||||
|
||||
return detail::WorldCoordinatesToParametricCoordinates3D(
|
||||
pointWCoords, wcoords, vtkm::CellShapeTagPyramid(), worklet);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // namespace vtkm::exec
|
||||
|
||||
|
@ -24,5 +24,6 @@ set(unit_tests
|
||||
UnitTestCellDerivative.cxx
|
||||
UnitTestCellInterpolate.cxx
|
||||
UnitTestNewtonsMethod.cxx
|
||||
UnitTestParametricCoordinates.cxx
|
||||
)
|
||||
vtkm_unit_tests(SOURCES ${unit_tests})
|
||||
|
@ -19,8 +19,8 @@
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/exec/CellDerivative.h>
|
||||
#include <vtkm/exec/ParametricCoordinates.h>
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/exec/ParametricCoordinates.h>
|
||||
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
|
||||
|
||||
#include <vtkm/CellTraits.h>
|
||||
|
305
vtkm/exec/testing/UnitTestParametricCoordinates.cxx
Normal file
305
vtkm/exec/testing/UnitTestParametricCoordinates.cxx
Normal file
@ -0,0 +1,305 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//
|
||||
// Copyright 2015 Sandia Corporation.
|
||||
// Copyright 2015 UT-Battelle, LLC.
|
||||
// Copyright 2015 Los Alamos National Security.
|
||||
//
|
||||
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
||||
// the U.S. Government retains certain rights in this software.
|
||||
//
|
||||
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
||||
// Laboratory (LANL), the U.S. Government retains certain rights in
|
||||
// this software.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/exec/ParametricCoordinates.h>
|
||||
|
||||
#include <vtkm/CellTraits.h>
|
||||
#include <vtkm/VecVariable.h>
|
||||
|
||||
#include <vtkm/testing/Testing.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/uniform_real_distribution.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace {
|
||||
|
||||
boost::mt19937 g_RandomGenerator;
|
||||
|
||||
static const vtkm::IdComponent MAX_POINTS = 8;
|
||||
|
||||
template<typename CellShapeTag>
|
||||
void GetMinMaxPoints(CellShapeTag,
|
||||
vtkm::CellTraitsTagSizeFixed,
|
||||
vtkm::IdComponent &minPoints,
|
||||
vtkm::IdComponent &maxPoints)
|
||||
{
|
||||
// If this line fails, then MAX_POINTS is not large enough to support all
|
||||
// cell shapes.
|
||||
BOOST_STATIC_ASSERT((vtkm::CellTraits<CellShapeTag>::NUM_POINTS <= MAX_POINTS));
|
||||
minPoints = maxPoints = vtkm::CellTraits<CellShapeTag>::NUM_POINTS;
|
||||
}
|
||||
|
||||
template<typename CellShapeTag>
|
||||
void GetMinMaxPoints(CellShapeTag,
|
||||
vtkm::CellTraitsTagSizeVariable,
|
||||
vtkm::IdComponent &minPoints,
|
||||
vtkm::IdComponent &maxPoints)
|
||||
{
|
||||
minPoints = 1;
|
||||
maxPoints = MAX_POINTS;
|
||||
}
|
||||
|
||||
template<typename PointWCoordsType,
|
||||
typename T,
|
||||
typename CellShapeTag>
|
||||
static void CompareCoordinates(const PointWCoordsType &pointWCoords,
|
||||
vtkm::Vec<T,3> truePCoords,
|
||||
vtkm::Vec<T,3> trueWCoords,
|
||||
CellShapeTag shape)
|
||||
{
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
|
||||
// Stuff to fake running in the execution environment.
|
||||
char messageBuffer[256];
|
||||
messageBuffer[0] = '\0';
|
||||
vtkm::exec::internal::ErrorMessageBuffer errorMessage(messageBuffer, 256);
|
||||
vtkm::exec::FunctorBase workletProxy;
|
||||
workletProxy.SetErrorMessageBuffer(errorMessage);
|
||||
|
||||
Vector3 computedWCoords
|
||||
= vtkm::exec::ParametricCoordinatesToWorldCoordinates(pointWCoords,
|
||||
truePCoords,
|
||||
shape,
|
||||
workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
VTKM_TEST_ASSERT(test_equal(computedWCoords, trueWCoords),
|
||||
"Computed wrong world coords from parametric coords.");
|
||||
|
||||
Vector3 computedPCoords
|
||||
= vtkm::exec::WorldCoordinatesToParametricCoordinates(pointWCoords,
|
||||
trueWCoords,
|
||||
shape,
|
||||
workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
VTKM_TEST_ASSERT(test_equal(computedPCoords, truePCoords, 0.01),
|
||||
"Computed wrong parametric coords from world coords.");
|
||||
}
|
||||
|
||||
template<typename PointWCoordsType, typename CellShapeTag>
|
||||
void TestPCoordsSpecial(const PointWCoordsType &pointWCoords,
|
||||
CellShapeTag shape)
|
||||
{
|
||||
typedef typename PointWCoordsType::ComponentType Vector3;
|
||||
typedef typename Vector3::ComponentType T;
|
||||
|
||||
// Stuff to fake running in the execution environment.
|
||||
char messageBuffer[256];
|
||||
messageBuffer[0] = '\0';
|
||||
vtkm::exec::internal::ErrorMessageBuffer errorMessage(messageBuffer, 256);
|
||||
vtkm::exec::FunctorBase workletProxy;
|
||||
workletProxy.SetErrorMessageBuffer(errorMessage);
|
||||
|
||||
const vtkm::IdComponent numPoints = pointWCoords.GetNumberOfComponents();
|
||||
|
||||
std::cout << " Test parametric coordinates at cell nodes." << std::endl;
|
||||
for (vtkm::IdComponent pointIndex = 0; pointIndex < numPoints; pointIndex++)
|
||||
{
|
||||
Vector3 pcoords;
|
||||
vtkm::exec::ParametricCoordinatesPoint(
|
||||
numPoints, pointIndex, pcoords, shape, workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
Vector3 wcoords = pointWCoords[pointIndex];
|
||||
CompareCoordinates(pointWCoords, pcoords, wcoords, shape);
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << " Test parametric coordinates at cell center." << std::endl;
|
||||
Vector3 wcoords = pointWCoords[0];
|
||||
for (vtkm::IdComponent pointIndex = 1; pointIndex < numPoints; pointIndex++)
|
||||
{
|
||||
wcoords = wcoords + pointWCoords[pointIndex];
|
||||
}
|
||||
wcoords = wcoords/Vector3(T(numPoints));
|
||||
|
||||
Vector3 pcoords;
|
||||
vtkm::exec::ParametricCoordinatesCenter(
|
||||
numPoints, pcoords, shape, workletProxy);
|
||||
CompareCoordinates(pointWCoords, pcoords, wcoords, shape);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PointWCoordsType, typename CellShapeTag>
|
||||
void TestPCoordsSample(const PointWCoordsType &pointWCoords,
|
||||
CellShapeTag shape)
|
||||
{
|
||||
typedef typename PointWCoordsType::ComponentType Vector3;
|
||||
|
||||
// Stuff to fake running in the execution environment.
|
||||
char messageBuffer[256];
|
||||
messageBuffer[0] = '\0';
|
||||
vtkm::exec::internal::ErrorMessageBuffer errorMessage(messageBuffer, 256);
|
||||
vtkm::exec::FunctorBase workletProxy;
|
||||
workletProxy.SetErrorMessageBuffer(errorMessage);
|
||||
|
||||
const vtkm::IdComponent numPoints = pointWCoords.GetNumberOfComponents();
|
||||
|
||||
boost::random::uniform_real_distribution<vtkm::FloatDefault> randomDist;
|
||||
|
||||
for (vtkm::IdComponent trial = 0; trial < 5; trial++)
|
||||
{
|
||||
// Generate a random pcoords that we know is in the cell.
|
||||
vtkm::Vec<vtkm::FloatDefault,3> pcoords(0);
|
||||
vtkm::FloatDefault totalWeight = 0;
|
||||
for (vtkm::IdComponent pointIndex = 0;
|
||||
pointIndex < numPoints;
|
||||
pointIndex++)
|
||||
{
|
||||
vtkm::Vec<vtkm::FloatDefault,3> pointPcoords =
|
||||
vtkm::exec::ParametricCoordinatesPoint(numPoints,
|
||||
pointIndex,
|
||||
shape,
|
||||
workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
vtkm::FloatDefault weight = randomDist(g_RandomGenerator);
|
||||
pcoords = pcoords + weight*pointPcoords;
|
||||
totalWeight += weight;
|
||||
}
|
||||
pcoords = (1/totalWeight)*pcoords;
|
||||
|
||||
std::cout << " Test parametric coordinates at " << pcoords << std::endl;
|
||||
|
||||
// If you convert to world coordinates and back, you should get the
|
||||
// same value.
|
||||
Vector3 wcoords =
|
||||
vtkm::exec::ParametricCoordinatesToWorldCoordinates(pointWCoords,
|
||||
pcoords,
|
||||
shape,
|
||||
workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
Vector3 computedPCoords =
|
||||
vtkm::exec::WorldCoordinatesToParametricCoordinates(pointWCoords,
|
||||
wcoords,
|
||||
shape,
|
||||
workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal(pcoords, computedPCoords, 0.01),
|
||||
"pcoord/wcoord transform not symmetrical");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PointWCoordsType, typename CellShellTag>
|
||||
static void TestPCoords(const PointWCoordsType &pointWCoords,
|
||||
CellShellTag shape)
|
||||
{
|
||||
TestPCoordsSpecial(pointWCoords, shape);
|
||||
TestPCoordsSample(pointWCoords, shape);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct TestPCoordsFunctor
|
||||
{
|
||||
typedef vtkm::Vec<T,3> Vector3;
|
||||
typedef vtkm::VecVariable<Vector3,MAX_POINTS> PointWCoordType;
|
||||
|
||||
template<typename CellShapeTag>
|
||||
PointWCoordType MakePointWCoords(CellShapeTag,
|
||||
vtkm::IdComponent numPoints) const
|
||||
{
|
||||
// Stuff to fake running in the execution environment.
|
||||
char messageBuffer[256];
|
||||
messageBuffer[0] = '\0';
|
||||
vtkm::exec::internal::ErrorMessageBuffer errorMessage(messageBuffer, 256);
|
||||
vtkm::exec::FunctorBase workletProxy;
|
||||
workletProxy.SetErrorMessageBuffer(errorMessage);
|
||||
|
||||
boost::random::uniform_real_distribution<T> randomDist(-1,1);
|
||||
|
||||
Vector3 sheerVec(randomDist(g_RandomGenerator),
|
||||
randomDist(g_RandomGenerator),
|
||||
0);
|
||||
|
||||
PointWCoordType pointWCoords;
|
||||
for (vtkm::IdComponent pointIndex = 0; pointIndex < numPoints; pointIndex++)
|
||||
{
|
||||
Vector3 pcoords;
|
||||
vtkm::exec::ParametricCoordinatesPoint(
|
||||
numPoints, pointIndex, pcoords, CellShapeTag(), workletProxy);
|
||||
VTKM_TEST_ASSERT(!errorMessage.IsErrorRaised(), messageBuffer);
|
||||
|
||||
Vector3 wCoords = Vector3(pcoords[0],
|
||||
pcoords[1],
|
||||
pcoords[2] + vtkm::dot(pcoords,sheerVec));
|
||||
pointWCoords.Append(wCoords);
|
||||
}
|
||||
|
||||
return pointWCoords;
|
||||
}
|
||||
|
||||
template<typename CellShapeTag>
|
||||
void operator()(CellShapeTag) const
|
||||
{
|
||||
vtkm::IdComponent minPoints;
|
||||
vtkm::IdComponent maxPoints;
|
||||
GetMinMaxPoints(CellShapeTag(),
|
||||
typename vtkm::CellTraits<CellShapeTag>::IsSizeFixed(),
|
||||
minPoints,
|
||||
maxPoints);
|
||||
|
||||
std::cout << "--- Test shape tag directly" << std::endl;
|
||||
for (vtkm::IdComponent numPoints = minPoints;
|
||||
numPoints <= maxPoints;
|
||||
numPoints++)
|
||||
{
|
||||
TestPCoords(this->MakePointWCoords(CellShapeTag(), numPoints),
|
||||
CellShapeTag());
|
||||
}
|
||||
|
||||
std::cout << "--- Test generic shape tag" << std::endl;
|
||||
vtkm::CellShapeTagGeneric genericShape(CellShapeTag::Id);
|
||||
for (vtkm::IdComponent numPoints = minPoints;
|
||||
numPoints <= maxPoints;
|
||||
numPoints++)
|
||||
{
|
||||
TestPCoords(this->MakePointWCoords(CellShapeTag(), numPoints),
|
||||
genericShape);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(vtkm::CellShapeTagEmpty) const
|
||||
{
|
||||
std::cout << "Skipping empty cell shape. No points." << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void TestAllPCoords()
|
||||
{
|
||||
vtkm::UInt32 seed = static_cast<vtkm::UInt32>(time(NULL));
|
||||
std::cout << "Seed: " << seed << std::endl;
|
||||
g_RandomGenerator.seed(seed);
|
||||
|
||||
std::cout << "======== Float32 ==========================" << std::endl;
|
||||
vtkm::testing::Testing::TryAllCellShapes(TestPCoordsFunctor<vtkm::Float32>());
|
||||
std::cout << "======== Float64 ==========================" << std::endl;
|
||||
vtkm::testing::Testing::TryAllCellShapes(TestPCoordsFunctor<vtkm::Float64>());
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
int UnitTestParametricCoordinates(int, char *[])
|
||||
{
|
||||
return vtkm::testing::Testing::Run(TestAllPCoords);
|
||||
}
|
Loading…
Reference in New Issue
Block a user