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