1 // This file is part of libigl, a simple c++ geometry processing library.
2 //
3 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public License
6 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
7 // obtain one at http://mozilla.org/MPL/2.0/.
8 #include "snap_to_canonical_view_quat.h"
9
10 #include "canonical_quaternions.h"
11 #include "normalize_quat.h"
12
13 #include <cstdio>
14 #include <cassert>
15
16 // Note: For the canonical view quaternions it should be completely possible to
17 // determine this anaylitcally. That is the max_distance should be a
18 // theoretical known value
19 // Also: I'm not sure it matters in this case, but. We are dealing with
20 // quaternions on the 4d unit sphere, but measuring distance in general 4d
21 // space (i.e. not geodesics on the sphere). Probably something with angles
22 // would be better.
23 template <typename Q_type>
snap_to_canonical_view_quat(const Q_type * q,const Q_type threshold,Q_type * s)24 IGL_INLINE bool igl::snap_to_canonical_view_quat(
25 const Q_type* q,
26 const Q_type threshold,
27 Q_type* s)
28 {
29 // Copy input into output
30 // CANNOT use std::copy here according to:
31 // http://www.cplusplus.com/reference/algorithm/copy/
32 s[0] = q[0];
33 s[1] = q[1];
34 s[2] = q[2];
35 s[3] = q[3];
36
37 // Normalize input quaternion
38 Q_type qn[4];
39 bool valid_len =
40 igl::normalize_quat(q,qn);
41 // If normalizing valid then don't bother
42 if(!valid_len)
43 {
44 return false;
45 }
46
47 // 0.290019
48 const Q_type MAX_DISTANCE = 0.4;
49 Q_type min_distance = 2*MAX_DISTANCE;
50 int min_index = -1;
51 double min_sign = 0;
52 // loop over canonical view quaternions
53 for(double sign = -1;sign<=1;sign+=2)
54 {
55 for(int i = 0; i<NUM_CANONICAL_VIEW_QUAT; i++)
56 {
57 Q_type distance = 0.0;
58 // loop over coordinates
59 for(int j = 0;j<4;j++)
60 {
61 // Double cast because of bug in llvm version 4.2 with -O3
62 distance +=
63 (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j))*
64 (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j));
65 }
66 if(min_distance > distance)
67 {
68 min_distance = distance;
69 min_index = i;
70 min_sign = sign;
71 }
72 }
73 }
74
75 if(MAX_DISTANCE < min_distance)
76 {
77 fprintf(
78 stderr,
79 "ERROR: found new max MIN_DISTANCE: %g\n"
80 "PLEASE update snap_to_canonical_quat()",
81 min_distance);
82 }
83
84 assert(min_distance < MAX_DISTANCE);
85 assert(min_index >= 0);
86
87 if( min_distance/MAX_DISTANCE <= threshold)
88 {
89 // loop over coordinates
90 for(int j = 0;j<4;j++)
91 {
92 s[j] = min_sign*igl::CANONICAL_VIEW_QUAT<Q_type>(min_index,j);
93 }
94 return true;
95 }
96 return false;
97 }
98
99 template <typename Scalarq, typename Scalars>
snap_to_canonical_view_quat(const Eigen::Quaternion<Scalarq> & q,const double threshold,Eigen::Quaternion<Scalars> & s)100 IGL_INLINE bool igl::snap_to_canonical_view_quat(
101 const Eigen::Quaternion<Scalarq> & q,
102 const double threshold,
103 Eigen::Quaternion<Scalars> & s)
104 {
105 return snap_to_canonical_view_quat<Scalars>(
106 q.coeffs().data(),threshold,s.coeffs().data());
107 }
108
109 #ifdef IGL_STATIC_LIBRARY
110 // Explicit template instantiation
111 // generated by autoexplicit.sh
112 template bool igl::snap_to_canonical_view_quat<double>(const double*, double, double*);
113 // generated by autoexplicit.sh
114 template bool igl::snap_to_canonical_view_quat<float>(const float*, float, float*);
115 template bool igl::snap_to_canonical_view_quat<float, float>(Eigen::Quaternion<float, 0> const&, double, Eigen::Quaternion<float, 0>&);
116 template bool igl::snap_to_canonical_view_quat<double, double>(Eigen::Quaternion<double, 0> const&, double, Eigen::Quaternion<double, 0>&);
117 #endif
118