SUAPI-CppWrapper
C++WrapperforSketchUpCAPI
Transformation.cpp
1 //
2 // Transformation.cpp
3 //
4 // Sketchup C++ Wrapper for C API
5 // MIT License
6 //
7 // Copyright (c) 2017 Tom Kaneko
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 
16 // The above copyright notice and this permission notice shall be included in all
17 // copies or substantial portions of the Software.
18 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 // SOFTWARE.
26 //
27 
28 // Macro for getting rid of unused variables commonly for assert checking
29 #define _unused(x) ((void)(x))
30 
31 #include <cassert>
32 #include <cmath>
33 
34 #include "SUAPI-CppWrapper/Transformation.hpp"
35 
36 #include <SketchUpAPI/geometry/vector3d.h>
37 #include <SketchUpAPI/geometry/point3d.h>
38 #include <SketchUpAPI/geometry/plane3d.h>
39 
40 #include "SUAPI-CppWrapper/model/Axes.hpp"
41 #include "SUAPI-CppWrapper/model/Face.hpp"
42 #include "SUAPI-CppWrapper/model/Loop.hpp"
43 #include "SUAPI-CppWrapper/model/LoopInput.hpp"
44 #include "SUAPI-CppWrapper/model/Vertex.hpp"
45 #include "SUAPI-CppWrapper/model/Material.hpp"
46 
47 namespace CW {
48 
50  Transformation(1.0)
51 {}
52 
53 
54 Transformation::Transformation(SUTransformation transformation):
55  m_transformation(transformation)
56 {}
57 
58 Transformation::Transformation(const Axes& axes, const Vector3D& translation, double scalar):
59  Transformation(Point3D(translation), axes.x_axis(), axes.y_axis(), axes.z_axis(), scalar)
60 {}
61 
63  m_transformation(SU_INVALID)
64 {
65  SUResult res = SUTransformationSetFromPointAndAxes(&m_transformation, origin, x_axis, y_axis, z_axis);
66  assert(res == SU_ERROR_NONE); _unused(res);
67  if (scalar != 1.0) {
68  // TODO:
69  assert(false);
70  }
71 }
72 
74  m_transformation(SU_INVALID)
75 {
76  SUResult res = SUTransformationScale(&m_transformation, scalar);
77  assert(res == SU_ERROR_NONE); _unused(res);
78 }
79 
80 
81 Transformation::Transformation(double x_scale, double y_scale, double z_scale):
82  m_transformation(SU_INVALID)
83 {
84  SUResult res = SUTransformationNonUniformScale(&m_transformation, x_scale, y_scale, z_scale);
85  assert(res == SU_ERROR_NONE); _unused(res);
86 }
87 
88 
90  m_transformation(SU_INVALID)
91 {
92  SUResult res = SUTransformationTranslation(&m_transformation, translation);
93  assert(res == SU_ERROR_NONE); _unused(res);
94 }
95 
96 
98  m_transformation(SU_INVALID)
99 {
100  SUResult res = SUTransformationScaleAboutPoint(&m_transformation, translation, scalar);
101  assert(res == SU_ERROR_NONE); _unused(res);
102 }
103 
104 
106  m_transformation(SU_INVALID)
107 {
108  SUResult res = SUTransformationSetFromPointAndNormal(&m_transformation, translation, normal);
109  assert(res == SU_ERROR_NONE); _unused(res);
110 }
111 
112 
113 Transformation::Transformation(const Point3D& point, const Vector3D& vector, double angle):
114  m_transformation(SU_INVALID)
115 {
116  SUResult res = SUTransformationRotation(&m_transformation, point, vector, angle);
117  assert(res == SU_ERROR_NONE); _unused(res);
118 }
119 
120 
121 Transformation::Transformation(const Transformation& transform1, const Transformation& transform2, double weight):
122  m_transformation(SU_INVALID)
123 {
124  SUResult res = SUTransformationInterpolate(&m_transformation, transform1, transform2, weight);
125  assert(res == SU_ERROR_NONE); _unused(res);
126 }
127 
128 
129 double Transformation::determinant() const {
130  // From: http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm
131  // Note this is for general 4x4 matrix, and it is excessive for a 3x3 matrix.
132  double value =
133  m_transformation.values[12] * m_transformation.values[9] * m_transformation.values[6] * m_transformation.values[3]-m_transformation.values[8] * m_transformation.values[13] * m_transformation.values[6] * m_transformation.values[3]-m_transformation.values[12] * m_transformation.values[5] * m_transformation.values[10] * m_transformation.values[3]+m_transformation.values[4] * m_transformation.values[13] * m_transformation.values[10] * m_transformation.values[3]+
134  m_transformation.values[8] * m_transformation.values[5] * m_transformation.values[14] * m_transformation.values[3]-m_transformation.values[4] * m_transformation.values[9] * m_transformation.values[14] * m_transformation.values[3]-m_transformation.values[12] * m_transformation.values[9] * m_transformation.values[2] * m_transformation.values[7]+m_transformation.values[8] * m_transformation.values[13] * m_transformation.values[2] * m_transformation.values[7]+
135  m_transformation.values[12] * m_transformation.values[1] * m_transformation.values[10] * m_transformation.values[7]-m_transformation.values[0] * m_transformation.values[13] * m_transformation.values[10] * m_transformation.values[7]-m_transformation.values[8] * m_transformation.values[1] * m_transformation.values[14] * m_transformation.values[7]+m_transformation.values[0] * m_transformation.values[9] * m_transformation.values[14] * m_transformation.values[7]+
136  m_transformation.values[12] * m_transformation.values[5] * m_transformation.values[2] * m_transformation.values[11]-m_transformation.values[4] * m_transformation.values[13] * m_transformation.values[2] * m_transformation.values[11]-m_transformation.values[12] * m_transformation.values[1] * m_transformation.values[6] * m_transformation.values[11]+m_transformation.values[0] * m_transformation.values[13] * m_transformation.values[6] * m_transformation.values[11]+
137  m_transformation.values[4] * m_transformation.values[1] * m_transformation.values[14] * m_transformation.values[11]-m_transformation.values[0] * m_transformation.values[5] * m_transformation.values[14] * m_transformation.values[11]-m_transformation.values[8] * m_transformation.values[5] * m_transformation.values[2] * m_transformation.values[15]+m_transformation.values[4] * m_transformation.values[9] * m_transformation.values[2] * m_transformation.values[15]+
138  m_transformation.values[8] * m_transformation.values[1] * m_transformation.values[6] * m_transformation.values[15]-m_transformation.values[0] * m_transformation.values[9] * m_transformation.values[6] * m_transformation.values[15]-m_transformation.values[4] * m_transformation.values[1] * m_transformation.values[10] * m_transformation.values[15]+m_transformation.values[0] * m_transformation.values[5] * m_transformation.values[10] * m_transformation.values[15];
139  return value;
140 }
141 
142 
143 std::array<double, 4> Transformation::multiply4x1(std::array<double, 4> matrix4_1) const {
144  std::array<double, 4> output;
145  for (size_t i=0; i < 4; ++i) {
146  // This one is for multiplying 1x4 by 4x4:
147  //output[i] = matrix4_1[i] * (m_transformation.values[i] +
148  // m_transformation.values[i+4] +
149  // m_transformation.values[i+8] +
150  // m_transformation.values[i+12]);
151  // This one is for multiplying 4x4 by 4x1:
152  output[i] = (m_transformation.values[i] * matrix4_1[0]) +
153  (m_transformation.values[i+4] * matrix4_1[1]) +
154  (m_transformation.values[i+8] * matrix4_1[2]) +
155  (m_transformation.values[i+12] * matrix4_1[3]);
156 
157  }
158  return output;
159 }
160 
161 
162 
163 double Transformation::operator[](size_t i) const {
164  if (i > 15) {
165  throw std::out_of_range("CW::Transformation::operator[](): index range is between 0 and 15");
166  }
167  return m_transformation.values[i];
168 }
169 
170 double& Transformation::operator[](size_t i) {
171  if (i > 15) {
172  throw std::out_of_range("CW::Transformation::operator[](): index range is between 0 and 15");
173  }
174  return m_transformation.values[i];
175 }
176 
177 
178 SUTransformation Transformation::ref() const {
179  return m_transformation;
180 }
181 
182 Transformation::operator SUTransformation() const {
183  return ref();
184 }
185 
186 Transformation::operator const SUTransformation*() const {
187  return &m_transformation;
188 }
189 
190 
192  bool is_identity;
193  SUResult res = SUTransformationIsIdentity(&m_transformation, &is_identity);
194  assert(res == SU_ERROR_NONE); _unused(res);
195  return is_identity;
196 }
197 
198 
200  SUTransformation inverse = SU_INVALID;
201  SUResult res = SUTransformationGetInverse(&m_transformation, &inverse);
202  assert(res == SU_ERROR_NONE); _unused(res);
203  return Transformation(inverse);
204 }
205 
206 
208  SUVector3D x_axis = SU_INVALID;
209  SUResult res = SUTransformationGetXAxis(&m_transformation, &x_axis);
210  assert(res == SU_ERROR_NONE); _unused(res);
211  return Vector3D(x_axis);
212 }
213 
214 
216  SUVector3D y_axis = SU_INVALID;
217  SUResult res = SUTransformationGetYAxis(&m_transformation, &y_axis);
218  assert(res == SU_ERROR_NONE); _unused(res);
219  return Vector3D(y_axis);
220 }
221 
222 
224  SUVector3D z_axis = SU_INVALID;
225  SUResult res = SUTransformationGetZAxis(&m_transformation, &z_axis);
226  assert(res == SU_ERROR_NONE); _unused(res);
227  return Vector3D(z_axis);
228 }
229 
230 
232  double z_rotation;
233  SUResult res = SUTransformationGetZRotation(&m_transformation, &z_rotation);
234  assert(res == SU_ERROR_NONE); _unused(res);
235  return z_rotation;
236 }
237 
238 
240  if (m_transformation.values[15] == 1.0) {
241  // No normalisation necessary (is already normal)
242  return (*this);
243  }
244  assert(m_transformation.values[15] != 0.0);
245  for (size_t i=0; i < 15; ++i) {
246  m_transformation.values[i] = m_transformation.values[i] / m_transformation.values[15];
247  }
248  m_transformation.values[15] = 1.0;
249  return (*this);
250 }
251 
252 
254  SUPoint3D origin = SU_INVALID;
255  SUResult res = SUTransformationGetOrigin(&m_transformation, &origin);
256  assert(res == SU_ERROR_NONE); _unused(res);
257  return Point3D(origin);
258 }
259 
260 
262  if (m_transformation.values[15] == 1.0) {
263  return Vector3D( m_transformation.values[12], m_transformation.values[13], m_transformation.values[14]);
264  }
265  return Vector3D( m_transformation.values[12] / m_transformation.values[15], m_transformation.values[13] / m_transformation.values[15], m_transformation.values[14] / m_transformation.values[15]);
266 }
267 
268 
270  SUTransformation out_transform = SU_INVALID;
271  SUResult res = SUTransformationMultiply(&m_transformation, &transform.m_transformation, &out_transform);
272  assert(res == SU_ERROR_NONE); _unused(res);
273  return Transformation(out_transform);
274 }
275 
276 
277 /**
278 * Friend Functions of class Transformation
279 */
280 Vector3D operator*(const Transformation &lhs, const Vector3D &rhs) {
281  if (!rhs) {
282  throw std::invalid_argument("CW::Transformation::operator*(const Vector3D &lhs, const Transformation &rhs): Vector3D given is null");
283  }
284  SUVector3D transformed = rhs;
285  SUResult res = SUVector3DTransform(&lhs.m_transformation, &transformed);
286  assert(res == SU_ERROR_NONE); _unused(res);
287  return Vector3D(transformed);
288 }
289 
290 Vector3D operator*(const Vector3D &lhs, const Transformation &rhs) {
291  // Can't actually multiply a vector by transformation, so return the transforamtion multiplied by the vector
292  return rhs * lhs;
293 }
294 
295 /**
296 * Friend Functions of class Transformation
297 */
298 Point3D operator*(const Transformation &lhs, const Point3D &rhs) {
299  if (!rhs) {
300  throw std::invalid_argument("CW::Transformation::operator*(const Point3D &lhs, const Transformation &rhs): Point3D given is null");
301  }
302  SUPoint3D transformed = rhs;
303  SUResult res = SUPoint3DTransform(&lhs.m_transformation, &transformed);
304  assert(res == SU_ERROR_NONE); _unused(res);
305  return Vector3D(transformed);
306 }
307 
308 
309 Point3D operator*(const Point3D &lhs, const Transformation &rhs) {
310  // Can't actually multiply a vector by transformation, so return the transforamtion multiplied by the vector
311  return rhs * lhs;
312 }
313 
314 
315 /**
316 * Friend Functions of class Transformation
317 */
318 Plane3D operator*(const Transformation &lhs, const Plane3D &rhs) {
319  if (!rhs) {
320  throw std::invalid_argument("CW::Transformation::operator*(const Transformation &lhs, const Plane3D &rhs): Plane3D given is null");
321  }
322  SUPlane3D transformed = rhs;
323  SUResult res = SUPlane3DTransform(&lhs.m_transformation, &transformed);
324  assert(res == SU_ERROR_NONE); _unused(res);
325  return Plane3D(transformed);
326 }
327 
328 
329 Plane3D operator*(const Plane3D &lhs, const Transformation &rhs) {
330  return rhs * lhs;
331 }
332 
333 /**
334 * Friend Functions of class Transformation
335 */
336 Face operator*(const Face &lhs, const Transformation &rhs) {
337  if (!lhs) {
338  throw std::invalid_argument("CW::Transformation::operator*(const Face &lhs, const Transformation &rhs): Face given is null");
339  }
340  // We transform all the vertices then create loops
341  std::vector<Vertex> outer_vertices = lhs.outer_loop().vertices();
342  std::vector<Point3D> trans_outer_points;
343  trans_outer_points.reserve(outer_vertices.size());
344  for (size_t i=0; i < outer_vertices.size(); ++i) {
345  trans_outer_points.push_back(outer_vertices[i].position() * rhs);
346  }
347  LoopInput outer_loop_input = lhs.outer_loop().loop_input();
348  Face trans_face(trans_outer_points, outer_loop_input);
349  // Now add inner loops
350  std::vector<Loop> inner_loops = lhs.inner_loops();
351  for (size_t j=0; j < inner_loops.size(); ++j) {
352  std::vector<Vertex> inner_vertices = inner_loops[j].vertices();
353  std::vector<Point3D> trans_inner_points;
354  trans_inner_points.reserve(inner_vertices.size());
355  for (size_t i=0; i < inner_vertices.size(); ++i) {
356  trans_inner_points.push_back(inner_vertices[i].position() * rhs);
357  }
358  LoopInput inner_loop_input = inner_loops[j].loop_input();
359  trans_face.add_inner_loop(trans_inner_points, inner_loop_input);
360  }
361  if (!!lhs.material()) {
362  trans_face.material(lhs.material());
363  }
364  trans_face.copy_attributes_from(lhs);
365  return trans_face;
366 }
367 
368 
369 bool Transformation::equal(const Transformation transform, const double epsilon) const {
370  for (size_t i=0; i < 16; ++i) {
371  // Skip bottom row, except last
372  if (i == 3 || i == 7 || i == 11) {
373  }
374  else {
375  if (!(fabs((*this)[i] - transform[i]) < epsilon)) {
376  return false;
377  }
378  }
379  }
380  return true;
381 }
382 
383 bool Transformation::operator==(const Transformation transform) const {
384  return this->equal(transform);
385 }
386 
387 
388 /**
389 * Publc Static Methods
390 */
392  if (!line) {
393  throw std::invalid_argument("CW::Transformation::transformation_rotate_about_line(): Line3D given is null");
394  }
395  // TODO: create solution in terms of SU's native Transformation functions.
396 
397  // Solution derived from this article: http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/
398  SUTransformation transform;
399  double u = line.direction.x;
400  double v = line.direction.y;
401  double w = line.direction.z;
402  double a = line.point.x;
403  double b = line.point.y;
404  double c = line.point.z;
405  double cos_angle = cos(angle);
406  double sin_angle = sin(angle);
407  double u2 = pow(u,2);
408  double v2 = pow(v,2);
409  double w2 = pow(w,2);
410  double au = a * u;
411  double av = a * v;
412  double aw = a * w;
413  double bu = b * u;
414  double bv = b * v;
415  double bw = b * w;
416  double cu = c * u;
417  double cv = c * v;
418  double cw = c * w;
419 
420  transform.values[0] = u2 + (cos_angle * (v2 + w2));
421  transform.values[1] = (u * v * (1 - cos_angle)) + (w * sin_angle);
422  transform.values[2] = (u * w * (1 - cos_angle)) - (v * sin_angle);
423  transform.values[3] = 0;
424 
425  transform.values[4] = (u * v * (1 - cos_angle)) - (w * sin_angle);
426  transform.values[5] = v2 + ((u2 + w2) * cos_angle);
427  transform.values[6] = (v * w * (1 - cos_angle)) + (u * sin_angle);
428  transform.values[7] = 0;
429 
430  transform.values[8] = (u * w * (1 - cos_angle)) + (v * sin_angle);
431  transform.values[9] = (v * w * (1 - cos_angle)) - (u * sin_angle);
432  transform.values[10] = w2 + ((u2 + v2) * cos_angle);
433  transform.values[11] = 0;
434 
435  transform.values[12] = (( (a * (v2 + w2)) - (u * (bv + cw)) ) * (1 - cos_angle)) + ((bw - cv) * sin_angle);
436  transform.values[13] = (( (b * (u2 + w2)) - (v * (au + cw)) ) * (1 - cos_angle)) + ((cu - aw) * sin_angle);
437  transform.values[14] = (( (c * (u2 + v2)) - (w * (au + bv)) ) * (1 - cos_angle)) + ((av - bu) * sin_angle);
438  transform.values[15] = 1;
439  return Transformation(transform);
440 }
441 
442 } /* namespace CW */
Vector3D x_axis() const
Point3D origin() const
void add_inner_loop(std::vector< Point3D > &points, LoopInput &loop_input)
Definition: Face.cpp:187
std::vector< Loop > inner_loops() const
Definition: Face.cpp:315
bool copy_attributes_from(const Entity &entity)
Copies attributes from another Entity object to this one.
Definition: Entity.cpp:156
Transformation inverse() const
Transformation operator*(Transformation transform)
Vector3D z_axis() const
double z_rotation() const
Vector3D translation() const
bool is_identity() const
Definition: Color.hpp:34
static Transformation transformation_rotate_about_line(const double angle, const Line3D line)
bool equal(const Transformation transform, const double epsilon=EPSILON) const
std::vector< Vertex > vertices() const
Definition: Loop.cpp:112
Vector3D y_axis() const
Transformation & normalize()