MinAreaRectangle.cpp
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 
11 
12 namespace ApproxMVBB{
14  // Compute minimum area rectangle
15 
16  // Clear minBox;
17  m_minBox.reset();
18 
19  // If no points return early!
20  if(m_p.cols() == 0) {
21  return;
22  }
23 
24  // Generate Convex Hull
25  m_convh.compute();
26  ApproxMVBB_ASSERTMSG(m_convh.verifyHull(), "Convex hull not ok!")
27 
28  // Compute Rectangle
29  // computes p,u,v of box (not normalized)
31 
32  // Final adjustments (u and v are getting normalized)
34 }
35 
37 
38  // Copy Points;
40  unsigned int nPoints = m_hullIdx.size();
41 
42  //std::cout << "Convex hull points:" << nPoints << std::endl;
43 
44  // The below code works for points >= 2
45  // Anyway catch the cases n=1 and 2 and return early!
46  if(nPoints == 0) {
47  return;
48  } else if( nPoints == 1) {
49  m_minBox.m_p = m_p.col(m_hullIdx[0]);
50  m_minBox.m_u.setZero();
51  m_minBox.m_v.setZero();
52  return;
53  } else if(nPoints == 2) {
54  m_minBox.m_p = m_p.col(m_hullIdx[0]);
55  m_minBox.m_u = m_p.col(m_hullIdx[1]) - m_p.col(m_hullIdx[0]);
56  m_minBox.m_v.setZero();
57  return;
58  }
59 
60 
61  // Performing Rotating Calipers method
62  // 1. find the vertices with the minimum and maximum x an y coordinates.
63  // These vertices (points) will be denoted by {PI, PJ, PK, PL}
64  // 2. construct CALL and CALJ as the first set of calipers parallel to the x-axis,
65  // and CALI and CALK as the second set of calipers parallel to the y-axis
66  // 3. create for every CALX a next caliper,
67  // NEXT_CALX, based on the next point in the convex hull and calculate the tangent of CALX and it's NEXT_CALX
68  // 4. get the smallest positive tangent between all CALX and NEXT_CALX and rotate every caliper by that smallest gradient
69  // 5. repeat step 3 and 4 untill the calipers have turned more then 90 degrees
70 
71  // We implement this algorithm a bit differently:
72  // 1. Compute all angles of all edges angle[i] is angle of edge p[i],p[i+1].
73  // 2. Rotatate the first caliper A from edge to edge.
74  // 3. Determine all new angles for B,C,D such that it forms a box (rotation of pi from angle of caliper A)
75  // 4. Determine for each caliper I the location (the corresponding vertex index) where the
76  // caliper I forms a tangent (starting from the currend index).
77  // 5. Determine the box by intersecting the calipers.
78  // 6. Compare to area to minimum and return to 2.
79 
80  // Calcualte all edge angles
81 
82  m_angles.resize(nPoints);
83  for(unsigned int i=0; i<nPoints; ++i) {
85  m_p.col(m_hullIdx[(i+1) % nPoints])
86  );
87  //std::cout << "angle: " << m_angles[i] << std::endl;
88  }
89 
90  // 2. Construct 4 Calipers
91  Caliper calipers[4];
92  // Set A
93  calipers[0].m_idx = 0;
94  calipers[0].m_ptIdx = m_hullIdx[0];
95  // Init A,B,C,D
96  updateCalipers(m_angles[0],calipers);
97 
98  Box2d box;
99  // Init minBox
100  getBox(calipers,m_minBox);
101 
102  // Rotate calipers over all edges and take minimum box
103  for(unsigned int i=1; i<nPoints; ++i) {
104 
105  updateCalipers(m_angles[i],calipers);
106  // Get Box from Calipers
107  getBox(calipers,box);
108 
109  if(box.m_area < m_minBox.m_area) {
110 
111  m_minBox = box;
112  }
113  }
114 }
115 
116 // determine the vertex v for which the edge angle is greater than c.m_currAngle
117 // the find algroithm starts at c.m_idx
119 
120  PREC matchAngle = c.m_currAngle; // between 0-2pi
121  //std::cout << "Match Angle: " << matchAngle << std::endl;
122 
123  unsigned int currIdx = c.m_idx;
124 
125  PREC currAngle = m_angles[currIdx]; // all between 0-2pi
126  PREC nextAngle;
127 
128  unsigned int nPoints = m_hullIdx.size();
129  bool found = false;
130  unsigned int i = 0;
131  while(!found && i < nPoints) {
132 
133  currIdx = (currIdx + 1) % nPoints;
134  // std::cout << "c: " << currIdx << std::endl;
135  nextAngle = m_angles[currIdx];
136  //std::cout << "diff: " << std::abs(currAngle-nextAngle) << std::endl;
137  // curr next
138  // if we are not at the boundary [ ..., 45 degree, 50 degree , ....]
139  // and in
140  if( nextAngle > currAngle ) {
141  //std::cout << " greater" <<std::endl;
142  found = (currAngle < matchAngle && matchAngle <= nextAngle);
143  } else {
144  //std::cout << " boundary" <<std::endl;
145  // curr next
146  // if we are at the boundary [ ..., 359 degree] [ 5 degree , .... ]
147  // skip this if we have an angle difference |curr -next| < eps
148  // this might happen due to floating point nonsense
149  found = (std::abs(currAngle-nextAngle)>1e-10) && (currAngle < matchAngle || matchAngle <= nextAngle);
150  }
151 
152  currAngle = nextAngle;
153  ++i;
154  }
155 
156  if(found) {
157  c.m_idx = currIdx;
158  c.m_ptIdx = m_hullIdx[currIdx];
159  //std::cout << "caliper idx:" << currIdx << std::endl;
160  } else {
161  std::stringstream ss;
162  for(auto & a : m_angles){ ss << a <<",";}
163  ApproxMVBB_ERRORMSG("Could not find vertex with angle greater than: "
164  << matchAngle << "in angles: " << ss.str());
165  }
166 }
167 
168 void MinAreaRectangle::getBox(Caliper (&c)[4], Box2d & box) {
169  using namespace PointFunctions;
170  // Intersect Caliper A with B,
171  box.m_u = intersectLines( m_p.col(c[0].m_ptIdx), c[0].m_currAngle,
172  m_p.col(c[1].m_ptIdx), c[1].m_currAngle);
173  // Intersect Caliper D with C,
174  box.m_v = intersectLines( m_p.col(c[3].m_ptIdx), c[3].m_currAngle,
175  m_p.col(c[2].m_ptIdx), c[2].m_currAngle);
176 
177  // Intersect Caliper A with D,
178  box.m_p = intersectLines( m_p.col(c[0].m_ptIdx), c[0].m_currAngle,
179  m_p.col(c[3].m_ptIdx), c[3].m_currAngle);
180 
181  box.m_u -= box.m_p; //(p1-p0)
182  box.m_v -= box.m_p; //(p2-p0)
183  box.m_area = box.m_u.norm()*box.m_v.norm();
184 
185  }
186 
187 }
#define ApproxMVBB_ASSERTMSG(condition, message)
An Assert Macro to use within C++ code.
Vector2 m_p
first corner x = m_p0 + m_u*m_uL * u + m_v*m_vL * v , u,v in [0,1]
These are some container definitions.
#define ApproxMVBB_ERRORMSG(message)
Vector2 m_u
vector of first side (x-Axis) (normalized)
void updateCalipers(PREC edgeAngle, Caliper(&c)[4])
void getBox(Caliper(&c)[4], Box2d &box)
Vector2 intersectLines(const VecT1 &p1, PREC ang1, const VecT2 &p2, PREC ang2, PREC eps=1e-10)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void reset()
std::vector< unsigned int > & getIndices()
const MatrixRef< const Matrix2Dyn > m_p
Vector2 m_v
vector of second side (y-Axis) (normalized)
PREC getAngle(const VecT1 &a, const VecT2 &b)
std::vector< unsigned int > m_hullIdx


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