Cylinder.cpp
Go to the documentation of this file.
1 #include "Cylinder.h"
2 #include "LevMarFitting.h"
3 #include <MiscLib/Performance.h>
4 #include <GfxTL/VectorXD.h>
5 #include "LevMarFitting.h"
6 #include "LevMarLSWeight.h"
8 #include <GfxTL/Mean.h>
9 #ifdef DOPARALLEL
10 #include <omp.h>
11 #endif
12 
14  : std::runtime_error("Parallel normals")
15 {}
16 
18  : m_angularRotatedRadians(0)
19 {}
20 
21 Cylinder::Cylinder(const Vec3f& axisDir, const Vec3f& axisPos, float radius)
22  : m_angularRotatedRadians(0)
23 {
24  Init(axisDir, axisPos, radius);
25 }
26 
27 Cylinder::Cylinder(const Vec3f& pointA, const Vec3f& pointB,
28  const Vec3f& normalA, const Vec3f& normalB)
29  : m_angularRotatedRadians(0)
30 {
31  if (!Init(pointA, pointB, normalA, normalB))
32  {
33  throw ParallelNormalsError();
34  }
35 }
36 
38 {
39  if (samples.size() < 4)
40  {
41  return false;
42  }
43  // estimate axis from all pairs
44  m_axisDir = Vec3f(0, 0, 0);
45  size_t c = samples.size() / 2;
46  size_t axisCount = 0;
47  m_axisDir = samples[0 + c].cross(samples[1 + c]);
48  if (m_axisDir.normalize() < 1e-3)
49  {
50  return false;
51  }
52  m_axisPos = Vec3f(0, 0, 0);
53  m_radius = 0;
54  // project first normal into plane
55  float l = m_axisDir.dot(samples[0 + c]);
56  Vec3f xdir = samples[0 + c] - l * m_axisDir;
57  xdir.normalize();
58  Vec3f ydir = m_axisDir.cross(xdir);
59  ydir.normalize();
60  // xdir is the x axis in the plane (y = 0) samples[0] is the origin
61  float lineBnx = ydir.dot(samples[1 + c]);
62  if (abs(lineBnx) < 1e-6)
63  {
64  return false;
65  }
66  float lineBny = -xdir.dot(samples[1 + c]);
67  // origin of lineB
68  Vec3f originB = samples[1] - samples[0];
69  float lineBOx = xdir.dot(originB);
70  float lineBOy = ydir.dot(originB);
71  float lineBd = lineBnx * lineBOx + lineBny * lineBOy;
72  // lineB in the plane complete
73  // point of intersection is y = 0 and x = lineBd / lineBnx
74  float radius = lineBd / lineBnx;
75  m_axisPos += samples[0] + radius * xdir;
76  m_radius += abs(radius);
77  m_radius += std::sqrt((radius - lineBOx) * (radius - lineBOx) + lineBOy * lineBOy);
78  m_radius /= 2;
79  if (m_radius > 1e6)
80  {
81  return false;
82  }
83 
84  // find point on axis closest to origin
85  float lambda = m_axisDir.dot(-m_axisPos);
86  m_axisPos = m_axisPos + lambda * m_axisDir;
87 
88  m_hcs.FromNormal(m_axisDir);
89  m_angularRotatedRadians = 0;
90  return true;
91 }
92 
94 {
95  if (samples.size() < 4)
96  {
97  return false;
98  }
99  // estimate axis from covariance of normal vectors
101  size_t c = samples.size() / 2;
102  for (size_t i = c; i < samples.size(); ++i)
103  {
104  normals.push_back(GfxTL::Vector3Df(samples[i]));
105  normals.push_back(GfxTL::Vector3Df(-samples[i]));
106  }
107  GfxTL::MatrixXX< 3, 3, float > cov, eigenVectors;
108  GfxTL::Vector3Df eigenValues;
110  normals.begin(), normals.end(), &cov);
111  GfxTL::Jacobi(cov, &eigenValues, &eigenVectors);
112  // find the minimal eigenvalue and corresponding vector
113  float minEigVal = eigenValues[0];
114  unsigned int minEigIdx = 0;
115  for (unsigned int i = 1; i < 3; ++i)
116  if (eigenValues[i] < minEigVal)
117  {
118  minEigVal = eigenValues[i];
119  minEigIdx = i;
120  }
121  m_axisDir = Vec3f(eigenVectors[minEigIdx]);
122  // get a point on the axis from all pairs
123  m_axisPos = Vec3f(0, 0, 0);
124  m_radius = 0;
125  size_t pointCount = 0;
126  size_t pairCount = 0;
127  for (size_t i = 0; i < c - 1; ++i)
128  for (size_t j = i + 1; j < c; ++j)
129  {
130  // project first normal into plane
131  float l = m_axisDir.dot(samples[i + c]);
132  Vec3f xdir = samples[i + c] - l * m_axisDir;
133  xdir.normalize();
134  Vec3f ydir = m_axisDir.cross(xdir);
135  ydir.normalize();
136  // xdir is the x axis in the plane (y = 0) samples[i] is the origin
137  float lineBnx = ydir.dot(samples[j + c]);
138  if (abs(lineBnx) < .05f)
139  {
140  continue;
141  }
142  float lineBny = -xdir.dot(samples[j + c]);
143  // origin of lineB
144  Vec3f originB = samples[j] - samples[i];
145  float lineBOx = xdir.dot(originB);
146  float lineBOy = ydir.dot(originB);
147  float lineBd = lineBnx * lineBOx + lineBny * lineBOy;
148  // lineB in the plane complete
149  // point of intersection is y = 0 and x = lineBd / lineBnx
150  float radius = lineBd / lineBnx;
151  m_axisPos += samples[i] + radius * xdir;
152  m_radius += abs(radius);
153  m_radius += std::sqrt((radius - lineBOx) * (radius - lineBOx) + lineBOy * lineBOy);
154  ++pointCount;
155  }
156  if (!pointCount)
157  {
158  return false;
159  }
160  m_axisPos /= pointCount;
161  m_radius /= pointCount * 2;
162  if (m_radius > 1e6)
163  {
164  return false;
165  }
166 
167  // find point on axis closest to origin
168  float lambda = m_axisDir.dot(-m_axisPos);
169  m_axisPos = m_axisPos + lambda * m_axisDir;
170 
171  m_hcs.FromNormal(m_axisDir);
172  m_angularRotatedRadians = 0;
173  return true;
174 }
175 
176 bool Cylinder::Init(const Vec3f& axisDir, const Vec3f& axisPos, float radius)
177 {
178  m_axisDir = axisDir;
179  m_axisPos = axisPos;
180  m_radius = radius;
181  m_hcs.FromNormal(m_axisDir);
182  m_angularRotatedRadians = 0;
183  return true;
184 }
185 
186 bool Cylinder::Init(const Vec3f& pointA, const Vec3f& pointB,
187  const Vec3f& normalA, const Vec3f& normalB)
188 {
189  if (normalA.dot(normalB) > 0.9998477)
190  {
191  return false;
192  }
193  m_axisDir = normalA.cross(normalB);
194  if (m_axisDir.normalize() < 1e-6)
195  {
196  return false;
197  }
198  // normalA is the x axis in the plane (y = 0) pointA is the origin
199  Vec3f planeY = normalA.cross(m_axisDir); // planeX = normalA
200  planeY.normalize();
201  float lineBnx = planeY.dot(normalB);
202  float lineBny = -normalA.dot(normalB);
203  // origin of lineB
204  Vec3f originB = pointB - pointA;
205  float lineBOx = normalA.dot(originB);
206  float lineBOy = planeY.dot(originB);
207  float lineBd = lineBnx * lineBOx + lineBny * lineBOy;
208  // lineB in the plane complete
209  // point of intersection is y = 0 and x = lineBd / lineBnx
210  m_radius = lineBd / lineBnx;
211  m_axisPos = pointA + m_radius * normalA;
212  m_radius = abs(m_radius);
213  if (m_radius > 1e6)
214  {
215  return false;
216  }
217  m_hcs.FromNormal(m_axisDir);
218  m_angularRotatedRadians = 0;
219  return true;
220 }
221 
222 bool Cylinder::Init(bool binary, std::istream* i)
223 {
224  float rotate = 0;
225  if (binary)
226  {
227  i->read((char*)&m_axisDir, sizeof(m_axisDir));
228  i->read((char*)&m_axisPos, sizeof(m_axisPos));
229  i->read((char*)&m_radius, sizeof(m_radius));
230  i->read((char*)&rotate, sizeof(rotate));
231  }
232  else
233  {
234  for (size_t j = 0; j < 3; ++j)
235  {
236  (*i) >> m_axisDir[j];
237  }
238  for (size_t j = 0; j < 3; ++j)
239  {
240  (*i) >> m_axisPos[j];
241  }
242  (*i) >> m_radius;
243  (*i) >> rotate;
244  }
245  m_hcs.FromNormal(m_axisDir);
246  m_angularRotatedRadians = 0;
247  RotateAngularDirection(rotate);
248  return true;
249 }
250 
251 void Cylinder::Init(FILE* i)
252 {
253  float rotate = 0;
254  fread(&m_axisDir, sizeof(m_axisDir), 1, i);
255  fread(&m_axisPos, sizeof(m_axisPos), 1, i);
256  fread(&m_radius, sizeof(m_radius), 1, i);
257  fread(&rotate, sizeof(rotate), 1, i);
258  m_hcs.FromNormal(m_axisDir);
259  m_angularRotatedRadians = 0;
260  RotateAngularDirection(rotate);
261 }
262 
263 void Cylinder::Init(float* array)
264 {
265  float rotate = 0;
266  for (int i = 0; i < 3; i++)
267  {
268  m_axisDir[i] = array[i];
269  m_axisPos[i] = array[i + 3];
270  }
271  m_radius = array[6];
272  rotate = array[7];
273 
274  m_hcs.FromNormal(m_axisDir);
275  m_angularRotatedRadians = 0;
276  RotateAngularDirection(rotate);
277 }
278 
279 void Cylinder::Project(const Vec3f& p, Vec3f* pp) const
280 {
281  Vec3f diff = m_axisPos - p;
282  float lambda = m_axisDir.dot(diff);
283  *pp = (diff - lambda * m_axisDir);
284  float l = pp->length();
285  *pp *= (l - m_radius) / l;
286  *pp += p;
287 }
288 
290  std::pair< float, float >* param) const
291 {
292  Vec3f diff = p - m_axisPos;
293  param->first = m_axisDir.dot(diff);
294  float planex = diff.dot(m_hcs[0].Data());
295  float planey = diff.dot(m_hcs[1].Data());
296  float l = planex * planex + planey * planey;
297  if (l > 0)
298  {
299  planex /= l;
300  planey /= l;
301  }
302  param->second = std::atan2(planey, planex);
303  if (param->second < 0)
304  {
305  param->second += float(2 * M_PI);
306  }
307 }
308 
309 float Cylinder::Radius() const
310 {
311  return m_radius;
312 }
313 
314 float& Cylinder::Radius()
315 {
316  return m_radius;
317 }
318 
320 {
321  return m_axisDir;
322 }
323 
325 {
326  return m_axisDir;
327 }
328 
330 {
331  return m_axisPos;
332 }
333 
335 {
336  return m_axisPos;
337 }
338 
340 {
341  return Vec3f(m_hcs[0].Data());
342 }
343 
345 {
347  q.RotationRad(radians, m_axisDir[0], m_axisDir[1], m_axisDir[2]);
348  Vec3f vvec;
349  q.Rotate(AngularDirection(), &vvec);
350  m_hcs[0] = GfxTL::Vector3Df(vvec);
351  m_hcs[1] = GfxTL::Vector3Df(m_axisDir.cross(Vec3f(m_hcs[0].Data())));
352  m_angularRotatedRadians += radians;
353 }
354 
355 float CylinderDistance(const float* param, const float* x)
356 {
357  Vec3f s;
358  for (size_t i = 0; i < 3; ++i)
359  {
360  s[i] = x[i] - param[i];
361  }
362  float u = param[5] * s[1] - param[4] * s[2];
363  u *= u;
364  float v = param[3] * s[2] - param[5] * s[0];
365  u += v * v;
366  v = param[4] * s[0] - param[3] * s[1];
367  u += v * v;
368  return std::sqrt(u) - param[6];
369 }
370 
371 void CylinderDistanceDerivatives(const float* param, const float* x,
372  float* gradient)
373 {
374  Vec3f s;
375  for (size_t i = 0; i < 3; ++i)
376  {
377  s[i] = x[i] - param[i];
378  }
379  float g = s[0] * x[0] + s[1] * x[1] + s[2] * x[2];
380  float f = param[5] * s[1] - param[4] * s[2];
381  f *= f;
382  float v = param[3] * s[2] - param[5] * s[0];
383  f += v * v;
384  v = param[4] * s[0] - param[3] * s[1];
385  f += v * v;
386  f = std::sqrt(f);
387  if (f < 1e-6)
388  {
389  gradient[0] = std::sqrt(1 - param[3] * param[3]);
390  gradient[1] = std::sqrt(1 - param[4] * param[4]);
391  gradient[2] = std::sqrt(1 - param[5] * param[5]);
392  }
393  else
394  {
395  gradient[0] = (param[3] * g - s[0]) / f;
396  gradient[1] = (param[4] * g - s[1]) / f;
397  gradient[2] = (param[5] * g - s[2]) / f;
398  }
399  gradient[3] = g * gradient[0];
400  gradient[4] = g * gradient[1];
401  gradient[5] = g * gradient[2];
402  gradient[6] = -1;
403 }
404 
405 void NormalizeCylinderParams(float* param)
406 {
407  float l = std::sqrt(param[3] * param[3] + param[4] * param[4]
408  + param[5] * param[5]);
409  for (unsigned int i = 3; i < 6; ++i)
410  {
411  param[i] /= l;
412  }
413  // find point on axis closest to origin
414  float lambda = -(param[0] * param[3] + param[1] * param[4] +
415  param[2] * param[5]);
416  for (unsigned int i = 0; i < 3; ++i)
417  {
418  param[i] = param[i] + lambda * param[i + 3];
419  }
420 }
421 
425 {
426  bool retVal = LeastSquaresFit(GfxTL::IndexIterate(begin, pc.begin()),
427  GfxTL::IndexIterate(end, pc.begin()));
428  return retVal;
429 }
430 
432  const MiscLib::Vector< float >& weights, Cylinder* ic)
433 {
434  Vec3f axisPos(0, 0, 0);
435  Vec3f axisDir(0, 0, 0);
436  float r = 0;
437  for (size_t i = 0; i < cylinders.size(); ++i)
438  {
439  axisPos += weights[i] * cylinders[i].AxisPosition();
440  axisDir += weights[i] * cylinders[i].AxisDirection();
441  r += weights[i] * cylinders[i].Radius();
442  }
443  axisDir.normalize();
444  return ic->Init(axisDir, axisPos, r);
445 }
446 
447 void Cylinder::Serialize(bool binary, std::ostream* o) const
448 {
449  if (binary)
450  {
451  o->write((const char*)&m_axisDir, sizeof(m_axisDir));
452  o->write((const char*)&m_axisPos, sizeof(m_axisPos));
453  o->write((const char*)&m_radius, sizeof(m_radius));
454  o->write((const char*)&m_angularRotatedRadians,
455  sizeof(m_angularRotatedRadians));
456  }
457  else
458  {
459  (*o) << m_axisDir[0] << " " << m_axisDir[1] << " " << m_axisDir[2] << " "
460  << m_axisPos[0] << " " << m_axisPos[1] << " " << m_axisPos[2] << " "
461  << m_radius << " " << m_angularRotatedRadians << " ";
462  }
463 }
464 
466 {
467  return sizeof(Vec3f)
468  + sizeof(Vec3f)
469  + sizeof(float)
470  + sizeof(float);
471 }
472 
473 void Cylinder::Serialize(float* array) const
474 {
475 
476  for (int i = 0; i < 3; i++)
477  {
478  array[i] = m_axisDir[i];
479  array[i + 3] = m_axisPos[i];
480  }
481  array[6] = m_radius;
482  array[7] = m_angularRotatedRadians;
483 }
484 
486 {
487  return 8;
488 }
489 
490 void Cylinder::Serialize(FILE* o) const
491 {
492  fwrite(&m_axisDir, sizeof(m_axisDir), 1, o);
493  fwrite(&m_axisPos, sizeof(m_axisPos), 1, o);
494  fwrite(&m_radius, sizeof(m_radius), 1, o);
495  fwrite(&m_angularRotatedRadians,
496  sizeof(m_angularRotatedRadians), 1, o);
497 }
498 
499 void Cylinder::Transform(float scale, const Vec3f& translate)
500 {
501  m_axisPos *= scale;
502  m_axisPos += translate;
503  m_radius *= scale;
504 }
505 
507  const GfxTL::Vector3Df& trans)
508 {
509  m_axisDir = Vec3f((rot * GfxTL::Vector3Df(m_axisDir)).Data());
510  m_axisPos = Vec3f((rot * GfxTL::Vector3Df(m_axisPos) + trans).Data());
511  m_hcs[0] = rot * m_hcs[0];
512  m_hcs[1] = rot * m_hcs[1];
513 }
Cylinder::Radius
float Radius() const
Definition: Cylinder.cpp:309
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:662
GfxTL::VectorXD
Definition: MatrixXX.h:21
cyberglove_with_calib_22dof.ic
ic
Definition: cyberglove_with_calib_22dof.py:22
Cylinder.h
Cylinder::Interpolate
static bool Interpolate(const MiscLib::Vector< Cylinder > &cylinders, const MiscLib::Vector< float > &weights, Cylinder *ic)
Definition: Cylinder.cpp:431
MiscLib::Vector::begin
T * begin()
Definition: Vector.h:460
Cylinder::SerializedFloatSize
static size_t SerializedFloatSize()
Definition: Cylinder.cpp:485
Mean.h
Vec3f::normalize
float normalize()
Definition: basic.h:125
Vec3f
Definition: basic.h:16
MiscLib::Vector::push_back
void push_back(const T &v)
Definition: Vector.h:346
Cylinder::SerializedSize
static size_t SerializedSize()
Definition: Cylinder.cpp:465
Performance.h
Vec3f::cross
Vec3f cross(const Vec3f &v) const
Definition: basic.h:107
Cylinder::RotateAngularDirection
void RotateAngularDirection(float radians)
Definition: Cylinder.cpp:344
Cylinder::Serialize
void Serialize(bool binary, std::ostream *o) const
Definition: Cylinder.cpp:447
Cylinder::Cylinder
Cylinder()
Definition: Cylinder.cpp:17
Cylinder::AxisPosition
const Vec3f & AxisPosition() const
Definition: Cylinder.cpp:329
Cylinder::Parameters
void Parameters(const Vec3f &p, std::pair< float, float > *param) const
Definition: Cylinder.cpp:289
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
Vec3f::length
float length() const
Definition: basic.h:120
GfxTL::Quaternion
Definition: VectorXD.h:707
GfxTL::MatrixXX
Definition: MatrixXX.h:25
MiscLib::Vector
Definition: Vector.h:19
VectorXD.h
LevMarFitting.h
Cylinder::ParallelNormalsError::ParallelNormalsError
ParallelNormalsError()
Definition: Cylinder.cpp:13
GfxTL::Vector3Df
VectorXD< 3, float > Vector3Df
Definition: VectorXD.h:676
Cylinder::AxisDirection
const Vec3f & AxisDirection() const
Definition: Cylinder.cpp:319
MiscLib::Vector::size
size_type size() const
Definition: Vector.h:212
armarx::abs
std::vector< T > abs(const std::vector< T > &v)
Definition: VectorHelpers.h:253
M_PI
#define M_PI
Definition: MathTools.h:17
Cylinder::LeastSquaresFit
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition: Cylinder.cpp:422
Cylinder::Project
void Project(const Vec3f &p, Vec3f *pp) const
Definition: Cylinder.cpp:279
Cylinder::InitAverage
bool InitAverage(const MiscLib::Vector< Vec3f > &samples)
Definition: Cylinder.cpp:93
GfxTL::Jacobi
bool Jacobi(const MatrixXX< N, N, T > &m, VectorXD< N, T > *d, MatrixXX< N, N, T > *v, int *nrot=NULL)
Definition: Jacobi.h:22
CylinderDistanceDerivatives
void CylinderDistanceDerivatives(const float *param, const float *x, float *gradient)
Definition: Cylinder.cpp:371
GfxTL::IndexIterate
IndexedIterator< IndexIteratorT, IteratorT > IndexIterate(IndexIteratorT idxIt, IteratorT it)
Definition: IndexedIterator.h:154
MiscLib::Vector::end
T * end()
Definition: Vector.h:470
Cylinder::AngularDirection
const Vec3f AngularDirection() const
Definition: Cylinder.cpp:339
q
#define q
Cylinder::Transform
void Transform(float scale, const Vec3f &translate)
Definition: Cylinder.cpp:499
IndexedIterator.h
CylinderDistance
float CylinderDistance(const float *param, const float *x)
Definition: Cylinder.cpp:355
PointCloud
Definition: PointCloud.h:69
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
Cylinder::ParallelNormalsError
Definition: Cylinder.h:23
Vec3f::dot
float dot(const Vec3f &v) const
Definition: basic.h:92
float
#define float
Definition: 16_Level.h:22
std
Definition: Application.h:66
LevMarLSWeight.h
GfxTL::CovarianceMatrix
void CovarianceMatrix(const PointT &center, PointsForwardIt begin, PointsForwardIt end, WeightsForwardIt weights, MatrixT *matrix)
Definition: Covariance.h:162
GfxTL::Vec3f
VectorXD< 3, float > Vec3f
Definition: VectorXD.h:691
pc
Introduction Thank you for taking interest in our work and downloading this software This library implements the algorithm described in the paper R R R Klein Efficient RANSAC for Point Cloud Shape in Computer Graphics Blackwell June If you use this software you should cite the aforementioned paper in any resulting publication Please send comments or bug reports to Ruwen Roland BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE Example usage This section shows how to use the library to detect the shapes in a point cloud PointCloud pc
Definition: ReadMe.txt:68
Cylinder
Definition: Cylinder.h:20
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
NormalizeCylinderParams
void NormalizeCylinderParams(float *param)
Definition: Cylinder.cpp:405
Cylinder::Init
bool Init(const MiscLib::Vector< Vec3f > &samples)
Definition: Cylinder.cpp:37