PointFunctions.hpp
Go to the documentation of this file.
1 // ========================================================================================
2 // ApproxMVBB
3 // Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 // ========================================================================================
9 
10 #ifndef ApproxMVBB_PointFunctions_hpp
11 #define ApproxMVBB_PointFunctions_hpp
12 
13 #include <string>
14 
16 #include ApproxMVBB_AssertionDebug_INCLUDE_FILE
17 #include ApproxMVBB_StaticAssert_INCLUDE_FILE
18 
19 #include ApproxMVBB_TypeDefs_INCLUDE_FILE
21 
24 
26 
27 namespace ApproxMVBB{
28 namespace PointFunctions {
29 
32 
33  template<typename Derived, typename Gen>
34  void applyRandomRotTrans(MatrixBase<Derived> & points, Gen & g) {
35  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3, Eigen::Dynamic)
36  Quaternion q;
37  q.coeffs() = q.coeffs().unaryExpr(g); // TODO: Check if q=[0,0,0,0] is correctly normalized !! otherwise crash! NaN
38  q.normalize();
39  Matrix33 R = q.matrix();
40  Vector3 trans;
41  trans = trans.unaryExpr(g);
42  points = R*points;
43  points.colwise() += trans;
44  }
45 
46  template<typename Derived>
47  void applyRandomRotTrans(MatrixBase<Derived> & points) {
48 
49  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,3, Eigen::Dynamic)
50  Quaternion q;
51  q.coeffs().setRandom();
52  q.normalize();
53  Matrix33 R = q.matrix();
54  Vector3 trans;
55  trans.setRandom();
56  points = R*points;
57  points.colwise() += trans;
58  }
59 
60 
61 
62  template<typename VecT1, typename VecT2>
63  inline bool almostEqualAbs(const VecT1 & a, const VecT2 & b, PREC eps = 1.0e-8 ) {
64  return ((a-b).array().abs() <= eps).all();
65  }
66 
67  template<typename VecT1, typename VecT2>
68  inline bool almostEqualUlp(const VecT1 & a, const VecT2 & b /*, PREC eps = 1.0e-8*/ ) {
69  bool ret = true;
70  for(unsigned int i=0;i<a.size();i++){
71  ret = ret && FloatingPoint<PREC>(a(i)).AlmostEquals(FloatingPoint<PREC>(b(i)));
72  }
73  return ret;
74  }
75 
76 
77  template<typename VecT1, typename VecT2>
78  inline bool equal(const VecT1 & a, const VecT2 & b) {
79  return (a.array() == b.array()).all();
80  }
81 
83  template<typename VecT1, typename VecT2, typename VecT3>
84  inline int orient2d(const VecT1 & a, const VecT2 & b, const VecT3 & c) {
85  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT1,2)
86  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT2,2)
87  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT3,2)
88 
89  PREC f_A = GeometryPredicates::orient2d(const_cast<double*>(a.data()),
90  const_cast<double*>(b.data()),
91  const_cast<double*>(c.data()));
92 
93  return ( ( f_A < 0.0 )? -1 : ( (f_A > 0.0)? 1 : 0) );
94 
95  }
96 
98  template<typename VecT1, typename VecT2, typename VecT3>
99  inline bool leftTurn(const VecT1 & a, const VecT2 & b, const VecT3 & c) {
100  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT1,2)
101  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT2,2)
102  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT3,2)
103  return orient2d(a,b,c) > 0;
104  }
105 
107  template<typename VecT1, typename VecT2, typename VecT3>
108  inline int collinearAreOrderedAlongLine(const VecT1 & a, const VecT2 & b, const VecT3 & c) {
109  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT1,2)
110  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT2,2)
111  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT3,2)
112 
113  if (a(0) < b(0)) return !(c(0) < b(0));
114  if (b(0) < a(0)) return !(b(0) < c(0));
115  if (a(1) < b(1)) return !(c(1) < b(1));
116  if (b(1) < a(1)) return !(b(1) < c(1));
117  return true; // a==b
118 
119  }
120 
121 
122 
124  template<typename VecT1, typename VecT2>
125  inline PREC getAngle(const VecT1 & a, const VecT2 & b) {
126  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT1,2)
127  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT2,2)
128  Vector2 t = b - a ;
129  PREC angle = std::atan2(t(1),t(0));
130  if(angle<0.0) {
131  angle += 2*M_PI;
132  }
133  return angle;
134  }
135 
136  template<typename VecT1, typename VecT2>
137  Vector2 intersectLines(const VecT1 & p1, PREC ang1,
138  const VecT2 & p2, PREC ang2, PREC eps = 1e-10) {
139  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT1,2)
140  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VecT2,2)
141  using namespace std;
142  // Two lines p1 + a*t1 = p2 + b*t2;
143  // [-a, b]^-1 * (p1-p2) = [t1;t2]
144  // p = (p1-p2)
145  // =>
146  // t1 = px by - bx py / (ay bx - ax by);
147 
148  Vector2 a;
149  a(0) = cos(ang1);
150  a(1) = sin(ang1);
151 
152  PREC bx = cos(ang2);
153  PREC by = sin(ang2);
154 
155  PREC nom = (p1(0)-p2(0))*by - (p1(1)-p2(1)) *bx;
156 
157  PREC det = a(1)*bx - a(0)*by;
158 
159  if( det == 0.0 ) { // lines are collinear
160  if(abs(nom) < eps ) { // if the two lines are almost identical! rot( p1-p2, 90 degrees) almost orthogonal to b
161  return p1;
162  }
163  a(0) = std::numeric_limits<PREC>::infinity();
164  a(1) = std::numeric_limits<PREC>::infinity();
165  return a;
166  }
167 
168  return (nom / det) *a + p1;
169  }
170 
172  template<typename Derived>
173  inline unsigned int minPointYX(const MatrixBase<Derived> & points) {
174  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,2, Eigen::Dynamic)
175  unsigned int index = 0;
176  for(unsigned int i=1; i<points.cols(); ++i) {
177  if( points(1,i) < points(1,index) ) {
178  index = i;
179  } else if( points(1,i) == points(1,index) && points(0,i) < points(0,index) ) {
180  index = i;
181  }
182  }
183  return index;
184  }
185 
187  template<typename Derived>
188  inline unsigned int minPointXY(const MatrixBase<Derived> & points) {
189  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,2, Eigen::Dynamic)
190  unsigned int index = 0;
191  for(unsigned int i=1; i<points.cols(); ++i) {
192  if( points(0,i) < points(0,index) ) {
193  index = i;
194  } else if( points(0,i) == points(0,index) && points(1,i) < points(1,index) ) {
195  index = i;
196  }
197  }
198  return index;
199  }
200 
201  template<unsigned int Dimension,
202  typename Derived>
203  auto estimateDiameter( const MatrixBase<Derived> & points,
204  const PREC epsilon,
205  std::size_t seed = RandomGenerators::defaultSeed) -> std::pair<VectorStat<Dimension>,VectorStat<Dimension> >
206  {
207 
208  ApproxMVBB_STATIC_ASSERTM(Derived::RowsAtCompileTime == Dimension, "input points matrix need to be (Dimension x N) ");
209  ApproxMVBB_STATIC_ASSERTM((std::is_same<typename Derived::Scalar, PREC>::value), "estimate diameter can only accept double so far")
210 
211  /* MatrixBase<Derived> & pp = const_cast< MatrixBase<Derived> &>(points); */
212 
213  // Construct pointer list
214  auto size = points.cols();
215  PREC const * *pList = new PREC const*[size];
216  for(decltype(size) i=0; i<size; ++i) {
217  pList[i] = points.col(i).data() ;
218  }
219 
220  Diameter::TypeSegment pairP;
221  DiameterEstimator diamEstimator(seed);
222  diamEstimator.estimateDiameter(&pairP,pList,0,(int)(size-1),Dimension,epsilon);
223 
225  const MatrixMap<const Vector2d> p1(pairP.extremity1);
226  const MatrixMap<const Vector2d> p2(pairP.extremity2);
227 
228 
229 
230  ApproxMVBB_MSGLOG_L2( "p1: " << p1.transpose() << std::endl
231  << "p2: " << p2.transpose() << std::endl
232  << " l: " << std::sqrt(pairP.squareDiameter) << std::endl);
233 
234  delete[] pList;
235  return {p1,p2};
236 
237  }
238 
240  public:
241  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
243 
244 
245  using PointData = std::pair<unsigned int, bool>;
246 
250  template<typename Derived>
251  CompareByAngle(const MatrixBase<Derived> & points,
252  const Vector2 &base,
253  unsigned int baseIdx,
254  unsigned int & deletedPoints): m_p(points), m_base(base),m_baseIdx(baseIdx), m_deletedPoints(deletedPoints) {
255  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived,2, Eigen::Dynamic)
256  }
257 
259  int operator()( const PointData & point1In,
260  const PointData & point2In )
261  {
262  using namespace PointFunctions;
263  PointData & point1 = const_cast<PointData &>(point1In);
264  PointData & point2 = const_cast<PointData &>(point2In);
265  unsigned int idx1 = point1.first;
266  unsigned int idx2 = point2.first;
267 //
268 // if(idx1<idx2){
269 // if(almostEqualUlp(m_p.col(idx1),m_p.col(idx2))){
270 // if(!point1.second){point1.second = true; ++m_deletedPoints;}
271 // return false;
272 // }
273 // }else{
274 // if(almostEqualUlp(m_p.col(idx2),m_p.col(idx1))){
275 // if(!point2.second){point2.second = true; ++m_deletedPoints;}
276 // return false;
277 // }
278 // }
279 
280  // Compare by Area Sign (by ascending positive (z-Axis Rotation) angle in x-y Plane)
281  // always insert the smaller index first , and the larger second (as the function is not completely symmetric!
282  if(idx1<idx2) {
283  int sgn = orient2d( m_base, m_p.col(idx1), m_p.col(idx2) );
284  if(sgn != 0){ return (sgn > 0);}
285  } else {
286  int sgn = orient2d( m_base, m_p.col(idx2), m_p.col(idx1) );
287  if(sgn != 0) {return (sgn < 0);}
288 
289  }
290  // points are collinear
291 
292  if(PointFunctions::equal(m_base, m_p.col(idx1))) return false;
293  if(PointFunctions::equal(m_base, m_p.col(idx2))) return true;
294  if(PointFunctions::equal(m_p.col(idx1), m_p.col(idx2))) return false;
295 
296  // if idx2 lies between mbase and idx1 then it should go after idx1
297  return collinearAreOrderedAlongLine(m_base,m_p.col(idx2),m_p.col(idx1));
298  }
299  private:
300  const MatrixRef<const Matrix2Dyn> m_p;
301  const Vector2 m_base; const unsigned int m_baseIdx;
302  unsigned int & m_deletedPoints;
303 
304  };
305 
306 }
307 }
308 #endif
bool almostEqualAbs(const VecT1 &a, const VecT2 &b, PREC eps=1.0e-8)
Eigen::Quaternion< Scalar > Quaternion
unsigned int minPointXY(const MatrixBase< Derived > &points)
unsigned int minPointYX(const MatrixBase< Derived > &points)
Eigen::Matrix< Scalar, M, 1 > VectorStat
These are some container definitions.
double estimateDiameter(Diameter::TypeSegment *theDiam, double const **theList, const int first, const int last, const int dim, double epsilon)
bool almostEqualUlp(const VecT1 &a, const VecT2 &b)
std::pair< unsigned int, bool > PointData
REAL orient2d(REAL *pa, REAL *pb, REAL *pc)
Definition: Predicates.cpp:907
int orient2d(const VecT1 &a, const VecT2 &b, const VecT3 &c)
CompareByAngle(const MatrixBase< Derived > &points, const Vector2 &base, unsigned int baseIdx, unsigned int &deletedPoints)
bool equal(const VecT1 &a, const VecT2 &b)
static const uint64_t defaultSeed
Eigen::Matrix< Scalar, 3, 3 > Matrix33
int operator()(const PointData &point1In, const PointData &point2In)
const MatrixRef< const Matrix2Dyn > m_p
#define ApproxMVBB_DEFINE_POINTS_CONFIG_TYPES
bool leftTurn(const VecT1 &a, const VecT2 &b, const VecT3 &c)
#define ApproxMVBB_MSGLOG_L2(message)
Definition: LogDefines.hpp:35
Eigen::Matrix< Scalar, 2, 1 > Vector2
Vector2 intersectLines(const VecT1 &p1, PREC ang1, const VecT2 &p2, PREC ang2, PREC eps=1e-10)
Eigen::Matrix< Scalar, 3, 1 > Vector3
#define ApproxMVBB_STATIC_ASSERTM(B, COMMENT)
auto estimateDiameter(const MatrixBase< Derived > &points, const PREC epsilon, std::size_t seed=RandomGenerators::defaultSeed) -> std::pair< VectorStat< Dimension >, VectorStat< Dimension > >
#define ApproxMVBB_DEFINE_MATRIX_TYPES
Definition: TypeDefs.hpp:26
PREC getAngle(const VecT1 &a, const VecT2 &b)
ApproxMVBB_DEFINE_MATRIX_TYPES ApproxMVBB_DEFINE_POINTS_CONFIG_TYPES void applyRandomRotTrans(MatrixBase< Derived > &points, Gen &g)
int collinearAreOrderedAlongLine(const VecT1 &a, const VecT2 &b, const VecT3 &c)


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Mon Jun 10 2019 12:38:08