1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 
11 #include <vtkm/cont/testing/Testing.h>
12 #include <vtkm/filter/PointTransform.h>
13 
14 #include <random>
15 #include <string>
16 #include <vector>
17 
18 namespace
19 {
20 std::mt19937 randGenerator;
21 
MakePointTransformTestDataSet()22 vtkm::cont::DataSet MakePointTransformTestDataSet()
23 {
24   vtkm::cont::DataSet dataSet;
25 
26   std::vector<vtkm::Vec3f> coordinates;
27   const vtkm::Id dim = 5;
28   for (vtkm::Id j = 0; j < dim; ++j)
29   {
30     vtkm::FloatDefault z =
31       static_cast<vtkm::FloatDefault>(j) / static_cast<vtkm::FloatDefault>(dim - 1);
32     for (vtkm::Id i = 0; i < dim; ++i)
33     {
34       vtkm::FloatDefault x =
35         static_cast<vtkm::FloatDefault>(i) / static_cast<vtkm::FloatDefault>(dim - 1);
36       vtkm::FloatDefault y = (x * x + z * z) / 2.0f;
37       coordinates.push_back(vtkm::make_Vec(x, y, z));
38     }
39   }
40 
41   vtkm::Id numCells = (dim - 1) * (dim - 1);
42   dataSet.AddCoordinateSystem(
43     vtkm::cont::make_CoordinateSystem("coordinates", coordinates, vtkm::CopyFlag::On));
44 
45   vtkm::cont::CellSetExplicit<> cellSet;
46   cellSet.PrepareToAddCells(numCells, numCells * 4);
47   for (vtkm::Id j = 0; j < dim - 1; ++j)
48   {
49     for (vtkm::Id i = 0; i < dim - 1; ++i)
50     {
51       cellSet.AddCell(vtkm::CELL_SHAPE_QUAD,
52                       4,
53                       vtkm::make_Vec<vtkm::Id>(
54                         j * dim + i, j * dim + i + 1, (j + 1) * dim + i + 1, (j + 1) * dim + i));
55     }
56   }
57   cellSet.CompleteAddingCells(vtkm::Id(coordinates.size()));
58 
59   dataSet.SetCellSet(cellSet);
60   return dataSet;
61 }
62 
ValidatePointTransform(const vtkm::cont::CoordinateSystem & coords,const std::string fieldName,const vtkm::cont::DataSet & result,const vtkm::Matrix<vtkm::FloatDefault,4,4> & matrix)63 void ValidatePointTransform(const vtkm::cont::CoordinateSystem& coords,
64                             const std::string fieldName,
65                             const vtkm::cont::DataSet& result,
66                             const vtkm::Matrix<vtkm::FloatDefault, 4, 4>& matrix)
67 {
68   //verify the result
69   VTKM_TEST_ASSERT(result.HasField(fieldName, vtkm::cont::Field::Association::POINTS),
70                    "Output field missing.");
71 
72   vtkm::cont::ArrayHandle<vtkm::Vec3f> resultArrayHandle;
73   result.GetField(fieldName, vtkm::cont::Field::Association::POINTS)
74     .GetData()
75     .AsArrayHandle(resultArrayHandle);
76 
77   auto outPointsArrayHandle = result.GetCoordinateSystem().GetDataAsMultiplexer();
78 
79   auto points = coords.GetDataAsMultiplexer();
80   VTKM_TEST_ASSERT(points.GetNumberOfValues() == resultArrayHandle.GetNumberOfValues(),
81                    "Incorrect number of points in point transform");
82 
83   auto pointsPortal = points.ReadPortal();
84   auto resultsPortal = resultArrayHandle.ReadPortal();
85   auto outPointsPortal = outPointsArrayHandle.ReadPortal();
86 
87   for (vtkm::Id i = 0; i < points.GetNumberOfValues(); i++)
88   {
89     VTKM_TEST_ASSERT(
90       test_equal(resultsPortal.Get(i), vtkm::Transform3DPoint(matrix, pointsPortal.Get(i))),
91       "Wrong result for PointTransform worklet");
92     VTKM_TEST_ASSERT(
93       test_equal(outPointsPortal.Get(i), vtkm::Transform3DPoint(matrix, pointsPortal.Get(i))),
94       "Wrong result for PointTransform worklet");
95   }
96 }
97 
98 
TestPointTransformTranslation(const vtkm::cont::DataSet & ds,const vtkm::Vec3f & trans)99 void TestPointTransformTranslation(const vtkm::cont::DataSet& ds, const vtkm::Vec3f& trans)
100 {
101   vtkm::filter::PointTransform filter;
102 
103   filter.SetOutputFieldName("translation");
104   filter.SetTranslation(trans);
105   vtkm::cont::DataSet result = filter.Execute(ds);
106 
107   ValidatePointTransform(
108     ds.GetCoordinateSystem(), "translation", result, Transform3DTranslate(trans));
109 }
110 
TestPointTransformScale(const vtkm::cont::DataSet & ds,const vtkm::Vec3f & scale)111 void TestPointTransformScale(const vtkm::cont::DataSet& ds, const vtkm::Vec3f& scale)
112 {
113   vtkm::filter::PointTransform filter;
114 
115   filter.SetOutputFieldName("scale");
116   filter.SetScale(scale);
117   vtkm::cont::DataSet result = filter.Execute(ds);
118 
119   ValidatePointTransform(ds.GetCoordinateSystem(), "scale", result, Transform3DScale(scale));
120 }
121 
TestPointTransformRotation(const vtkm::cont::DataSet & ds,const vtkm::FloatDefault & angle,const vtkm::Vec3f & axis)122 void TestPointTransformRotation(const vtkm::cont::DataSet& ds,
123                                 const vtkm::FloatDefault& angle,
124                                 const vtkm::Vec3f& axis)
125 {
126   vtkm::filter::PointTransform filter;
127 
128   filter.SetOutputFieldName("rotation");
129   filter.SetRotation(angle, axis);
130   vtkm::cont::DataSet result = filter.Execute(ds);
131 
132   ValidatePointTransform(
133     ds.GetCoordinateSystem(), "rotation", result, Transform3DRotate(angle, axis));
134 }
135 }
136 
TestPointTransform()137 void TestPointTransform()
138 {
139   std::cout << "Testing PointTransform Worklet" << std::endl;
140 
141   vtkm::cont::DataSet ds = MakePointTransformTestDataSet();
142   int N = 41;
143 
144   //Test translation
145   TestPointTransformTranslation(ds, vtkm::Vec3f(0, 0, 0));
146   TestPointTransformTranslation(ds, vtkm::Vec3f(1, 1, 1));
147   TestPointTransformTranslation(ds, vtkm::Vec3f(-1, -1, -1));
148 
149   std::uniform_real_distribution<vtkm::FloatDefault> transDist(-100, 100);
150   for (int i = 0; i < N; i++)
151     TestPointTransformTranslation(
152       ds,
153       vtkm::Vec3f(transDist(randGenerator), transDist(randGenerator), transDist(randGenerator)));
154 
155   //Test scaling
156   TestPointTransformScale(ds, vtkm::Vec3f(1, 1, 1));
157   TestPointTransformScale(ds, vtkm::Vec3f(.23f, .23f, .23f));
158   TestPointTransformScale(ds, vtkm::Vec3f(1, 2, 3));
159   TestPointTransformScale(ds, vtkm::Vec3f(3.23f, 9.23f, 4.23f));
160 
161   std::uniform_real_distribution<vtkm::FloatDefault> scaleDist(0.0001f, 100);
162   for (int i = 0; i < N; i++)
163   {
164     TestPointTransformScale(ds, vtkm::Vec3f(scaleDist(randGenerator)));
165     TestPointTransformScale(
166       ds,
167       vtkm::Vec3f(scaleDist(randGenerator), scaleDist(randGenerator), scaleDist(randGenerator)));
168   }
169 
170   //Test rotation
171   std::vector<vtkm::FloatDefault> angles;
172   std::uniform_real_distribution<vtkm::FloatDefault> angleDist(0, 360);
173   for (int i = 0; i < N; i++)
174     angles.push_back(angleDist(randGenerator));
175 
176   std::vector<vtkm::Vec3f> axes;
177   axes.push_back(vtkm::Vec3f(1, 0, 0));
178   axes.push_back(vtkm::Vec3f(0, 1, 0));
179   axes.push_back(vtkm::Vec3f(0, 0, 1));
180   axes.push_back(vtkm::Vec3f(1, 1, 1));
181   axes.push_back(-axes[0]);
182   axes.push_back(-axes[1]);
183   axes.push_back(-axes[2]);
184   axes.push_back(-axes[3]);
185 
186   std::uniform_real_distribution<vtkm::FloatDefault> axisDist(-1, 1);
187   for (int i = 0; i < N; i++)
188     axes.push_back(
189       vtkm::Vec3f(axisDist(randGenerator), axisDist(randGenerator), axisDist(randGenerator)));
190 
191   for (std::size_t i = 0; i < angles.size(); i++)
192     for (std::size_t j = 0; j < axes.size(); j++)
193       TestPointTransformRotation(ds, angles[i], axes[j]);
194 }
195 
196 
UnitTestPointTransform(int argc,char * argv[])197 int UnitTestPointTransform(int argc, char* argv[])
198 {
199   return vtkm::cont::testing::Testing::Run(TestPointTransform, argc, argv);
200 }
201