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 #ifndef vtk_m_ImplicitFunction_h
11 #define vtk_m_ImplicitFunction_h
12 
13 #include <vtkm/Bounds.h>
14 #include <vtkm/Deprecated.h>
15 #include <vtkm/Math.h>
16 #include <vtkm/VectorAnalysis.h>
17 
18 #include <vtkm/exec/internal/Variant.h>
19 
20 // For interface class only.
21 #include <vtkm/cont/ExecutionAndControlObjectBase.h>
22 
23 #ifndef VTKM_NO_DEPRECATED_VIRTUAL
24 #include <vtkm/VirtualObjectBase.h>
25 #endif // VTKM_NO_DEPRECATED_VIRTUAL
26 
27 namespace vtkm
28 {
29 
30 //============================================================================
31 #ifndef VTKM_NO_DEPRECATED_VIRTUAL
32 class VTKM_DEPRECATED(1.6, "ImplicitFunction with virtual methods no longer supported.")
33   VTKM_ALWAYS_EXPORT ImplicitFunction : public vtkm::VirtualObjectBase
34 {
35 public:
36   using Scalar = vtkm::FloatDefault;
37   using Vector = vtkm::Vec<Scalar, 3>;
38 
39   VTKM_EXEC_CONT virtual Scalar Value(const Vector& point) const = 0;
40   VTKM_EXEC_CONT virtual Vector Gradient(const Vector& point) const = 0;
41 
42   VTKM_DEPRECATED_SUPPRESS_BEGIN
Value(Scalar x,Scalar y,Scalar z)43   VTKM_EXEC_CONT Scalar Value(Scalar x, Scalar y, Scalar z) const
44   {
45     return this->Value(Vector(x, y, z));
46   }
47 
Gradient(Scalar x,Scalar y,Scalar z)48   VTKM_EXEC_CONT Vector Gradient(Scalar x, Scalar y, Scalar z) const
49   {
50     return this->Gradient(Vector(x, y, z));
51   }
52   VTKM_DEPRECATED_SUPPRESS_END
53 };
54 #endif // VTKM_NO_DEPRECATED_VIRTUAL
55 
56 //============================================================================
57 namespace internal
58 {
59 
60 /// \brief Base class for all `ImplicitFunction` classes.
61 ///
62 /// `ImplicitFunctionBase` uses the curiously recurring template pattern (CRTP). Subclasses
63 /// must provide their own type for the template parameter. Subclasses must implement
64 /// `Value` and `Gradient` methods.
65 ///
66 /// Also, all subclasses must be trivially copiable. This is so they can be copied among
67 /// host and devices.
68 ///
69 template <typename Derived>
70 class ImplicitFunctionBase : public vtkm::cont::ExecutionAndControlObjectBase
71 {
72 public:
73   using Scalar = vtkm::FloatDefault;
74   using Vector = vtkm::Vec<Scalar, 3>;
75 
Value(Scalar x,Scalar y,Scalar z)76   VTKM_EXEC_CONT Scalar Value(Scalar x, Scalar y, Scalar z) const
77   {
78     return reinterpret_cast<const Derived*>(this)->Value(Vector(x, y, z));
79   }
80 
Gradient(Scalar x,Scalar y,Scalar z)81   VTKM_EXEC_CONT Vector Gradient(Scalar x, Scalar y, Scalar z) const
82   {
83     return reinterpret_cast<const Derived*>(this)->Gradient(Vector(x, y, z));
84   }
85 
PrepareForExecution(vtkm::cont::DeviceAdapterId,vtkm::cont::Token &)86   VTKM_CONT Derived PrepareForExecution(vtkm::cont::DeviceAdapterId, vtkm::cont::Token&) const
87   {
88     return *reinterpret_cast<const Derived*>(this);
89   }
90 
PrepareForControl()91   VTKM_CONT Derived PrepareForControl() const { return *reinterpret_cast<const Derived*>(this); }
92 };
93 
94 } // namespace vtkm::internal
95 
96 //============================================================================
97 #ifndef VTKM_NO_DEPRECATED_VIRTUAL
98 VTKM_DEPRECATED_SUPPRESS_BEGIN
99 
100 /// A helpful functor that calls the (virtual) value method of a given ImplicitFunction. Can be
101 /// passed to things that expect a functor instead of an ImplictFunction class (like an array
102 /// transform).
103 ///
104 class VTKM_DEPRECATED(1.6,
105                       "Use ImplicitFunctionValueFunctor.") VTKM_ALWAYS_EXPORT ImplicitFunctionValue
106 {
107 public:
108   using Scalar = vtkm::ImplicitFunction::Scalar;
109   using Vector = vtkm::ImplicitFunction::Vector;
110 
ImplicitFunctionValue()111   VTKM_EXEC_CONT ImplicitFunctionValue()
112     : Function(nullptr)
113   {
114   }
115 
ImplicitFunctionValue(const ImplicitFunction * function)116   VTKM_EXEC_CONT ImplicitFunctionValue(const ImplicitFunction* function)
117     : Function(function)
118   {
119   }
120 
operator()121   VTKM_EXEC_CONT Scalar operator()(const Vector& point) const
122   {
123     return this->Function->Value(point);
124   }
125 
126 private:
127   const vtkm::ImplicitFunction* Function;
128 };
129 
130 /// A helpful functor that calls the (virtual) gradient method of a given ImplicitFunction. Can be
131 /// passed to things that expect a functor instead of an ImplictFunction class (like an array
132 /// transform).
133 ///
134 class VTKM_DEPRECATED(1.6, "Use ImplicitFunctionGradientFunctor.")
135   VTKM_ALWAYS_EXPORT ImplicitFunctionGradient
136 {
137 public:
138   using Scalar = vtkm::ImplicitFunction::Scalar;
139   using Vector = vtkm::ImplicitFunction::Vector;
140 
ImplicitFunctionGradient()141   VTKM_EXEC_CONT ImplicitFunctionGradient()
142     : Function(nullptr)
143   {
144   }
145 
ImplicitFunctionGradient(const ImplicitFunction * function)146   VTKM_EXEC_CONT ImplicitFunctionGradient(const ImplicitFunction* function)
147     : Function(function)
148   {
149   }
150 
operator()151   VTKM_EXEC_CONT Vector operator()(const Vector& point) const
152   {
153     return this->Function->Gradient(point);
154   }
155 
156 private:
157   const vtkm::ImplicitFunction* Function;
158 };
159 
160 VTKM_DEPRECATED_SUPPRESS_END
161 #endif // VTKM_NO_DEPRECATED_VIRTUAL
162 
163 //============================================================================
164 /// A helpful functor that calls the value method of a given `ImplicitFunction`. Can be
165 /// passed to things that expect a functor instead of an `ImplictFunction` class (like an array
166 /// transform).
167 ///
168 template <typename FunctionType>
169 class ImplicitFunctionValueFunctor
170 {
171 public:
172   using Scalar = typename FunctionType::Scalar;
173   using Vector = typename FunctionType::Vector;
174 
175   ImplicitFunctionValueFunctor() = default;
176 
ImplicitFunctionValueFunctor(const vtkm::internal::ImplicitFunctionBase<FunctionType> & function)177   VTKM_EXEC_CONT ImplicitFunctionValueFunctor(
178     const vtkm::internal::ImplicitFunctionBase<FunctionType>& function)
179     : Function(reinterpret_cast<const FunctionType&>(function))
180   {
181   }
182 
ImplicitFunctionValueFunctor(const FunctionType & function)183   VTKM_EXEC_CONT ImplicitFunctionValueFunctor(const FunctionType& function)
184     : Function(function)
185   {
186   }
187 
operator()188   VTKM_EXEC_CONT Scalar operator()(const Vector& point) const
189   {
190     return this->Function.Value(point);
191   }
192 
193 private:
194   FunctionType Function;
195 };
196 
197 /// A helpful functor that calls the gradient method of a given `ImplicitFunction`. Can be
198 /// passed to things that expect a functor instead of an `ImplictFunction` class (like an array
199 /// transform).
200 ///
201 template <typename FunctionType>
202 class ImplicitFunctionGradientFunctor
203 {
204 public:
205   using Scalar = typename FunctionType::Scalar;
206   using Vector = typename FunctionType::Vector;
207 
208   ImplicitFunctionGradientFunctor() = default;
209 
ImplicitFunctionGradientFunctor(const vtkm::internal::ImplicitFunctionBase<FunctionType> & function)210   VTKM_EXEC_CONT ImplicitFunctionGradientFunctor(
211     const vtkm::internal::ImplicitFunctionBase<FunctionType>& function)
212     : Function(reinterpret_cast<const FunctionType&>(function))
213   {
214   }
215 
ImplicitFunctionGradientFunctor(const FunctionType & function)216   VTKM_EXEC_CONT ImplicitFunctionGradientFunctor(const FunctionType& function)
217     : Function(function)
218   {
219   }
220 
operator()221   VTKM_EXEC_CONT Vector operator()(const Vector& point) const
222   {
223     return this->Function->Gradient(point);
224   }
225 
226 private:
227   FunctionType Function;
228 };
229 
230 //============================================================================
231 /// \brief Implicit function for a box
232 ///
233 /// \c Box computes the implicit function and/or gradient for a axis-aligned
234 /// bounding box. Each side of the box is orthogonal to all other sides
235 /// meeting along shared edges and all faces are orthogonal to the x-y-z
236 /// coordinate axes.
237 
238 class VTKM_ALWAYS_EXPORT Box : public internal::ImplicitFunctionBase<Box>
239 {
240 public:
241   /// \brief Construct box with center at (0,0,0) and each side of length 1.0.
Box()242   VTKM_EXEC_CONT Box()
243     : MinPoint(Vector(Scalar(-0.5)))
244     , MaxPoint(Vector(Scalar(0.5)))
245   {
246   }
247 
Box(const Vector & minPoint,const Vector & maxPoint)248   VTKM_EXEC_CONT Box(const Vector& minPoint, const Vector& maxPoint)
249     : MinPoint(minPoint)
250     , MaxPoint(maxPoint)
251   {
252   }
253 
Box(Scalar xmin,Scalar xmax,Scalar ymin,Scalar ymax,Scalar zmin,Scalar zmax)254   VTKM_EXEC_CONT Box(Scalar xmin, Scalar xmax, Scalar ymin, Scalar ymax, Scalar zmin, Scalar zmax)
255     : MinPoint(xmin, ymin, zmin)
256     , MaxPoint(xmax, ymax, zmax)
257   {
258   }
259 
Box(const vtkm::Bounds & bounds)260   VTKM_CONT Box(const vtkm::Bounds& bounds) { this->SetBounds(bounds); }
261 
SetMinPoint(const Vector & point)262   VTKM_CONT void SetMinPoint(const Vector& point) { this->MinPoint = point; }
263 
SetMaxPoint(const Vector & point)264   VTKM_CONT void SetMaxPoint(const Vector& point) { this->MaxPoint = point; }
265 
GetMinPoint()266   VTKM_EXEC_CONT const Vector& GetMinPoint() const { return this->MinPoint; }
267 
GetMaxPoint()268   VTKM_EXEC_CONT const Vector& GetMaxPoint() const { return this->MaxPoint; }
269 
SetBounds(const vtkm::Bounds & bounds)270   VTKM_CONT void SetBounds(const vtkm::Bounds& bounds)
271   {
272     this->SetMinPoint({ Scalar(bounds.X.Min), Scalar(bounds.Y.Min), Scalar(bounds.Z.Min) });
273     this->SetMaxPoint({ Scalar(bounds.X.Max), Scalar(bounds.Y.Max), Scalar(bounds.Z.Max) });
274   }
275 
GetBounds()276   VTKM_EXEC_CONT vtkm::Bounds GetBounds() const
277   {
278     return vtkm::Bounds(vtkm::Range(this->MinPoint[0], this->MaxPoint[0]),
279                         vtkm::Range(this->MinPoint[1], this->MaxPoint[1]),
280                         vtkm::Range(this->MinPoint[2], this->MaxPoint[2]));
281   }
282 
Value(const Vector & point)283   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
284   {
285     Scalar minDistance = vtkm::NegativeInfinity32();
286     Scalar diff, t, dist;
287     Scalar distance = Scalar(0.0);
288     vtkm::IdComponent inside = 1;
289 
290     for (vtkm::IdComponent d = 0; d < 3; d++)
291     {
292       diff = this->MaxPoint[d] - this->MinPoint[d];
293       if (diff != Scalar(0.0))
294       {
295         t = (point[d] - this->MinPoint[d]) / diff;
296         // Outside before the box
297         if (t < Scalar(0.0))
298         {
299           inside = 0;
300           dist = this->MinPoint[d] - point[d];
301         }
302         // Outside after the box
303         else if (t > Scalar(1.0))
304         {
305           inside = 0;
306           dist = point[d] - this->MaxPoint[d];
307         }
308         else
309         {
310           // Inside the box in lower half
311           if (t <= Scalar(0.5))
312           {
313             dist = MinPoint[d] - point[d];
314           }
315           // Inside the box in upper half
316           else
317           {
318             dist = point[d] - MaxPoint[d];
319           }
320           if (dist > minDistance)
321           {
322             minDistance = dist;
323           }
324         }
325       }
326       else
327       {
328         dist = vtkm::Abs(point[d] - MinPoint[d]);
329         if (dist > Scalar(0.0))
330         {
331           inside = 0;
332         }
333       }
334       if (dist > Scalar(0.0))
335       {
336         distance += dist * dist;
337       }
338     }
339 
340     distance = vtkm::Sqrt(distance);
341     if (inside)
342     {
343       return minDistance;
344     }
345     else
346     {
347       return distance;
348     }
349   }
350 
Gradient(const Vector & point)351   VTKM_EXEC_CONT Vector Gradient(const Vector& point) const
352   {
353     vtkm::IdComponent minAxis = 0;
354     Scalar dist = 0.0;
355     Scalar minDist = vtkm::Infinity32();
356     vtkm::IdComponent3 location;
357     Vector normal(Scalar(0));
358     Vector inside(Scalar(0));
359     Vector outside(Scalar(0));
360     Vector center((this->MaxPoint + this->MinPoint) * Scalar(0.5));
361 
362     // Compute the location of the point with respect to the box
363     // Point will lie in one of 27 separate regions around or within the box
364     // Gradient vector is computed differently in each of the regions.
365     for (vtkm::IdComponent d = 0; d < 3; d++)
366     {
367       if (point[d] < this->MinPoint[d])
368       {
369         // Outside the box low end
370         location[d] = 0;
371         outside[d] = -1.0;
372       }
373       else if (point[d] > this->MaxPoint[d])
374       {
375         // Outside the box high end
376         location[d] = 2;
377         outside[d] = 1.0;
378       }
379       else
380       {
381         location[d] = 1;
382         if (point[d] <= center[d])
383         {
384           // Inside the box low end
385           dist = point[d] - this->MinPoint[d];
386           inside[d] = -1.0;
387         }
388         else
389         {
390           // Inside the box high end
391           dist = this->MaxPoint[d] - point[d];
392           inside[d] = 1.0;
393         }
394         if (dist < minDist) // dist is negative
395         {
396           minDist = dist;
397           minAxis = d;
398         }
399       }
400     }
401 
402     vtkm::Id indx = location[0] + 3 * location[1] + 9 * location[2];
403     switch (indx)
404     {
405       // verts - gradient points away from center point
406       case 0:
407       case 2:
408       case 6:
409       case 8:
410       case 18:
411       case 20:
412       case 24:
413       case 26:
414         for (vtkm::IdComponent d = 0; d < 3; d++)
415         {
416           normal[d] = point[d] - center[d];
417         }
418         vtkm::Normalize(normal);
419         break;
420 
421       // edges - gradient points out from axis of cube
422       case 1:
423       case 3:
424       case 5:
425       case 7:
426       case 9:
427       case 11:
428       case 15:
429       case 17:
430       case 19:
431       case 21:
432       case 23:
433       case 25:
434         for (vtkm::IdComponent d = 0; d < 3; d++)
435         {
436           if (outside[d] != 0.0)
437           {
438             normal[d] = point[d] - center[d];
439           }
440           else
441           {
442             normal[d] = 0.0;
443           }
444         }
445         vtkm::Normalize(normal);
446         break;
447 
448       // faces - gradient points perpendicular to face
449       case 4:
450       case 10:
451       case 12:
452       case 14:
453       case 16:
454       case 22:
455         for (vtkm::IdComponent d = 0; d < 3; d++)
456         {
457           normal[d] = outside[d];
458         }
459         break;
460 
461       // interior - gradient is perpendicular to closest face
462       case 13:
463         normal[0] = normal[1] = normal[2] = 0.0;
464         normal[minAxis] = inside[minAxis];
465         break;
466       default:
467         VTKM_ASSERT(false);
468         break;
469     }
470     return normal;
471   }
472 
473   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
474   VTKM_EXEC Box* operator->() { return this; }
475   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
476   VTKM_EXEC const Box* operator->() const { return this; }
477 
478 private:
479   Vector MinPoint;
480   Vector MaxPoint;
481 };
482 
483 //============================================================================
484 /// \brief Implicit function for a cylinder
485 ///
486 /// \c Cylinder computes the implicit function and function gradient
487 /// for a cylinder using F(r)=r^2-Radius^2. By default the Cylinder is
488 /// centered at the origin and the axis of rotation is along the
489 /// y-axis. You can redefine the center and axis of rotation by setting
490 /// the Center and Axis data members.
491 ///
492 /// Note that the cylinder is infinite in extent.
493 ///
494 class VTKM_ALWAYS_EXPORT Cylinder : public vtkm::internal::ImplicitFunctionBase<Cylinder>
495 {
496 public:
497   /// Construct cylinder radius of 0.5; centered at origin with axis
498   /// along y coordinate axis.
Cylinder()499   VTKM_EXEC_CONT Cylinder()
500     : Center(Scalar(0))
501     , Axis(Scalar(0), Scalar(1), Scalar(0))
502     , Radius(Scalar(0.5))
503   {
504   }
505 
Cylinder(const Vector & axis,Scalar radius)506   VTKM_EXEC_CONT Cylinder(const Vector& axis, Scalar radius)
507     : Center(Scalar(0))
508     , Axis(axis)
509     , Radius(radius)
510   {
511   }
512 
Cylinder(const Vector & center,const Vector & axis,Scalar radius)513   VTKM_EXEC_CONT Cylinder(const Vector& center, const Vector& axis, Scalar radius)
514     : Center(center)
515     , Axis(vtkm::Normal(axis))
516     , Radius(radius)
517   {
518   }
519 
SetCenter(const Vector & center)520   VTKM_CONT void SetCenter(const Vector& center) { this->Center = center; }
521 
SetAxis(const Vector & axis)522   VTKM_CONT void SetAxis(const Vector& axis) { this->Axis = vtkm::Normal(axis); }
523 
SetRadius(Scalar radius)524   VTKM_CONT void SetRadius(Scalar radius) { this->Radius = radius; }
525 
Value(const Vector & point)526   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
527   {
528     Vector x2c = point - this->Center;
529     FloatDefault proj = vtkm::Dot(this->Axis, x2c);
530     return vtkm::Dot(x2c, x2c) - (proj * proj) - (this->Radius * this->Radius);
531   }
532 
Gradient(const Vector & point)533   VTKM_EXEC_CONT Vector Gradient(const Vector& point) const
534   {
535     Vector x2c = point - this->Center;
536     FloatDefault t = this->Axis[0] * x2c[0] + this->Axis[1] * x2c[1] + this->Axis[2] * x2c[2];
537     vtkm::Vec<FloatDefault, 3> closestPoint = this->Center + (this->Axis * t);
538     return (point - closestPoint) * FloatDefault(2);
539   }
540 
541   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
542   VTKM_EXEC Cylinder* operator->() { return this; }
543   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
544   VTKM_EXEC const Cylinder* operator->() const { return this; }
545 
546 private:
547   Vector Center;
548   Vector Axis;
549   Scalar Radius;
550 };
551 
552 //============================================================================
553 /// \brief Implicit function for a frustum
554 class VTKM_ALWAYS_EXPORT Frustum : public vtkm::internal::ImplicitFunctionBase<Frustum>
555 {
556 public:
557   /// \brief Construct axis-aligned frustum with center at (0,0,0) and each side of length 1.0.
558   Frustum() = default;
559 
Frustum(const Vector points[6],const Vector normals[6])560   VTKM_EXEC_CONT Frustum(const Vector points[6], const Vector normals[6])
561   {
562     this->SetPlanes(points, normals);
563   }
564 
Frustum(const Vector points[8])565   VTKM_EXEC_CONT explicit Frustum(const Vector points[8]) { this->CreateFromPoints(points); }
566 
SetPlanes(const Vector points[6],const Vector normals[6])567   VTKM_EXEC void SetPlanes(const Vector points[6], const Vector normals[6])
568   {
569     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
570     {
571       this->Points[index] = points[index];
572     }
573     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
574     {
575       this->Normals[index] = normals[index];
576     }
577   }
578 
SetPlane(int idx,const Vector & point,const Vector & normal)579   VTKM_EXEC void SetPlane(int idx, const Vector& point, const Vector& normal)
580   {
581     VTKM_ASSERT((idx >= 0) && (idx < 6));
582     this->Points[idx] = point;
583     this->Normals[idx] = normal;
584   }
585 
GetPlanes(Vector points[6],Vector normals[6])586   VTKM_EXEC_CONT void GetPlanes(Vector points[6], Vector normals[6]) const
587   {
588     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
589     {
590       points[index] = this->Points[index];
591     }
592     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
593     {
594       normals[index] = this->Normals[index];
595     }
596   }
597 
GetPoints()598   VTKM_EXEC_CONT const Vector* GetPoints() const { return this->Points; }
599 
GetNormals()600   VTKM_EXEC_CONT const Vector* GetNormals() const { return this->Normals; }
601 
602   // The points should be specified in the order of hex-cell vertices
CreateFromPoints(const Vector points[8])603   VTKM_EXEC_CONT void CreateFromPoints(const Vector points[8])
604   {
605     // XXX(clang-format-3.9): 3.8 is silly. 3.9 makes it look like this.
606     // clang-format off
607     int planes[6][3] = {
608       { 3, 2, 0 }, { 4, 5, 7 }, { 0, 1, 4 }, { 1, 2, 5 }, { 2, 3, 6 }, { 3, 0, 7 }
609     };
610     // clang-format on
611 
612     for (int i = 0; i < 6; ++i)
613     {
614       const Vector& v0 = points[planes[i][0]];
615       const Vector& v1 = points[planes[i][1]];
616       const Vector& v2 = points[planes[i][2]];
617 
618       this->Points[i] = v0;
619       this->Normals[i] = vtkm::Normal(vtkm::TriangleNormal(v0, v1, v2));
620     }
621   }
622 
Value(const Vector & point)623   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
624   {
625     Scalar maxVal = vtkm::NegativeInfinity<Scalar>();
626     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
627     {
628       const Vector& p = this->Points[index];
629       const Vector& n = this->Normals[index];
630       const Scalar val = vtkm::Dot(point - p, n);
631       maxVal = vtkm::Max(maxVal, val);
632     }
633     return maxVal;
634   }
635 
Gradient(const Vector & point)636   VTKM_EXEC_CONT Vector Gradient(const Vector& point) const
637   {
638     Scalar maxVal = vtkm::NegativeInfinity<Scalar>();
639     vtkm::Id maxValIdx = 0;
640     for (vtkm::Id index : { 0, 1, 2, 3, 4, 5 })
641     {
642       const Vector& p = this->Points[index];
643       const Vector& n = this->Normals[index];
644       Scalar val = vtkm::Dot(point - p, n);
645       if (val > maxVal)
646       {
647         maxVal = val;
648         maxValIdx = index;
649       }
650     }
651     return this->Normals[maxValIdx];
652   }
653 
654   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
655   VTKM_EXEC Frustum* operator->() { return this; }
656   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
657   VTKM_EXEC const Frustum* operator->() const { return this; }
658 
659 private:
660   Vector Points[6] = { { -0.5f, 0.0f, 0.0f }, { 0.5f, 0.0f, 0.0f },  { 0.0f, -0.5f, 0.0f },
661                        { 0.0f, 0.5f, 0.0f },  { 0.0f, 0.0f, -0.5f }, { 0.0f, 0.0f, 0.5f } };
662   Vector Normals[6] = { { -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f },  { 0.0f, -1.0f, 0.0f },
663                         { 0.0f, 1.0f, 0.0f },  { 0.0f, 0.0f, -1.0f }, { 0.0f, 0.0f, 1.0f } };
664 };
665 
666 //============================================================================
667 /// \brief Implicit function for a plane
668 ///
669 /// A plane is defined by a point in the plane and a normal to the plane.
670 /// The normal does not have to be a unit vector. The implicit function will
671 /// still evaluate to 0 at the plane, but the values outside the plane
672 /// (and the gradient) will be scaled by the length of the normal vector.
673 class VTKM_ALWAYS_EXPORT Plane : public vtkm::internal::ImplicitFunctionBase<Plane>
674 {
675 public:
676   /// Construct plane passing through origin and normal to z-axis.
Plane()677   VTKM_EXEC_CONT Plane()
678     : Origin(Scalar(0))
679     , Normal(Scalar(0), Scalar(0), Scalar(1))
680   {
681   }
682 
683   /// Construct a plane through the origin with the given normal.
Plane(const Vector & normal)684   VTKM_EXEC_CONT explicit Plane(const Vector& normal)
685     : Origin(Scalar(0))
686     , Normal(normal)
687   {
688   }
689 
690   /// Construct a plane through the given point with the given normal.
Plane(const Vector & origin,const Vector & normal)691   VTKM_EXEC_CONT Plane(const Vector& origin, const Vector& normal)
692     : Origin(origin)
693     , Normal(normal)
694   {
695   }
696 
SetOrigin(const Vector & origin)697   VTKM_CONT void SetOrigin(const Vector& origin) { this->Origin = origin; }
698 
SetNormal(const Vector & normal)699   VTKM_CONT void SetNormal(const Vector& normal) { this->Normal = normal; }
700 
GetOrigin()701   VTKM_EXEC_CONT const Vector& GetOrigin() const { return this->Origin; }
GetNormal()702   VTKM_EXEC_CONT const Vector& GetNormal() const { return this->Normal; }
703 
Value(const Vector & point)704   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
705   {
706     return vtkm::Dot(point - this->Origin, this->Normal);
707   }
708 
Gradient(const Vector &)709   VTKM_EXEC_CONT Vector Gradient(const Vector&) const { return this->Normal; }
710 
711   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
712   VTKM_EXEC Plane* operator->() { return this; }
713   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
714   VTKM_EXEC const Plane* operator->() const { return this; }
715 
716 private:
717   Vector Origin;
718   Vector Normal;
719 };
720 
721 //============================================================================
722 /// \brief Implicit function for a sphere
723 ///
724 /// A sphere is defined by its center and a radius.
725 ///
726 /// The value of the sphere implicit function is the square of the distance
727 /// from the center biased by the radius (so the surface of the sphere is
728 /// at value 0).
729 class VTKM_ALWAYS_EXPORT Sphere : public vtkm::internal::ImplicitFunctionBase<Sphere>
730 {
731 public:
732   /// Construct sphere with center at (0,0,0) and radius = 0.5.
Sphere()733   VTKM_EXEC_CONT Sphere()
734     : Radius(Scalar(0.5))
735     , Center(Scalar(0))
736   {
737   }
738 
739   /// Construct a sphere with center at (0,0,0) and the given radius.
Sphere(Scalar radius)740   VTKM_EXEC_CONT explicit Sphere(Scalar radius)
741     : Radius(radius)
742     , Center(Scalar(0))
743   {
744   }
745 
Sphere(Vector center,Scalar radius)746   VTKM_EXEC_CONT Sphere(Vector center, Scalar radius)
747     : Radius(radius)
748     , Center(center)
749   {
750   }
751 
SetRadius(Scalar radius)752   VTKM_CONT void SetRadius(Scalar radius) { this->Radius = radius; }
753 
SetCenter(const Vector & center)754   VTKM_CONT void SetCenter(const Vector& center) { this->Center = center; }
755 
GetRadius()756   VTKM_EXEC_CONT Scalar GetRadius() const { return this->Radius; }
757 
GetCenter()758   VTKM_EXEC_CONT const Vector& GetCenter() const { return this->Center; }
759 
Value(const Vector & point)760   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
761   {
762     return vtkm::MagnitudeSquared(point - this->Center) - (this->Radius * this->Radius);
763   }
764 
Gradient(const Vector & point)765   VTKM_EXEC_CONT Vector Gradient(const Vector& point) const
766   {
767     return Scalar(2) * (point - this->Center);
768   }
769 
770   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
771   VTKM_EXEC Sphere* operator->() { return this; }
772   VTKM_DEPRECATED(1.6, "ImplicitFunctions are no longer pointers. Use . operator.")
773   VTKM_EXEC const Sphere* operator->() const { return this; }
774 
775 private:
776   Scalar Radius;
777   Vector Center;
778 };
779 
780 namespace detail
781 {
782 
783 struct ImplicitFunctionValueFunctor
784 {
785   template <typename ImplicitFunctionType>
operatorImplicitFunctionValueFunctor786   VTKM_EXEC_CONT typename ImplicitFunctionType::Scalar operator()(
787     const ImplicitFunctionType& function,
788     const typename ImplicitFunctionType::Vector& point) const
789   {
790     return function.Value(point);
791   }
792 };
793 
794 struct ImplicitFunctionGradientFunctor
795 {
796   template <typename ImplicitFunctionType>
operatorImplicitFunctionGradientFunctor797   VTKM_EXEC_CONT typename ImplicitFunctionType::Vector operator()(
798     const ImplicitFunctionType& function,
799     const typename ImplicitFunctionType::Vector& point) const
800   {
801     return function.Gradient(point);
802   }
803 };
804 
805 } // namespace detail
806 
807 //============================================================================
808 /// \brief Implicit function that can switch among different types.
809 ///
810 /// An `ImplicitFunctionMultiplexer` is a templated `ImplicitFunction` that takes
811 /// as template arguments any number of other `ImplicitFunction`s that it can
812 /// behave as. This allows you to decide at runtime which of these implicit
813 /// functions to define and compute.
814 ///
815 /// For example, let's say you want a filter that finds points either inside
816 /// a sphere or inside a box. Rather than create 2 different filters, one for
817 /// each type of implicit function, you can use `ImplicitFunctionMultiplexer<Sphere, Box>`
818 /// and then set either a `Sphere` or a `Box` at runtime.
819 ///
820 /// To use `ImplicitFunctionMultiplexer`, simply create the actual implicit
821 /// function that you want to use, and then set the `ImplicitFunctionMultiplexer`
822 /// to that concrete implicit function object.
823 ///
824 template <typename... ImplicitFunctionTypes>
825 class ImplicitFunctionMultiplexer
826   : public vtkm::internal::ImplicitFunctionBase<
827       ImplicitFunctionMultiplexer<ImplicitFunctionTypes...>>
828 {
829   vtkm::exec::internal::Variant<ImplicitFunctionTypes...> Variant;
830 
831   using Superclass =
832     vtkm::internal::ImplicitFunctionBase<ImplicitFunctionMultiplexer<ImplicitFunctionTypes...>>;
833 
834 public:
835   using Scalar = typename Superclass::Scalar;
836   using Vector = typename Superclass::Vector;
837 
838   ImplicitFunctionMultiplexer() = default;
839 
840   template <typename FunctionType>
ImplicitFunctionMultiplexer(const vtkm::internal::ImplicitFunctionBase<FunctionType> & function)841   VTKM_EXEC_CONT ImplicitFunctionMultiplexer(
842     const vtkm::internal::ImplicitFunctionBase<FunctionType>& function)
843     : Variant(reinterpret_cast<const FunctionType&>(function))
844   {
845   }
846 
Value(const Vector & point)847   VTKM_EXEC_CONT Scalar Value(const Vector& point) const
848   {
849     return this->Variant.CastAndCall(detail::ImplicitFunctionValueFunctor{}, point);
850   }
851 
Gradient(const Vector & point)852   VTKM_EXEC_CONT Vector Gradient(const Vector& point) const
853   {
854     return this->Variant.CastAndCall(detail::ImplicitFunctionGradientFunctor{}, point);
855   }
856 };
857 
858 //============================================================================
859 /// \brief Implicit function that can switch among known implicit function types.
860 ///
861 /// `ImplicitFunctionGeneral` can behave as any of the predefined implicit functions
862 /// provided by VTK-m. This is helpful when the type of implicit function is not
863 /// known at compile time. For example, say you want a filter that can operate on
864 /// an implicit function. Rather than compile separate versions of the filter, one
865 /// for each type of implicit function, you can compile the filter once for
866 /// `ImplicitFunctionGeneral` and then set the desired implicit function at runtime.
867 ///
868 /// To use `ImplicitFunctionGeneral`, simply create the actual implicit
869 /// function that you want to use, and then set the `ImplicitFunctionGeneral`
870 /// to that concrete implicit function object.
871 ///
872 class ImplicitFunctionGeneral
873   : public vtkm::ImplicitFunctionMultiplexer<vtkm::Box,
874                                              vtkm::Cylinder,
875                                              vtkm::Frustum,
876                                              vtkm::Plane,
877                                              vtkm::Sphere>
878 {
879   using Superclass = vtkm::ImplicitFunctionMultiplexer<vtkm::Box,
880                                                        vtkm::Cylinder,
881                                                        vtkm::Frustum,
882                                                        vtkm::Plane,
883                                                        vtkm::Sphere>;
884 
885 public:
886   using Superclass::Superclass;
887 };
888 
889 } // namespace vtkm
890 
891 #endif //vtk_m_ImplicitFunction_h
892