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>
9#ifdef DOPARALLEL
10#include <omp.h>
11#endif
12
13Cylinder::ParallelNormalsError::ParallelNormalsError() : std::runtime_error("Parallel normals")
14{
15}
16
17Cylinder::Cylinder() : m_angularRotatedRadians(0)
18{
19}
20
21Cylinder::Cylinder(const Vec3f& axisDir, const Vec3f& axisPos, float radius) :
22 m_angularRotatedRadians(0)
23{
24 Init(axisDir, axisPos, radius);
25}
26
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 {
36 }
37}
38
39bool
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
96bool
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
179bool
180Cylinder::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
190bool
191Cylinder::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
226bool
227Cylinder::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;
253 return true;
254}
255
256void
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;
267}
268
269void
270Cylinder::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;
284}
285
286void
287Cylinder::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
297void
298Cylinder::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
317float
319{
320 return m_radius;
321}
322
323float&
325{
326 return m_radius;
327}
328
329const Vec3f&
331{
332 return m_axisDir;
333}
334
335Vec3f&
337{
338 return m_axisDir;
339}
340
341const Vec3f&
343{
344 return m_axisPos;
345}
346
347Vec3f&
349{
350 return m_axisPos;
351}
352
353const Vec3f
355{
356 return Vec3f(m_hcs[0].Data());
357}
358
359void
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
371float
372CylinderDistance(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
388void
389CylinderDistanceDerivatives(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
422void
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
438bool
447
448bool
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
466void
467Cylinder::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
484size_t
486{
487 return sizeof(Vec3f) + sizeof(Vec3f) + sizeof(float) + sizeof(float);
488}
489
490void
491Cylinder::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
503size_t
505{
506 return 8;
507}
508
509void
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
518void
519Cylinder::Transform(float scale, const Vec3f& translate)
520{
521 m_axisPos *= scale;
522 m_axisPos += translate;
523 m_radius *= scale;
524}
525
526void
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}
#define float
Definition 16_Level.h:22
float CylinderDistance(const float *param, const float *x)
Definition Cylinder.cpp:372
void NormalizeCylinderParams(float *param)
Definition Cylinder.cpp:423
void CylinderDistanceDerivatives(const float *param, const float *x, float *gradient)
Definition Cylinder.cpp:389
#define M_PI
Definition MathTools.h:17
constexpr T c
static size_t SerializedFloatSize()
Definition Cylinder.cpp:504
static bool Interpolate(const MiscLib::Vector< Cylinder > &cylinders, const MiscLib::Vector< float > &weights, Cylinder *ic)
Definition Cylinder.cpp:449
static size_t SerializedSize()
Definition Cylinder.cpp:485
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Cylinder.cpp:439
const Vec3f AngularDirection() const
Definition Cylinder.cpp:354
void Transform(float scale, const Vec3f &translate)
Definition Cylinder.cpp:519
const Vec3f & AxisPosition() const
Definition Cylinder.cpp:342
void RotateAngularDirection(float radians)
Definition Cylinder.cpp:360
float Radius() const
Definition Cylinder.cpp:318
void Project(const Vec3f &p, Vec3f *pp) const
Definition Cylinder.cpp:287
const Vec3f & AxisDirection() const
Definition Cylinder.cpp:330
void Serialize(bool binary, std::ostream *o) const
Definition Cylinder.cpp:467
bool InitAverage(const MiscLib::Vector< Vec3f > &samples)
Definition Cylinder.cpp:97
bool Init(const MiscLib::Vector< Vec3f > &samples)
Definition Cylinder.cpp:40
void Parameters(const Vec3f &p, std::pair< float, float > *param) const
Definition Cylinder.cpp:298
size_type size() const
Definition Vector.h:215
void push_back(const T &v)
Definition Vector.h:354
Definition basic.h:18
float length() const
Definition basic.h:135
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
#define q
void CovarianceMatrix(const PointT &center, PointsForwardIt begin, PointsForwardIt end, WeightsForwardIt weights, MatrixT *matrix)
Definition Covariance.h:175
VectorXD< 3, float > Vector3Df
Definition VectorXD.h:718
bool Jacobi(const MatrixXX< N, N, T > &m, VectorXD< N, T > *d, MatrixXX< N, N, T > *v, int *nrot=NULL)
Definition Jacobi.h:24
IndexedIterator< IndexIteratorT, IteratorT > IndexIterate(IndexIteratorT idxIt, IteratorT it)
This file offers overloads of toIce() and fromIce() functions for STL container types.