1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.md 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 lcl_Quad_h
11 #define lcl_Quad_h
12 
13 #include <lcl/ErrorCode.h>
14 #include <lcl/Shapes.h>
15 
16 #include <lcl/internal/Common.h>
17 
18 namespace lcl
19 {
20 
21 class Quad : public Cell
22 {
23 public:
Quad()24   constexpr LCL_EXEC Quad() : Cell(ShapeId::QUAD, 4) {}
Quad(const Cell & cell)25   constexpr LCL_EXEC explicit Quad(const Cell& cell) : Cell(cell) {}
26 };
27 
validate(Quad tag)28 LCL_EXEC inline lcl::ErrorCode validate(Quad tag) noexcept
29 {
30   if (tag.shape() != ShapeId::QUAD && tag.shape() != ShapeId::PIXEL)
31   {
32     return ErrorCode::WRONG_SHAPE_ID_FOR_TAG_TYPE;
33   }
34   if (tag.numberOfPoints() != 4)
35   {
36     return ErrorCode::INVALID_NUMBER_OF_POINTS;
37   }
38 
39   return ErrorCode::SUCCESS;
40 }
41 
42 template<typename CoordType>
parametricCenter(Quad,CoordType && pcoords)43 LCL_EXEC inline lcl::ErrorCode parametricCenter(Quad, CoordType&& pcoords) noexcept
44 {
45   LCL_STATIC_ASSERT_PCOORDS_IS_FLOAT_TYPE(CoordType);
46 
47   component(pcoords, 0) = 0.5f;
48   component(pcoords, 1) = 0.5f;
49   return ErrorCode::SUCCESS;
50 }
51 
52 template<typename CoordType>
parametricPoint(Quad,IdComponent pointId,CoordType && pcoords)53 LCL_EXEC inline lcl::ErrorCode parametricPoint(
54   Quad, IdComponent pointId, CoordType&& pcoords) noexcept
55 {
56   LCL_STATIC_ASSERT_PCOORDS_IS_FLOAT_TYPE(CoordType);
57 
58   switch (pointId)
59   {
60     case 0:
61       component(pcoords, 0) = 0.0f;
62       component(pcoords, 1) = 0.0f;
63       break;
64     case 1:
65       component(pcoords, 0) = 1.0f;
66       component(pcoords, 1) = 0.0f;
67       break;
68     case 2:
69       component(pcoords, 0) = 1.0f;
70       component(pcoords, 1) = 1.0f;
71       break;
72     case 3:
73       component(pcoords, 0) = 0.0f;
74       component(pcoords, 1) = 1.0f;
75       break;
76     default:
77       return ErrorCode::INVALID_POINT_ID;
78   }
79 
80   return ErrorCode::SUCCESS;
81 }
82 
83 template<typename CoordType>
parametricDistance(Quad,const CoordType & pcoords)84 LCL_EXEC inline ComponentType<CoordType> parametricDistance(Quad, const CoordType& pcoords) noexcept
85 {
86   LCL_STATIC_ASSERT_PCOORDS_IS_FLOAT_TYPE(CoordType);
87   return internal::findParametricDistance(pcoords, 2);
88 }
89 
90 template<typename CoordType>
cellInside(Quad,const CoordType & pcoords)91 LCL_EXEC inline bool cellInside(Quad, const CoordType& pcoords) noexcept
92 {
93   LCL_STATIC_ASSERT_PCOORDS_IS_FLOAT_TYPE(CoordType);
94 
95   using T = ComponentType<CoordType>;
96 
97   constexpr T eps = 0.001f;
98   return component(pcoords, 0) >= -eps && component(pcoords, 0) <= (T{1} + eps) &&
99          component(pcoords, 1) >= -eps && component(pcoords, 1) <= (T{1} + eps);
100 }
101 
102 template <typename Values, typename CoordType, typename Result>
interpolate(Quad,const Values & values,const CoordType & pcoords,Result && result)103 LCL_EXEC inline lcl::ErrorCode interpolate(
104   Quad,
105   const Values& values,
106   const CoordType& pcoords,
107   Result&& result) noexcept
108 {
109   LCL_STATIC_ASSERT_PCOORDS_IS_FLOAT_TYPE(CoordType);
110 
111   using T = internal::ClosestFloatType<typename Values::ValueType>;
112 
113   for (IdComponent c = 0; c < values.getNumberOfComponents(); ++c)
114   {
115     auto v0 = internal::lerp(static_cast<T>(values.getValue(0, c)),
116                              static_cast<T>(values.getValue(1, c)),
117                              static_cast<T>(component(pcoords, 0)));
118     auto v1 = internal::lerp(static_cast<T>(values.getValue(3, c)),
119                              static_cast<T>(values.getValue(2, c)),
120                              static_cast<T>(component(pcoords, 0)));
121     auto v = internal::lerp(v0, v1, static_cast<T>(component(pcoords, 1)));
122     component(result, c) = static_cast<ComponentType<Result>>(v);
123   }
124 
125   return ErrorCode::SUCCESS;
126 }
127 
128 namespace internal
129 {
130 
131 template <typename Values, typename CoordType, typename Result>
parametricDerivative(Quad,const Values & values,IdComponent comp,const CoordType & pcoords,Result && result)132 LCL_EXEC inline void parametricDerivative(
133   Quad, const Values& values, IdComponent comp, const CoordType& pcoords, Result&& result) noexcept
134 {
135   using T = internal::ClosestFloatType<typename Values::ValueType>;
136   T p0 = static_cast<T>(component(pcoords, 0));
137   T p1 = static_cast<T>(component(pcoords, 1));
138   T rm = T{1} - p0;
139   T sm = T{1} - p1;
140 
141   T dr = (static_cast<T>(values.getValue(0, comp)) * -sm) +
142          (static_cast<T>(values.getValue(1, comp)) *  sm) +
143          (static_cast<T>(values.getValue(2, comp)) *  p1) +
144          (static_cast<T>(values.getValue(3, comp)) * -p1);
145   T ds = (static_cast<T>(values.getValue(0, comp)) * -rm) +
146          (static_cast<T>(values.getValue(1, comp)) * -p0) +
147          (static_cast<T>(values.getValue(2, comp)) *  p0) +
148          (static_cast<T>(values.getValue(3, comp)) *  rm);
149 
150   component(result, 0) = static_cast<ComponentType<Result>>(dr);
151   component(result, 1) = static_cast<ComponentType<Result>>(ds);
152 }
153 
154 } // internal
155 
156 template <typename Points, typename Values, typename CoordType, typename Result>
derivative(Quad,const Points & points,const Values & values,const CoordType & pcoords,Result && dx,Result && dy,Result && dz)157 LCL_EXEC inline lcl::ErrorCode derivative(
158   Quad,
159   const Points& points,
160   const Values& values,
161   const CoordType& pcoords,
162   Result&& dx,
163   Result&& dy,
164   Result&& dz) noexcept
165 {
166   return internal::derivative2D(Quad{},
167                                 points,
168                                 values,
169                                 pcoords,
170                                 std::forward<Result>(dx),
171                                 std::forward<Result>(dy),
172                                 std::forward<Result>(dz));
173 }
174 
175 template <typename Points, typename PCoordType, typename WCoordType>
parametricToWorld(Quad,const Points & points,const PCoordType & pcoords,WCoordType && wcoords)176 LCL_EXEC inline lcl::ErrorCode parametricToWorld(
177   Quad,
178   const Points& points,
179   const PCoordType& pcoords,
180   WCoordType&& wcoords) noexcept
181 {
182   return interpolate(Quad{}, points, pcoords, std::forward<WCoordType>(wcoords));
183 }
184 
185 template <typename Points, typename WCoordType, typename PCoordType>
worldToParametric(Quad,const Points & points,const WCoordType & wcoords,PCoordType && pcoords)186 LCL_EXEC inline lcl::ErrorCode worldToParametric(
187   Quad,
188   const Points& points,
189   const WCoordType& wcoords,
190   PCoordType&& pcoords) noexcept
191 {
192   return internal::worldToParametric2D(Quad{}, points, wcoords, std::forward<PCoordType>(pcoords));
193 }
194 
195 } //namespace lcl
196 
197 #endif //lcl_Quad_h
198