Cone.h
Go to the documentation of this file.
1 #ifndef CONE_HEADER
2 #define CONE_HEADER
3 #ifdef DOPARALLEL
4 #include <omp.h>
5 #endif
6 #include "basic.h"
7 #include "PointCloud.h"
9 #include <stdexcept>
10 #include <ostream>
11 #include <istream>
12 #include <stdio.h>
13 #include <MiscLib/NoShrinkVector.h>
14 #include "LevMarLSWeight.h"
15 #include "LevMarFitting.h"
16 
17 #ifndef DLL_LINKAGE
18 #define DLL_LINKAGE
19 #endif
20 
21 // This implements a one sided cone!
23 {
24 public:
26  : public std::runtime_error
27  {
29  : std::runtime_error("Parallel planes in cone construction")
30  {}
31  };
32  enum { RequiredSamples = 3 };
33  Cone();
34  Cone(const Vec3f& center, const Vec3f& axisDir, float angle);
35  Cone(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3,
36  const Vec3f& n1, const Vec3f& n2, const Vec3f& n3);
37  bool Init(const MiscLib::Vector< Vec3f >& samples);
38  bool InitAverage(const MiscLib::Vector< Vec3f >& samples);
39  bool Init(const Vec3f& center, const Vec3f& axisDir, float angle);
40  bool Init(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3,
41  const Vec3f& n1, const Vec3f& n2, const Vec3f& n3);
42  bool Init(bool binary, std::istream* i);
43  void Init(FILE* i);
44  void Init(float* array);
45  inline float Distance(const Vec3f& p) const;
46  inline void Normal(const Vec3f& p, Vec3f* n) const;
47  inline float DistanceAndNormal(const Vec3f& p, Vec3f* n) const;
48  inline float SignedDistance(const Vec3f& p) const;
49  inline float SignedDistanceAndNormal(const Vec3f& p, Vec3f* n) const;
50  void Project(const Vec3f& p, Vec3f* pp) const;
51  // Paramterizes into (length, angle)
52  void Parameters(const Vec3f& p,
53  std::pair< float, float >* param) const;
54  inline float Height(const Vec3f& p) const;
55  inline float Angle() const;
56  inline const Vec3f& Center() const;
57  inline const Vec3f& AxisDirection() const;
59  {
60  return m_axisDir;
61  }
62  inline const Vec3f AngularDirection() const;
63  //void AngularDirection(const Vec3f &angular);
64  void RotateAngularDirection(float radians);
65  inline float RadiusAtLength(float length) const;
66  bool LeastSquaresFit(const PointCloud& pc,
69  template< class IteratorT >
70  bool LeastSquaresFit(IteratorT begin, IteratorT end);
71  bool Fit(const PointCloud& pc,
74  {
75  return LeastSquaresFit(pc, begin, end);
76  }
77  static bool Interpolate(const MiscLib::Vector< Cone >& cones,
78  const MiscLib::Vector< float >& weights, Cone* ic);
79  void Serialize(bool binary, std::ostream* o) const;
80  static size_t SerializedSize();
81  void Serialize(FILE* o) const;
82  void Serialize(float* array) const;
83  static size_t SerializedFloatSize();
84  void Transform(float scale, const Vec3f& translate);
85  void Transform(const GfxTL::MatrixXX< 3, 3, float >& rot,
86  const GfxTL::Vector3Df& trans);
87  inline unsigned int Intersect(const Vec3f& p, const Vec3f& r,
88  float lambda[2], Vec3f interPts[2]) const;
89 
90 private:
91  template< class WeightT >
92  class LevMarCone
93  : public WeightT
94  {
95  public:
96  enum { NumParams = 7 };
97  typedef float ScalarType;
98 
99  template< class IteratorT >
100  ScalarType Chi(const ScalarType* params, IteratorT begin, IteratorT end,
101  ScalarType* values, ScalarType* temp) const
102  {
103  ScalarType chi = 0;
104  ScalarType cosPhi = std::cos(params[6]);
105  ScalarType sinPhi = std::sin(params[6]);
106  int size = end - begin;
107  #pragma omp parallel for schedule(static) reduction(+:chi)
108  for (int idx = 0; idx < size; ++idx)
109  {
110  Vec3f s;
111  for (unsigned int j = 0; j < 3; ++j)
112  {
113  s[j] = begin[idx][j] - params[j];
114  }
115  ScalarType g = abs(s[0] * params[3] + s[1] * params[4] + s[2] * params[5]);
116  ScalarType f = s.sqrLength() - (g * g);
117  if (f <= 0)
118  {
119  f = 0;
120  }
121  else
122  {
123  f = std::sqrt(f);
124  }
125  temp[idx] = f;
126  chi += (values[idx] = WeightT::Weigh(cosPhi * f - sinPhi * g))
127  * values[idx];
128  }
129  return chi;
130  }
131 
132  template< class IteratorT >
133  void Derivatives(const ScalarType* params, IteratorT begin, IteratorT end,
134  const ScalarType* values, const ScalarType* temp, ScalarType* matrix) const
135  {
136  ScalarType sinPhi = -std::sin(params[6]);
137  ScalarType cosPhi = std::cos(params[6]);
138  int size = end - begin;
139  #pragma omp parallel for schedule(static)
140  for (int idx = 0; idx < size; ++idx)
141  {
142  Vec3f s;
143  for (unsigned int j = 0; j < 3; ++j)
144  {
145  s[j] = begin[idx][j] - params[j];
146  }
147  ScalarType g = abs(s[0] * params[3] + s[1] * params[4] + s[2] * params[5]);
148  ScalarType ggradient[6];
149  for (unsigned int j = 0; j < 3; ++j)
150  {
151  ggradient[j] = -params[j + 3];
152  }
153  for (unsigned int j = 0; j < 3; ++j)
154  {
155  ggradient[j + 3] = s[j] - params[j + 3] * g;
156  }
157  ScalarType fgradient[6];
158  if (temp[idx] < 1e-6)
159  {
160  fgradient[0] = std::sqrt(1 - params[3] * params[3]);
161  fgradient[1] = std::sqrt(1 - params[4] * params[4]);
162  fgradient[2] = std::sqrt(1 - params[5] * params[5]);
163  }
164  else
165  {
166  fgradient[0] = (params[3] * g - s[0]) / temp[idx];
167  fgradient[1] = (params[4] * g - s[1]) / temp[idx];
168  fgradient[2] = (params[5] * g - s[2]) / temp[idx];
169  }
170  fgradient[3] = g * fgradient[0];
171  fgradient[4] = g * fgradient[1];
172  fgradient[5] = g * fgradient[2];
173  for (unsigned int j = 0; j < 6; ++j)
174  matrix[idx * NumParams + j] =
175  cosPhi * fgradient[j] + sinPhi * ggradient[j];
176  matrix[idx * NumParams + 6] = temp[idx] * sinPhi - g * cosPhi;
177  WeightT::template DerivWeigh< NumParams >(cosPhi * temp[idx] + sinPhi * g,
178  matrix + idx * NumParams);
179  }
180  }
181 
182  void Normalize(float* params) const
183  {
184  // normalize direction
185  ScalarType l = std::sqrt(params[3] * params[3] + params[4] * params[4] +
186  params[5] * params[5]);
187  for (unsigned int i = 3; i < 6; ++i)
188  {
189  params[i] /= l;
190  }
191  // normalize angle
192  params[6] -= std::floor(params[6] / (2 * ScalarType(M_PI))) * (2 * ScalarType(M_PI)); // params[6] %= 2*M_PI
193  if (params[6] > M_PI)
194  {
195  params[6] -= std::floor(params[6] / ScalarType(M_PI)) * ScalarType(M_PI); // params[6] %= M_PI
196  for (unsigned int i = 3; i < 6; ++i)
197  {
198  params[i] *= -1;
199  }
200  }
201  if (params[6] > ScalarType(M_PI) / 2)
202  {
203  params[6] = ScalarType(M_PI) - params[6];
204  }
205  }
206  };
207 
208 private:
209  Vec3f m_center; // this is the apex of the cone
210  Vec3f m_axisDir; // the axis points into the interior of the cone
211  float m_angle; // the opening angle
212  Vec3f m_normal;
213  Vec3f m_normalY; // precomputed normal part
214  float m_n2d[2];
216  float m_angularRotatedRadians;
217 };
218 
219 inline float Cone::Distance(const Vec3f& p) const
220 {
221  // this is for one sided cone!
222  Vec3f s = p - m_center;
223  float g = s.dot(m_axisDir); // distance to plane orhogonal to
224  // axisdir through center
225  // distance to axis
226  float sqrS = s.sqrLength();
227  float f = sqrS - (g * g);
228  if (f <= 0)
229  {
230  f = 0;
231  }
232  else
233  {
234  f = std::sqrt(f);
235  }
236  float da = m_n2d[0] * f;
237  float db = m_n2d[1] * g;
238  if (g < 0 && da - db < 0) // is inside other side of cone -> disallow
239  {
240  return std::sqrt(sqrS);
241  }
242  return abs(da + db);
243 }
244 
245 inline void Cone::Normal(const Vec3f& p, Vec3f* n) const
246 {
247  Vec3f s = p - m_center;
248  Vec3f pln = s.cross(m_axisDir);
249  Vec3f plx = m_axisDir.cross(pln);
250  plx.normalize();
251  // we are not dealing with two-sided cone
252  *n = m_normal[0] * plx + m_normalY;
253 }
254 
255 inline float Cone::DistanceAndNormal(const Vec3f& p, Vec3f* n) const
256 {
257  // this is for one-sided cone !!!
258  Vec3f s = p - m_center;
259  float g = s.dot(m_axisDir); // distance to plane orhogonal to
260  // axisdir through center
261  // distance to axis
262  float sqrS = s.sqrLength();
263  float f = sqrS - (g * g);
264  if (f <= 0)
265  {
266  f = 0;
267  }
268  else
269  {
270  f = std::sqrt(f);
271  }
272  float da = m_n2d[0] * f;
273  float db = m_n2d[1] * g;
274  float dist;
275  if (g < 0 && da - db < 0) // is inside other side of cone -> disallow
276  {
277  dist = std::sqrt(sqrS);
278  }
279  else
280  {
281  dist = abs(da + db);
282  }
283  // need normal
284  Vec3f plx = s - g * m_axisDir;
285  plx.normalize();
286  *n = m_normal[0] * plx + m_normalY;
287  return dist;
288 }
289 
290 inline float Cone::SignedDistance(const Vec3f& p) const
291 {
292  // this is for one sided cone!
293  Vec3f s = p - m_center;
294  float g = s.dot(m_axisDir); // distance to plane orhogonal to
295  // axisdir through center
296  // distance to axis
297  float sqrS = s.sqrLength();
298  float f = sqrS - (g * g);
299  if (f <= 0)
300  {
301  f = 0;
302  }
303  else
304  {
305  f = std::sqrt(f);
306  }
307  float da = m_n2d[0] * f;
308  float db = m_n2d[1] * g;
309  if (g < 0 && da - db < 0) // is inside other side of cone -> disallow
310  {
311  return std::sqrt(sqrS);
312  }
313  return da + db;
314 }
315 
316 inline float Cone::SignedDistanceAndNormal(const Vec3f& p, Vec3f* n) const
317 {
318  // this is for one-sided cone !!!
319  Vec3f s = p - m_center;
320  float g = s.dot(m_axisDir); // distance to plane orhogonal to
321  // axisdir through center
322  // distance to axis
323  float sqrS = s.sqrLength();
324  float f = sqrS - (g * g);
325  if (f <= 0)
326  {
327  f = 0;
328  }
329  else
330  {
331  f = std::sqrt(f);
332  }
333  float da = m_n2d[0] * f;
334  float db = m_n2d[1] * g;
335  float dist;
336  if (g < 0 && da - db < 0) // is inside other side of cone -> disallow
337  {
338  dist = std::sqrt(sqrS);
339  }
340  else
341  {
342  dist = da + db;
343  }
344  // need normal
345  Vec3f plx = s - g * m_axisDir;
346  plx.normalize();
347  *n = m_normal[0] * plx + m_normalY;
348  return dist;
349 }
350 
351 float Cone::Angle() const
352 {
353  return m_angle;
354 }
355 
356 const Vec3f& Cone::Center() const
357 {
358  return m_center;
359 }
360 
362 {
363  return m_axisDir;
364 }
365 
367 {
368  return Vec3f(m_hcs[0].Data());
369 }
370 
371 float Cone::RadiusAtLength(float length) const
372 {
373  return std::sin(m_angle) * abs(length);
374 }
375 
376 float Cone::Height(const Vec3f& p) const
377 {
378  Vec3f s = p - m_center;
379  return m_axisDir.dot(s);
380 }
381 
382 template< class IteratorT >
383 bool Cone::LeastSquaresFit(IteratorT begin, IteratorT end)
384 {
385  float param[7];
386  for (unsigned int i = 0; i < 3; ++i)
387  {
388  param[i] = m_center[i];
389  }
390  for (unsigned int i = 0; i < 3; ++i)
391  {
392  param[i + 3] = m_axisDir[i];
393  }
394  param[6] = m_angle;
395  LevMarCone< LevMarLSWeight > levMarCone;
396  if (!LevMar(begin, end, levMarCone, param))
397  {
398  return false;
399  }
400  if (param[6] < 1e-6 || param[6] > float(M_PI) / 2 - 1e-6)
401  {
402  return false;
403  }
404  for (unsigned int i = 0; i < 3; ++i)
405  {
406  m_center[i] = param[i];
407  }
408  for (unsigned int i = 0; i < 3; ++i)
409  {
410  m_axisDir[i] = param[i + 3];
411  }
412  m_angle = param[6];
413  m_normal = Vec3f(std::cos(-m_angle), std::sin(-m_angle), 0);
414  m_normalY = m_normal[1] * m_axisDir;
415  m_n2d[0] = std::cos(m_angle);
416  m_n2d[1] = -std::sin(m_angle);
417  m_hcs.FromNormal(m_axisDir);
418  m_angularRotatedRadians = 0;
419  // it could be that the axis has flipped during fitting
420  // we need to detect such a case
421  // for this we run over all points and compute the sum
422  // of their respective heights. If that sum is negative
423  // the axis needs to be flipped.
424  float heightSum = 0;
425  intptr_t size = end - begin;
426 #ifndef _WIN64 // for some reason the Microsoft x64 compiler crashes at the next line
427  #pragma omp parallel for schedule(static) reduction(+:heightSum)
428 #endif
429  for (intptr_t i = 0; i < size; ++i)
430  {
431  heightSum += Height(begin[i]);
432  }
433  if (heightSum < 0)
434  {
435  m_axisDir *= -1;
436  m_hcs.FromNormal(m_axisDir);
437  }
438  return true;
439 }
440 
441 inline unsigned int Cone::Intersect(const Vec3f& p, const Vec3f& r,
442  float lambda[2], Vec3f interPts[2]) const
443 {
444  // Set up the quadratic Q(t) = c2*t^2 + 2*c1*t + c0 that corresponds to
445  // the cone. Let the vertex be V, the unit-length direction vector be A,
446  // and the angle measured from the cone axis to the cone wall be Theta,
447  // and define g = cos(Theta). A point X is on the cone wall whenever
448  // Dot(A,(X-V)/|X-V|) = g. Square this equation and factor to obtain
449  // (X-V)^T * (A*A^T - g^2*I) * (X-V) = 0
450  // where the superscript T denotes the transpose operator. This defines
451  // a double-sided cone. The line is L(t) = P + t*D, where P is the line
452  // origin and D is a unit-length direction vector. Substituting
453  // X = L(t) into the cone equation above leads to Q(t) = 0. Since we
454  // want only intersection points on the single-sided cone that lives in
455  // the half-space pointed to by A, any point L(t) generated by a root of
456  // Q(t) = 0 must be tested for Dot(A,L(t)-V) >= 0.
457  using namespace std;
458  float fAdD = m_axisDir.dot(r);
459  float tmp, fCosSqr = (tmp = cos(m_angle)) * tmp;
460  Vec3f kE = p - m_center;
461  float fAdE = m_axisDir.dot(kE);
462  float fDdE = r.dot(kE);
463  float fEdE = kE.dot(kE);
464  float fC2 = fAdD * fAdD - fCosSqr;
465  float fC1 = fAdD * fAdE - fCosSqr * fDdE;
466  float fC0 = fAdE * fAdE - fCosSqr * fEdE;
467  float fdot;
468 
469  // Solve the quadratic. Keep only those X for which Dot(A,X-V) >= 0.
470  unsigned int interCount = 0;
471  if (abs(fC2) >= 1e-7)
472  {
473  // c2 != 0
474  float fDiscr = fC1 * fC1 - fC0 * fC2;
475  if (fDiscr < (float)0.0)
476  {
477  // Q(t) = 0 has no real-valued roots. The line does not
478  // intersect the double-sided cone.
479  return 0;
480  }
481  else if (fDiscr > 1e-7)
482  {
483  // Q(t) = 0 has two distinct real-valued roots. However, one or
484  // both of them might intersect the portion of the double-sided
485  // cone "behind" the vertex. We are interested only in those
486  // intersections "in front" of the vertex.
487  float fRoot = sqrt(fDiscr);
488  float fInvC2 = ((float)1.0) / fC2;
489  interCount = 0;
490 
491  float fT = (-fC1 - fRoot) * fInvC2;
492  if (fT > 0) // intersect only in positive direction of ray
493  {
494  interPts[interCount] = p + fT * r;
495  kE = interPts[interCount] - m_center;
496  fdot = kE.dot(m_axisDir);
497  if (fdot > (float)0.0)
498  {
499  lambda[interCount] = fT;
500  interCount++;
501  }
502  }
503 
504  fT = (-fC1 + fRoot) * fInvC2;
505  if (fT > 0)
506  {
507  interPts[interCount] = p + fT * r;
508  kE = interPts[interCount] - m_center;
509  fdot = kE.dot(m_axisDir);
510  if (fdot > (float)0.0)
511  {
512  lambda[interCount] = fT;
513  interCount++;
514  }
515  }
516  }
517  else if (fC1 / fC2 < 0)
518  {
519  // one repeated real root (line is tangent to the cone)
520  interPts[0] = p - (fC1 / fC2) * r;
521  lambda[0] = -(fC1 / fC2);
522  kE = interPts[0] - m_center;
523  if (kE.dot(m_axisDir) > (float)0.0)
524  {
525  interCount = 1;
526  }
527  else
528  {
529  interCount = 0;
530  }
531  }
532  }
533  else if (abs(fC1) >= 1e-7)
534  {
535  // c2 = 0, c1 != 0 (D is a direction vector on the cone boundary)
536  lambda[0] = -(((float)0.5) * fC0 / fC1);
537  if (lambda[0] < 0)
538  {
539  return 0;
540  }
541  interPts[0] = p + lambda[0] * r;
542  kE = interPts[0] - m_center;
543  fdot = kE.dot(m_axisDir);
544  if (fdot > (float)0.0)
545  {
546  interCount = 1;
547  }
548  else
549  {
550  interCount = 0;
551  }
552  }
553  else if (abs(fC0) >= 1e-7)
554  {
555  // c2 = c1 = 0, c0 != 0
556  interCount = 0;
557  }
558  else
559  {
560  // c2 = c1 = c0 = 0, cone contains ray V+t*D where V is cone vertex
561  // and D is the line direction.
562  interCount = 1;
563  lambda[0] = (m_center - p).dot(r);
564  interPts[0] = m_center;
565  }
566 
567  return interCount;
568 }
569 
570 #endif
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:662
GfxTL::HyperplaneCoordinateSystem< float, 3 >
GfxTL::VectorXD
Definition: MatrixXX.h:21
cyberglove_with_calib_22dof.ic
ic
Definition: cyberglove_with_calib_22dof.py:22
Cone::Intersect
unsigned int Intersect(const Vec3f &p, const Vec3f &r, float lambda[2], Vec3f interPts[2]) const
Definition: Cone.h:441
Vec3f::normalize
float normalize()
Definition: basic.h:125
Vec3f
Definition: basic.h:16
Vec3f::cross
Vec3f cross(const Vec3f &v) const
Definition: basic.h:107
Cone::Distance
float Distance(const Vec3f &p) const
Definition: Cone.h:219
Cone::Normal
void Normal(const Vec3f &p, Vec3f *n) const
Definition: Cone.h:245
Cone::ParallelPlanesError::ParallelPlanesError
ParallelPlanesError()
Definition: Cone.h:28
ProsthesisInterface.values
values
Definition: ProsthesisInterface.py:190
Cone::DistanceAndNormal
float DistanceAndNormal(const Vec3f &p, Vec3f *n) const
Definition: Cone.h:255
GfxTL::MatrixXX
Definition: MatrixXX.h:25
MiscLib::Vector
Definition: Vector.h:19
LevMarFitting.h
Cone::ParallelPlanesError
Definition: Cone.h:25
NoShrinkVector.h
Cone::Fit
bool Fit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition: Cone.h:71
armarx::abs
std::vector< T > abs(const std::vector< T > &v)
Definition: VectorHelpers.h:253
M_PI
#define M_PI
Definition: MathTools.h:17
Cone
Definition: Cone.h:22
Cone::SignedDistance
float SignedDistance(const Vec3f &p) const
Definition: Cone.h:290
HyperplaneCoordinateSystem.h
Cone::Angle
float Angle() const
Definition: Cone.h:351
Cone::Center
const Vec3f & Center() const
Definition: Cone.h:356
Cone::RadiusAtLength
float RadiusAtLength(float length) const
Definition: Cone.h:371
PointCloud
Definition: PointCloud.h:69
Cone::AxisDirection
Vec3f & AxisDirection()
Definition: Cone.h:58
Vec3f::dot
float dot(const Vec3f &v) const
Definition: basic.h:92
float
#define float
Definition: 16_Level.h:22
basic.h
std
Definition: Application.h:66
LevMarLSWeight.h
dot
double dot(const Point &x, const Point &y)
Definition: point.hpp:53
Cone::SignedDistanceAndNormal
float SignedDistanceAndNormal(const Vec3f &p, Vec3f *n) const
Definition: Cone.h:316
PointCloud.h
DLL_LINKAGE
#define DLL_LINKAGE
Definition: basic.h:11
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:100
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
Cone::AngularDirection
const Vec3f AngularDirection() const
Definition: Cone.h:366
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
LevMar
bool LevMar(IteratorT begin, IteratorT end, FuncT &func, typename FuncT::ScalarType *param)
Definition: LevMarFitting.h:143
Cone::AxisDirection
const Vec3f & AxisDirection() const
Definition: Cone.h:361
Cone::Height
float Height(const Vec3f &p) const
Definition: Cone.h:376
Cone::LeastSquaresFit
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition: Cone.cpp:667