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