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