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