1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestParametricSpline.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkCardinalSpline.h"
17 #include "vtkKochanekSpline.h"
18 #include "vtkMath.h"
19 #include "vtkMathUtilities.h"
20 #include "vtkParametricSpline.h"
21 #include "vtkPoints.h"
22 #include "vtkSmartPointer.h"
23 
24 #include <cmath>
25 
26 #include "vtkTestErrorObserver.h"
27 
28 void TestPrint();
29 int TestSetGet();
30 int TestConstraints();
31 int TestErrors();
32 int TestMisc();
33 int TestSetPoints(vtkPoints*, bool closed = false);
34 void GeneratePoints(int, vtkSmartPointer<vtkPoints>&);
35 void GenerateRandomPoints(int, vtkSmartPointer<vtkPoints>&);
UnitTestParametricSpline(int,char * [])36 int UnitTestParametricSpline(int, char*[])
37 {
38   int status = 0;
39   vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
40   GeneratePoints(100, points);
41   TestPrint();
42   status += TestErrors();
43   status += TestSetGet();
44   status += TestConstraints();
45   status += TestSetPoints(points);
46   status += TestSetPoints(points, true);
47   status += TestMisc();
48 
49   return status == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
50 }
51 
GeneratePoints(int npts,vtkSmartPointer<vtkPoints> & points)52 void GeneratePoints(int npts, vtkSmartPointer<vtkPoints>& points)
53 {
54   points->SetNumberOfPoints(npts);
55   double deltaX = vtkMath::Pi() * 2.0 / (npts - 1);
56   double deltaZ = 2.0 / (npts - 1);
57   for (int n = 0; n < npts; ++n)
58   {
59     double x[3];
60     x[0] = -vtkMath::Pi() + n * deltaX;
61     x[1] = std::sin(x[0]);
62     x[2] = -1.0 + n * deltaZ;
63     points->SetPoint(n, x[0], x[1], x[2]);
64   }
65 }
66 
TestSetPoints(vtkPoints * points,bool closed)67 int TestSetPoints(vtkPoints* points, bool closed)
68 {
69   int status = 0;
70 
71   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
72   if (closed)
73   {
74     pspline->ClosedOn();
75   }
76   else
77   {
78     pspline->ClosedOff();
79   }
80   int npts = points->GetNumberOfPoints();
81 
82   pspline->SetNumberOfPoints(npts);
83 
84   double length = 0.0;
85 
86   vtkPoints* knots = vtkPoints::New(VTK_DOUBLE);
87   knots->SetNumberOfPoints(npts);
88 
89   double xm1[3] = { 0.0, 0.0, 0.0 };
90   double x[3];
91   for (int n = 0; n < npts; ++n)
92   {
93     points->GetPoint(n, x);
94     pspline->SetPoint(n, x[0], x[1], x[2]);
95     if (n > 0)
96     {
97       length += std::sqrt(vtkMath::Distance2BetweenPoints(x, xm1));
98     }
99     xm1[0] = x[0];
100     xm1[1] = x[1];
101     xm1[2] = x[2];
102   }
103   if (closed)
104   {
105     points->GetPoint(0, x);
106     points->GetPoint(npts - 1, xm1);
107     length += std::sqrt(vtkMath::Distance2BetweenPoints(x, xm1));
108   }
109 
110   double tolerance = 4.0 * std::numeric_limits<double>::epsilon();
111   pspline->ParameterizeByLengthOff();
112   for (int n = 0; n < npts; ++n)
113   {
114     double t[3];
115     if (closed)
116     {
117       t[0] = static_cast<double>(n) / static_cast<double>((npts));
118     }
119     else
120     {
121       t[0] = static_cast<double>(n) / static_cast<double>((npts - 1));
122     }
123     t[1] = t[2] = 0.0;
124 
125     points->GetPoint(n, x);
126 
127     double result[3];
128     pspline->Evaluate(t, result, nullptr);
129     if (!vtkMathUtilities::FuzzyCompare(x[0], result[0], tolerance) ||
130       !vtkMathUtilities::FuzzyCompare(x[1], result[1], tolerance) ||
131       !vtkMathUtilities::FuzzyCompare(x[2], result[2], tolerance))
132     {
133       std::cout << "TestSetPoints(by point id): Expected " << x[0] << ", " << x[1] << ", " << x[2]
134                 << " but got " << result[0] << ", " << result[1] << ", " << result[2] << std::endl;
135       ++status;
136     }
137   }
138 
139   // Test with externally created points
140   tolerance = 8.0 * std::numeric_limits<double>::epsilon();
141   pspline->SetPoints(points);
142   pspline->ParameterizeByLengthOn();
143   double totalLength = length;
144 
145   length = 0.0;
146   for (int n = 0; n < npts; ++n)
147   {
148     points->GetPoint(n, x);
149 
150     if (n > 0)
151     {
152       length += std::sqrt(vtkMath::Distance2BetweenPoints(x, xm1));
153     }
154     double t[3];
155     t[0] = length / totalLength;
156     t[1] = t[2] = 0.0;
157 
158     double result[3];
159     pspline->Evaluate(t, result, nullptr);
160     if (!vtkMathUtilities::FuzzyCompare(x[0], result[0], tolerance) ||
161       !vtkMathUtilities::FuzzyCompare(x[1], result[1], tolerance) ||
162       !vtkMathUtilities::FuzzyCompare(x[2], result[2], tolerance))
163     {
164       std::cout << "TestSetPoints(by length): Expected " << x[0] << ", " << x[1] << ", " << x[2]
165                 << " but got " << result[0] << ", " << result[1] << ", " << result[2] << std::endl;
166       ++status;
167     }
168     xm1[0] = x[0];
169     xm1[1] = x[1];
170     xm1[2] = x[2];
171   }
172 
173   knots->Delete();
174   return status;
175 }
176 
TestErrors()177 int TestErrors()
178 {
179   int status = 0;
180   vtkSmartPointer<vtkTest::ErrorObserver> errorObserver =
181     vtkSmartPointer<vtkTest::ErrorObserver>::New();
182 
183   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
184   pspline->AddObserver(vtkCommand::ErrorEvent, errorObserver);
185 
186   double x[3];
187   x[0] = 0.0;
188   x[1] = 0.0;
189   x[2] = 0.0;
190   double result[3];
191 
192   pspline->Evaluate(x, result, nullptr);
193   // Check for model bounds error
194   if (errorObserver->GetError())
195   {
196     std::cout << "Caught expected error: " << errorObserver->GetErrorMessage();
197   }
198   else
199   {
200     std::cout << "Failed to catch expected 'Please specify points' error" << std::endl;
201     ++status;
202   }
203   errorObserver->Clear();
204 
205   pspline->SetNumberOfPoints(0);
206   pspline->EvaluateScalar(x, nullptr, nullptr);
207   if (errorObserver->GetError())
208   {
209     std::cout << "Caught expected error: " << errorObserver->GetErrorMessage();
210   }
211   else
212   {
213     std::cout << "Failed to catch expected 'Please specify at least one point' error" << std::endl;
214     ++status;
215   }
216   errorObserver->Clear();
217 
218   pspline->SetXSpline(nullptr);
219   pspline->Evaluate(x, result, nullptr);
220   if (errorObserver->GetError())
221   {
222     std::cout << "Caught expected error: " << errorObserver->GetErrorMessage();
223   }
224   else
225   {
226     std::cout << "Failed to catch expected 'Please specify spline' error" << std::endl;
227     ++status;
228   }
229   errorObserver->Clear();
230 
231   return status;
232 }
233 
TestSetGet()234 int TestSetGet()
235 {
236   int status = 0;
237   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
238 
239   if (pspline->GetDimension() != 1)
240   {
241     std::cout << "GetDimension: expected 1 but got " << pspline->GetDimension() << std::endl;
242     ++status;
243   }
244 
245   if (pspline->GetParameterizeByLength() != 1)
246   {
247     std::cout << "GetParameterizeByLength: expected 1 but got "
248               << pspline->GetParameterizeByLength() << std::endl;
249     ++status;
250   }
251 
252   if (pspline->GetPoints() != nullptr)
253   {
254     std::cout << "GetPoints: Expected nullptr but got " << pspline->GetPoints() << std::endl;
255     ++status;
256   }
257 
258   std::string className;
259   className = pspline->GetXSpline()->GetClassName();
260   if (className != "vtkCardinalSpline")
261   {
262     std::cout << "GetXSpline: Expected "
263               << "vtkCardinalSpline"
264               << " but got " << className << std::endl;
265     ++status;
266   }
267   className = pspline->GetYSpline()->GetClassName();
268   if (className != "vtkCardinalSpline")
269   {
270     std::cout << "GetYSpline: Expected "
271               << "vtkCardinalSpline"
272               << " but got " << className << std::endl;
273     ++status;
274   }
275   className = pspline->GetZSpline()->GetClassName();
276   if (className != "vtkCardinalSpline")
277   {
278     std::cout << "GetZSpline: Expected "
279               << "vtkCardinalSpline"
280               << " but got " << className << std::endl;
281     ++status;
282   }
283 
284   // Now change the spline tyeps
285   vtkSmartPointer<vtkKochanekSpline> xSpline = vtkSmartPointer<vtkKochanekSpline>::New();
286   pspline->SetXSpline(xSpline);
287   className = pspline->GetXSpline()->GetClassName();
288   if (className != "vtkKochanekSpline")
289   {
290     std::cout << "GetXSpline: Expected "
291               << "vtkKochanekSpline"
292               << " but got " << className << std::endl;
293     ++status;
294   }
295 
296   vtkSmartPointer<vtkKochanekSpline> ySpline = vtkSmartPointer<vtkKochanekSpline>::New();
297   pspline->SetYSpline(ySpline);
298   className = pspline->GetYSpline()->GetClassName();
299   if (className != "vtkKochanekSpline")
300   {
301     std::cout << "GetYSpline: Expected "
302               << "vtkKochanekSpline"
303               << " but got " << className << std::endl;
304     ++status;
305   }
306 
307   vtkSmartPointer<vtkKochanekSpline> zSpline = vtkSmartPointer<vtkKochanekSpline>::New();
308   pspline->SetZSpline(zSpline);
309   className = pspline->GetZSpline()->GetClassName();
310   if (className != "vtkKochanekSpline")
311   {
312     std::cout << "GetZSpline: Expected "
313               << "vtkKochanekSpline"
314               << " but got " << className << std::endl;
315     ++status;
316   }
317 
318   return status;
319 }
320 
TestConstraints()321 int TestConstraints()
322 {
323   int status = 0;
324 
325   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
326 
327   pspline->SetNumberOfPoints(2);
328   double x[3], result[3];
329   x[0] = x[1] = x[2] = 0.0;
330   pspline->SetPoint(0, x[0], x[1], x[2]);
331   pspline->SetPoint(1, x[0], x[1], x[2]);
332 
333   pspline->SetLeftConstraint(2);
334   pspline->SetLeftValue(0.0);
335   pspline->SetRightConstraint(2);
336   pspline->SetRightValue(0.0);
337 
338   // Force initialize
339   pspline->Evaluate(x, result, nullptr);
340 
341   if (pspline->GetXSpline()->GetLeftConstraint() != pspline->GetLeftConstraint())
342   {
343     std::cout << "GetXSpline->GetLeftContraint: Expected " << pspline->GetLeftConstraint()
344               << " but got " << pspline->GetXSpline()->GetLeftConstraint() << std::endl;
345     ++status;
346   }
347   if (pspline->GetXSpline()->GetLeftValue() != pspline->GetLeftValue())
348   {
349     std::cout << "GetXSpline->GetLeftValue: Expected " << pspline->GetLeftValue() << " but got "
350               << pspline->GetXSpline()->GetLeftValue() << std::endl;
351     ++status;
352   }
353 
354   if (pspline->GetYSpline()->GetLeftConstraint() != pspline->GetLeftConstraint())
355   {
356     std::cout << "GetYSpline->GetLeftContraint: Expected " << pspline->GetLeftConstraint()
357               << " but got " << pspline->GetYSpline()->GetLeftConstraint() << std::endl;
358     ++status;
359   }
360   if (pspline->GetYSpline()->GetLeftValue() != pspline->GetLeftValue())
361   {
362     std::cout << "GetYSpline->GetLeftValue: Expected " << pspline->GetLeftValue() << " but got "
363               << pspline->GetYSpline()->GetLeftValue() << std::endl;
364     ++status;
365   }
366 
367   if (pspline->GetZSpline()->GetLeftConstraint() != pspline->GetLeftConstraint())
368   {
369     std::cout << "GetZSpline->GetLeftContraint: Expected " << pspline->GetLeftConstraint()
370               << " but got " << pspline->GetZSpline()->GetLeftConstraint() << std::endl;
371     ++status;
372   }
373   if (pspline->GetZSpline()->GetLeftValue() != pspline->GetLeftValue())
374   {
375     std::cout << "GetZSpline->GetLeftValue: Expected " << pspline->GetLeftValue() << " but got "
376               << pspline->GetZSpline()->GetLeftValue() << std::endl;
377     ++status;
378   }
379   return status;
380 }
381 
TestMisc()382 int TestMisc()
383 {
384   int status = 0;
385   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
386   pspline->SetNumberOfPoints(1);
387   double x[3];
388   x[0] = 1.0;
389   x[1] = 0.0;
390   x[2] = 0.0;
391 
392   if (pspline->EvaluateScalar(x, nullptr, nullptr) != x[0])
393   {
394     std::cout << "EvaluateScalar: Expected " << x[0] << " but got "
395               << pspline->EvaluateScalar(x, nullptr, nullptr) << std::endl;
396     ++status;
397   }
398   return status;
399 }
TestPrint()400 void TestPrint()
401 {
402   vtkSmartPointer<vtkParametricSpline> pspline = vtkSmartPointer<vtkParametricSpline>::New();
403   // First test uninitialized spline
404   pspline->Print(std::cout);
405 
406   // With Points
407   double x[3];
408   x[0] = x[1] = x[2] = 0.0;
409 
410   pspline->SetNumberOfPoints(1);
411   pspline->SetPoint(0, x[0], x[1], x[2]);
412   pspline->Print(std::cout);
413 
414   // With nullptr Splines
415   pspline->SetXSpline(nullptr);
416   pspline->SetYSpline(nullptr);
417   pspline->SetZSpline(nullptr);
418   pspline->Print(std::cout);
419 }
420