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