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 #include <vtkm/filter/CellAverage.h>
11 #include <vtkm/filter/Contour.h>
12 #include <vtkm/filter/SplitSharpEdges.h>
13 #include <vtkm/filter/SurfaceNormals.h>
14 
15 #include <vtkm/cont/testing/MakeTestDataSet.h>
16 #include <vtkm/cont/testing/Testing.h>
17 
18 #include <vtkm/source/Wavelet.h>
19 
20 namespace
21 {
22 
23 using NormalsArrayHandle = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
24 
25 const vtkm::Vec3f expectedCoords[24] = {
26   { 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 1.0, 0.0 },
27   { 1.0, 1.0, 0.0 }, { 1.0, 1.0, 1.0 }, { 0.0, 1.0, 1.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 },
28   { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 },
29   { 0.0, 0.0, 1.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 },
30   { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 0.0, 1.0, 1.0 }, { 0.0, 1.0, 1.0 }
31 };
32 
33 const std::vector<vtkm::Id> expectedConnectivityArray91{ 0, 1, 5, 4, 1, 2, 6, 5, 2, 3, 7, 6,
34                                                          3, 0, 4, 7, 4, 5, 6, 7, 0, 3, 2, 1 };
35 const std::vector<vtkm::FloatDefault> expectedPointvar{ 10.1f, 20.1f, 30.2f, 40.2f, 50.3f, 60.3f,
36                                                         70.3f, 80.3f, 10.1f, 10.1f, 20.1f, 20.1f,
37                                                         30.2f, 30.2f, 40.2f, 40.2f, 50.3f, 50.3f,
38                                                         60.3f, 60.3f, 70.3f, 70.3f, 80.3f, 80.3f };
39 
Make3DExplicitSimpleCube()40 vtkm::cont::DataSet Make3DExplicitSimpleCube()
41 {
42   vtkm::cont::DataSet dataSet;
43   vtkm::cont::DataSetBuilderExplicit dsb;
44 
45   const int nVerts = 8;
46   const int nCells = 6;
47   using CoordType = vtkm::Vec3f;
48   std::vector<CoordType> coords = {
49     CoordType(0, 0, 0), // 0
50     CoordType(1, 0, 0), // 1
51     CoordType(1, 0, 1), // 2
52     CoordType(0, 0, 1), // 3
53     CoordType(0, 1, 0), // 4
54     CoordType(1, 1, 0), // 5
55     CoordType(1, 1, 1), // 6
56     CoordType(0, 1, 1)  // 7
57   };
58 
59   //Connectivity
60   std::vector<vtkm::UInt8> shapes;
61   std::vector<vtkm::IdComponent> numIndices;
62   for (size_t i = 0; i < 6; i++)
63   {
64     shapes.push_back(vtkm::CELL_SHAPE_QUAD);
65     numIndices.push_back(4);
66   }
67 
68 
69   std::vector<vtkm::Id> conn;
70   // Down face
71   conn.push_back(0);
72   conn.push_back(1);
73   conn.push_back(5);
74   conn.push_back(4);
75   // Right face
76   conn.push_back(1);
77   conn.push_back(2);
78   conn.push_back(6);
79   conn.push_back(5);
80   // Top face
81   conn.push_back(2);
82   conn.push_back(3);
83   conn.push_back(7);
84   conn.push_back(6);
85   // Left face
86   conn.push_back(3);
87   conn.push_back(0);
88   conn.push_back(4);
89   conn.push_back(7);
90   // Front face
91   conn.push_back(4);
92   conn.push_back(5);
93   conn.push_back(6);
94   conn.push_back(7);
95   // Back face
96   conn.push_back(0);
97   conn.push_back(3);
98   conn.push_back(2);
99   conn.push_back(1);
100 
101   //Create the dataset.
102   dataSet = dsb.Create(coords, shapes, numIndices, conn, "coordinates");
103 
104   vtkm::FloatDefault vars[nVerts] = { 10.1f, 20.1f, 30.2f, 40.2f, 50.3f, 60.3f, 70.3f, 80.3f };
105   vtkm::FloatDefault cellvar[nCells] = { 100.1f, 200.2f, 300.3f, 400.4f, 500.5f, 600.6f };
106 
107   dataSet.AddPointField("pointvar", vars, nVerts);
108   dataSet.AddCellField("cellvar", cellvar, nCells);
109 
110   return dataSet;
111 }
112 
Make3DWavelet()113 vtkm::cont::DataSet Make3DWavelet()
114 {
115 
116   vtkm::source::Wavelet wavelet({ -25 }, { 25 });
117   wavelet.SetFrequency({ 60, 30, 40 });
118   wavelet.SetMagnitude({ 5 });
119 
120   vtkm::cont::DataSet result = wavelet.Execute();
121   return result;
122 }
123 
124 
TestSplitSharpEdgesFilterSplitEveryEdge(vtkm::cont::DataSet & simpleCubeWithSN,vtkm::filter::SplitSharpEdges & splitSharpEdgesFilter)125 void TestSplitSharpEdgesFilterSplitEveryEdge(vtkm::cont::DataSet& simpleCubeWithSN,
126                                              vtkm::filter::SplitSharpEdges& splitSharpEdgesFilter)
127 {
128   // Split every edge
129   vtkm::FloatDefault featureAngle = 89.0;
130   splitSharpEdgesFilter.SetFeatureAngle(featureAngle);
131   splitSharpEdgesFilter.SetActiveField("Normals", vtkm::cont::Field::Association::CELL_SET);
132   vtkm::cont::DataSet result = splitSharpEdgesFilter.Execute(simpleCubeWithSN);
133 
134   auto newCoords = result.GetCoordinateSystem().GetDataAsMultiplexer();
135   auto newCoordsP = newCoords.ReadPortal();
136   vtkm::cont::ArrayHandle<vtkm::FloatDefault> newPointvarField;
137   result.GetField("pointvar").GetData().AsArrayHandle(newPointvarField);
138 
139   for (vtkm::IdComponent i = 0; i < newCoords.GetNumberOfValues(); i++)
140   {
141     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[0], expectedCoords[i][0]),
142                      "result value does not match expected value");
143     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[1], expectedCoords[i][1]),
144                      "result value does not match expected value");
145     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[2], expectedCoords[i][2]),
146                      "result value does not match expected value");
147   }
148 
149   auto newPointvarFieldPortal = newPointvarField.ReadPortal();
150   for (vtkm::IdComponent i = 0; i < newPointvarField.GetNumberOfValues(); i++)
151   {
152     VTKM_TEST_ASSERT(test_equal(newPointvarFieldPortal.Get(static_cast<vtkm::Id>(i)),
153                                 expectedPointvar[static_cast<unsigned long>(i)]),
154                      "point field array result does not match expected value");
155   }
156 }
157 
TestSplitSharpEdgesFilterNoSplit(vtkm::cont::DataSet & simpleCubeWithSN,vtkm::filter::SplitSharpEdges & splitSharpEdgesFilter)158 void TestSplitSharpEdgesFilterNoSplit(vtkm::cont::DataSet& simpleCubeWithSN,
159                                       vtkm::filter::SplitSharpEdges& splitSharpEdgesFilter)
160 {
161   // Do nothing
162   vtkm::FloatDefault featureAngle = 91.0;
163   splitSharpEdgesFilter.SetFeatureAngle(featureAngle);
164   splitSharpEdgesFilter.SetActiveField("Normals", vtkm::cont::Field::Association::CELL_SET);
165   vtkm::cont::DataSet result = splitSharpEdgesFilter.Execute(simpleCubeWithSN);
166 
167   auto newCoords = result.GetCoordinateSystem().GetDataAsMultiplexer();
168   vtkm::cont::CellSetExplicit<>& newCellset =
169     result.GetCellSet().Cast<vtkm::cont::CellSetExplicit<>>();
170   auto newCoordsP = newCoords.ReadPortal();
171   vtkm::cont::ArrayHandle<vtkm::FloatDefault> newPointvarField;
172   result.GetField("pointvar").GetData().AsArrayHandle(newPointvarField);
173 
174   for (vtkm::IdComponent i = 0; i < newCoords.GetNumberOfValues(); i++)
175   {
176     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[0], expectedCoords[i][0]),
177                      "result value does not match expected value");
178     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[1], expectedCoords[i][1]),
179                      "result value does not match expected value");
180     VTKM_TEST_ASSERT(test_equal(newCoordsP.Get(i)[2], expectedCoords[i][2]),
181                      "result value does not match expected value");
182   }
183 
184   const auto& connectivityArray = newCellset.GetConnectivityArray(vtkm::TopologyElementTagCell(),
185                                                                   vtkm::TopologyElementTagPoint());
186   auto connectivityArrayPortal = connectivityArray.ReadPortal();
187   for (vtkm::IdComponent i = 0; i < connectivityArray.GetNumberOfValues(); i++)
188   {
189     VTKM_TEST_ASSERT(connectivityArrayPortal.Get(static_cast<vtkm::Id>(i)) ==
190                        expectedConnectivityArray91[static_cast<unsigned long>(i)],
191                      "connectivity array result does not match expected value");
192   }
193 
194   auto newPointvarFieldPortal = newPointvarField.ReadPortal();
195   for (vtkm::IdComponent i = 0; i < newPointvarField.GetNumberOfValues(); i++)
196   {
197     VTKM_TEST_ASSERT(test_equal(newPointvarFieldPortal.Get(static_cast<vtkm::Id>(i)),
198                                 expectedPointvar[static_cast<unsigned long>(i)]),
199                      "point field array result does not match expected value");
200   }
201 }
202 
TestWithExplicitData()203 void TestWithExplicitData()
204 {
205   vtkm::cont::DataSet simpleCube = Make3DExplicitSimpleCube();
206 
207   // Generate surface normal field
208   vtkm::filter::SurfaceNormals surfaceNormalsFilter;
209   surfaceNormalsFilter.SetGenerateCellNormals(true);
210   vtkm::cont::DataSet simpleCubeWithSN = surfaceNormalsFilter.Execute(simpleCube);
211   VTKM_TEST_ASSERT(simpleCubeWithSN.HasCellField("Normals"), "Cell normals missing.");
212   VTKM_TEST_ASSERT(simpleCubeWithSN.HasPointField("pointvar"), "point field pointvar missing.");
213 
214 
215   vtkm::filter::SplitSharpEdges splitSharpEdgesFilter;
216 
217   TestSplitSharpEdgesFilterSplitEveryEdge(simpleCubeWithSN, splitSharpEdgesFilter);
218   TestSplitSharpEdgesFilterNoSplit(simpleCubeWithSN, splitSharpEdgesFilter);
219 }
220 
221 
TestWithStructuredData()222 void TestWithStructuredData()
223 {
224   // Generate a wavelet:
225   vtkm::cont::DataSet dataSet = Make3DWavelet();
226 
227   // Cut a contour:
228   vtkm::filter::Contour contour;
229   contour.SetActiveField("scalars", vtkm::cont::Field::Association::POINTS);
230   contour.SetNumberOfIsoValues(1);
231   contour.SetIsoValue(192);
232   contour.SetMergeDuplicatePoints(true);
233   contour.SetGenerateNormals(true);
234   contour.SetComputeFastNormalsForStructured(true);
235   contour.SetNormalArrayName("normals");
236   dataSet = contour.Execute(dataSet);
237 
238   // Compute cell normals:
239   vtkm::filter::CellAverage cellNormals;
240   cellNormals.SetActiveField("normals", vtkm::cont::Field::Association::POINTS);
241   dataSet = cellNormals.Execute(dataSet);
242 
243   // Split sharp edges:
244   std::cout << dataSet.GetNumberOfCells() << std::endl;
245   std::cout << dataSet.GetNumberOfPoints() << std::endl;
246   vtkm::filter::SplitSharpEdges split;
247   split.SetActiveField("normals", vtkm::cont::Field::Association::CELL_SET);
248   dataSet = split.Execute(dataSet);
249 }
250 
251 
TestSplitSharpEdgesFilter()252 void TestSplitSharpEdgesFilter()
253 {
254   TestWithExplicitData();
255   TestWithStructuredData();
256 }
257 
258 } // anonymous namespace
259 
UnitTestSplitSharpEdgesFilter(int argc,char * argv[])260 int UnitTestSplitSharpEdgesFilter(int argc, char* argv[])
261 {
262   return vtkm::cont::testing::Testing::Run(TestSplitSharpEdgesFilter, argc, argv);
263 }
264