CylinderPrimitiveShape.cpp
Go to the documentation of this file.
2
3#include <limits>
4
6#include "ScoreComputer.h"
7#ifndef _USE_MATH_DEFINES
8#define _USE_MATH_DEFINES
9#endif
10#include <algorithm>
11#include <cmath>
12#include <iostream>
13
14#include "ConePrimitiveShape.h"
15#include "PlanePrimitiveShape.h"
17#include "TorusPrimitiveShape.h"
18#include <GfxTL/NullClass.h>
19#include <MiscLib/Performance.h>
21
25
26CylinderPrimitiveShape::CylinderPrimitiveShape(const Cylinder& cylinder) : m_cylinder(cylinder)
27{
28}
29
30size_t
32{
33 return 2;
34}
35
38{
39 return new CylinderPrimitiveShape(*this);
40}
41
42bool
44 const Vec3f& pointB,
45 const Vec3f& normalA,
46 const Vec3f& normalB)
47{
48 return m_cylinder.Init(pointA, pointB, normalA, normalB);
49}
50
51float
53{
54 return m_cylinder.Distance(p);
55}
56
57float
59{
60 return m_cylinder.SignedDistance(p);
61}
62
63float
65{
66 Vec3f normal;
67 m_cylinder.Normal(p, &normal);
68 return n.dot(normal);
69}
70
71void
73 const Vec3f& n,
74 std::pair<float, float>* dn) const
75{
76 Vec3f normal;
77 dn->first = m_cylinder.DistanceAndNormal(p, &normal);
78 dn->second = n.dot(normal);
79}
80
81void
83{
84 m_cylinder.Project(p, pp);
85}
86
87void
89{
90 m_cylinder.Normal(p, n);
91}
92
93unsigned int
95 float epsilon,
96 float normalThresh,
97 float rms,
98 const PointCloud& pc,
99 const MiscLib::Vector<size_t>& indices) const
100{
102 numTests, epsilon, normalThresh, rms, pc, indices);
103}
104
105void
107{
108 *s = "Cylinder";
109}
110
111bool
113 float epsilon,
114 float normalThresh,
117
118{
119 Cylinder fit = m_cylinder;
120 if (fit.LeastSquaresFit(pc, begin, end))
121 {
122 m_cylinder = fit;
123 return true;
124 }
125 return false;
126}
127
130 float epsilon,
131 float normalThresh,
134 std::pair<size_t, float>* score) const
135{
136 Cylinder fit = m_cylinder;
137 if (fit.LeastSquaresFit(pc, begin, end))
138 {
139 score->first = -1;
140 return new CylinderPrimitiveShape(fit);
141 }
142 score->first = 0;
143 return NULL;
144}
145
148{
149 return new CylinderLevMarFunc(m_cylinder);
150}
151
152void
153CylinderPrimitiveShape::Serialize(std::ostream* o, bool binary) const
154{
155 if (binary)
156 {
157 const char id = 2;
158 (*o) << id;
159 }
160 else
161 {
162 (*o) << "2"
163 << " ";
164 }
165 m_cylinder.Serialize(binary, o);
166 if (!binary)
167 {
168 *o << std::endl;
169 }
170}
171
172size_t
174{
175 return m_cylinder.SerializedSize() + 1;
176}
177
178void
179CylinderPrimitiveShape::Transform(float scale, const Vec3f& translate)
180{
181 m_cylinder.Transform(scale, translate);
182}
183
184void
186 const GfxTL::Vector3Df& trans)
187{
188 m_cylinder.Transform(rot, trans);
189}
190
191void
193{
194 visitor->Visit(*this);
195}
196
197void
199 const PointCloud& pc,
202 float distThresh,
204{
205 // sample the bounding box in parameter space at 25 locations
206 // these points are used to estimate the other shapes
207 // if the shapes succeed the suggestion is returned
208 MiscLib::Vector<Vec3f> samples(2 * 25);
209 float uStep = (m_extBbox.Max()[0] - m_extBbox.Min()[0]) / 4;
210 float vStep = (m_extBbox.Max()[1] - m_extBbox.Min()[1]) / 4;
211 float u = m_extBbox.Min()[0];
212 for (unsigned int i = 0; i < 5; ++i, u += uStep)
213 {
214 float v = m_extBbox.Min()[1];
215 for (unsigned int j = 0; j < 5; ++j, v += vStep)
216 InSpace(u, v * m_cylinder.Radius(), &samples[i * 5 + j], &samples[i * 5 + j + 25]);
217 }
218 size_t c = samples.size() / 2;
219 // now check all the shape types
220 Sphere sphere;
221 if (sphere.Init(samples))
222 {
223 sphere.LeastSquaresFit(samples.begin(), samples.begin() + c);
224 bool failed = false;
225 for (size_t i = 0; i < c; ++i)
226 if (sphere.Distance(samples[i]) > distThresh)
227 {
228 failed = true;
229 break;
230 }
231 if (!failed)
232 {
233 suggestions->push_back(new SpherePrimitiveShape(sphere));
234 suggestions->back()->Release();
235 }
236 }
237 Plane plane;
238 if (plane.LeastSquaresFit(samples.begin(), samples.begin() + c))
239 {
240 bool failed = false;
241 for (size_t i = 0; i < c; ++i)
242 if (plane.Distance(samples[i]) > distThresh)
243 {
244 failed = true;
245 break;
246 }
247 if (!failed)
248 {
249 suggestions->push_back(new PlanePrimitiveShape(plane));
250 suggestions->back()->Release();
251 }
252 }
253 /*// We suggest a sphere if a curvature of radius along the height
254 // does not introduce too large an error
255 float length = m_extBbox.Max()[0] - m_extBbox.Min()[0];
256 float meanLength = (m_extBbox.Max()[0] + m_extBbox.Min()[0]) / 2;
257 float radiusDiff = (std::sqrt(m_cylinder.Radius() * m_cylinder.Radius()
258 + length * length / 4) - m_cylinder.Radius()) / 2;
259 float radialExtent = m_extBbox.Max()[1] - m_extBbox.Min()[1];
260 if(radiusDiff < distThresh)
261 {
262 // the center of the sphere is given as the point on the axis
263 // with the height of the mean length
264 Vec3f center = meanLength * m_cylinder.AxisDirection()
265 + m_cylinder.AxisPosition();
266 Sphere sphere(center, m_cylinder.Radius() + radiusDiff);
267 suggestions->push_back(new SpherePrimitiveShape(sphere));
268 suggestions->back()->Release();
269 }
270
271 // We suggest a plane if the mean radius causes only a small error
272 // for this we need the angular extent in the curved direction of the cone
273 radiusDiff = (m_cylinder.Radius() - std::cos(radialExtent / 2)
274 * m_cylinder.Radius()) / 2;
275 if(radiusDiff < distThresh)
276 {
277 GfxTL::Vector2Df bboxCenter;
278 m_extBbox.Center(&bboxCenter);
279 Vec3f pos, normal;
280 InSpace(bboxCenter[0], bboxCenter[1] * m_cylinder.Radius(),
281 &pos, &normal);
282 // offset position
283 pos -= radiusDiff * normal;
284 Plane plane(pos, normal);
285 suggestions->push_back(new PlanePrimitiveShape(plane));
286 suggestions->back()->Release();
287 }*/
288}
289
290bool
291CylinderPrimitiveShape::Similar(float tolerance, const CylinderPrimitiveShape& shape) const
292{
293 return m_cylinder.Radius() <= (1.f + tolerance) * shape.m_cylinder.Radius() &&
294 (1.f + tolerance) * m_cylinder.Radius() >= shape.m_cylinder.Radius();
295}
296
297float
299{
300 return m_extBbox.Max()[0] - m_extBbox.Min()[0];
301}
302
303float
305{
306 return m_extBbox.Min()[0];
307}
308
309float
311{
312 return m_extBbox.Max()[0];
313}
314
315void
316CylinderPrimitiveShape::Parameters(const Vec3f& p, std::pair<float, float>* param) const
317{
318 m_cylinder.Parameters(p, param);
319 // convert angle to arc length
320 param->second *= m_cylinder.Radius();
321}
322
323void
331
332void
336 MiscLib::Vector<std::pair<float, float>>* bmpParams) const
337{
338 ParametersImpl(begin, end, bmpParams);
339}
340
341void
344 MiscLib::Vector<std::pair<float, float>>* params,
345 size_t* uextent,
346 size_t* vextent)
347{
348 *uextent = size_t(std::ceil((bbox->Max()[0] - bbox->Min()[0]) / epsilon));
349 *vextent = size_t(std::ceil((bbox->Max()[1] - bbox->Min()[1]) / epsilon));
350 if ((*vextent) * (*uextent) > 1e6)
351 {
352 // try to reparameterize
353 if (bbox->Min()[1] > epsilon && bbox->Max()[1] < 2 * M_PI * m_cylinder.Radius() - epsilon)
354 {
355 return; // there is no wrapping -> we can't do anything
356 }
357 MiscLib::Vector<float> angularParams(params->size());
358 for (size_t i = 0; i < params->size(); ++i)
359 {
360 angularParams[i] = (*params)[i].second;
361 }
362 std::sort(angularParams.begin(), angularParams.end());
363 // try to find a large gap
364 float maxGap = 0;
365 float lower, upper;
366 for (size_t i = 1; i < angularParams.size(); ++i)
367 {
368 float gap = angularParams[i] - angularParams[i - 1];
369 if (gap > maxGap)
370 {
371 maxGap = gap;
372 lower = angularParams[i - 1];
373 upper = angularParams[i];
374 }
375 }
376 if (maxGap > epsilon)
377 {
378 // reparameterize with new angular cut
379 float newCut = (lower + upper) / 2.f;
380 m_cylinder.RotateAngularDirection(newCut / m_cylinder.Radius());
381 bbox->Min()[1] = std::numeric_limits<float>::infinity();
382 bbox->Max()[1] = -std::numeric_limits<float>::infinity();
383 for (size_t i = 0; i < params->size(); ++i)
384 {
385 (*params)[i].second -= newCut;
386 if ((*params)[i].second < 0)
387 {
388 (*params)[i].second = 2 * M_PI * m_cylinder.Radius() + (*params)[i].second;
389 }
390 if ((*params)[i].second < bbox->Min()[1])
391 {
392 bbox->Min()[1] = (*params)[i].second;
393 }
394 if ((*params)[i].second > bbox->Max()[1])
395 {
396 bbox->Max()[1] = (*params)[i].second;
397 }
398 }
399 *vextent = size_t(std::ceil((bbox->Max()[1] - bbox->Min()[1]) / epsilon));
400 }
401 }
402}
403
404void
405CylinderPrimitiveShape::InBitmap(const std::pair<float, float>& param,
406 float epsilon,
408 size_t uextent,
409 size_t vextent,
410 std::pair<int, int>* inBmp) const
411{
412 // convert the parameters to bitmap coordinates
413 inBmp->first = std::floor((param.first - bbox.Min()[0]) / epsilon);
414 inBmp->second = std::floor((param.second - bbox.Min()[1]) / epsilon);
415}
416
417void
419 float epsilon,
420 bool* uwrap,
421 bool* vwrap) const
422{
423 *uwrap = false;
424 if (bbox.Max()[1] - bbox.Min()[1] >= 2 * M_PI * m_cylinder.Radius() - 2 * epsilon)
425 {
426 *vwrap = true; // wrap around angular component
427 }
428 else
429 {
430 *vwrap = false;
431 }
432}
433
434void
436 float epsilon,
437 size_t uextent,
438 size_t vextent,
439 MiscLib::Vector<char>* bmp) const
440{
441 // wraps the bitmpap around the v-axis
442 // note: we do not check, if the cylinder is really wrapped around !
443 // Use WrapBitmap for this check
444 for (int i = 0; i < uextent; i++)
445 {
446 char t = (*bmp)[i];
447 bmp->push_back(t);
448 }
449}
450
451void
453 const MiscLib::Vector<int>& componentsImg,
454 size_t uextent,
455 size_t vextent,
456 float epsilon,
457 int label)
458{
459 if (extBbox.Min()[1] * m_cylinder.Radius() <= epsilon &&
460 extBbox.Max()[1] * m_cylinder.Radius() >= 2 * M_PI * m_cylinder.Radius() - epsilon)
461 {
462 // component has been cut along angular direction
463 // run from both sides to find both ends
464 size_t row = 0, j = 0;
465 for (; j < vextent; ++j)
466 {
467 bool found = false;
468 for (size_t i = 0; i < uextent; ++i)
469 {
470 if (componentsImg[row + i] == label)
471 {
472 found = true;
473 break;
474 }
475 }
476 if (!found)
477 {
478 break;
479 }
480 row += uextent;
481 }
482 size_t maxj = j;
483 if (maxj == vextent) // cylinder is complete
484 {
485 m_clip = false;
486 return;
487 }
488 row = (vextent - 1) * uextent, j = 0;
489 for (; j < vextent; ++j)
490 {
491 bool found = false;
492 for (size_t i = 0; i < uextent; ++i)
493 {
494 if (componentsImg[row + i] == label)
495 {
496 found = true;
497 break;
498 }
499 }
500 if (!found)
501 {
502 break;
503 }
504 row -= uextent;
505 }
506 size_t minj = j;
507 // convert min and max to angular parameters
508 m_minPhi = minj * epsilon / m_cylinder.Radius() + extBbox.Min()[1];
509 m_maxPhi = maxj * epsilon / m_cylinder.Radius() + extBbox.Min()[1];
510 }
511 else
512 {
513 m_minPhi = extBbox.Min()[1];
514 m_maxPhi = extBbox.Max()[1];
515 }
516 m_clip = true;
517}
518
519bool
520CylinderPrimitiveShape::InSpace(float u, float v, Vec3f* p, Vec3f* n) const
521{
523 q.RotationRad(v / m_cylinder.Radius(),
524 m_cylinder.AxisDirection()[0],
525 m_cylinder.AxisDirection()[1],
526 m_cylinder.AxisDirection()[2]);
527 Vec3f vvec;
528 q.Rotate(m_cylinder.AngularDirection(), &vvec);
529 *p = u * m_cylinder.AxisDirection() + m_cylinder.Radius() * vvec + m_cylinder.AxisPosition();
530 *n = vvec;
531 return true;
532}
533
534bool
536 size_t v,
537 float epsilon,
539 size_t uextent,
540 size_t vextent,
541 Vec3f* p,
542 Vec3f* n) const
543{
545 q.RotationRad((bbox.Min()[1] + epsilon * (v + .5f)) / m_cylinder.Radius(),
546 m_cylinder.AxisDirection()[0],
547 m_cylinder.AxisDirection()[1],
548 m_cylinder.AxisDirection()[2]);
549 Vec3f vvec;
550 q.Rotate(m_cylinder.AngularDirection(), &vvec);
551 *p = (bbox.Min()[0] + epsilon * (u + .5f)) * m_cylinder.AxisDirection() +
552 m_cylinder.Radius() * vvec + m_cylinder.AxisPosition();
553 *n = vvec;
554 return true;
555}
MiscLib::performance_t totalTime_cylinderConnected
#define M_PI
Definition MathTools.h:17
class DLL_LINKAGE SpherePrimitiveShape
class DLL_LINKAGE PlanePrimitiveShape
constexpr T c
unsigned int ConfidenceTests(unsigned int numTests, float epsilon, float normalThresh, float rms, const PointCloud &pc, const MiscLib::Vector< size_t > &indices) const
GfxTL::AABox< GfxTL::Vector2Df > m_extBbox
void DistanceAndNormalDeviation(const Vec3f &p, const Vec3f &n, std::pair< float, float > *dn) const
unsigned int ConfidenceTests(unsigned int numTests, float epsilon, float normalThresh, float rms, const PointCloud &pc, const MiscLib::Vector< size_t > &indices) const
float SignedDistance(const Vec3f &p) const
float NormalDeviation(const Vec3f &p, const Vec3f &n) const
void PreWrapBitmap(const GfxTL::AABox< GfxTL::Vector2Df > &bbox, float epsilon, size_t uextent, size_t vextent, MiscLib::Vector< char > *bmp) const
PrimitiveShape * Clone() const
void Normal(const Vec3f &p, Vec3f *n) const
void SuggestSimplifications(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end, float distThresh, MiscLib::Vector< MiscLib::RefCountPtr< PrimitiveShape > > *suggestions) const
void InBitmap(const std::pair< float, float > &param, float epsilon, const GfxTL::AABox< GfxTL::Vector2Df > &bbox, size_t uextent, size_t vextent, std::pair< int, int > *inBmp) const
void Transform(float scale, const Vec3f &translate)
PrimitiveShape * LSFit(const PointCloud &pc, float epsilon, float normalThresh, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end, std::pair< size_t, float > *score) const
void Visit(PrimitiveShapeVisitor *visitor) const
void Project(const Vec3f &p, Vec3f *pp) const
bool Similar(float tolerance, const CylinderPrimitiveShape &shape) const
LevMarFunc< float > * SignedDistanceFunc() const
bool Fit(const PointCloud &pc, float epsilon, float normalThresh, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
void SetExtent(const GfxTL::AABox< GfxTL::Vector2Df > &bbox, const MiscLib::Vector< int > &componentsImg, size_t uextent, size_t vextent, float epsilon, int label)
void WrapBitmap(const GfxTL::AABox< GfxTL::Vector2Df > &bbox, float epsilon, bool *uwrap, bool *vwrap) const
float Distance(const Vec3f &p) const
void Serialize(std::ostream *o, bool binary=true) const
This is the one and only serialization function It stores all the parameters of the shape as well as ...
void BitmapExtent(float epsilon, GfxTL::AABox< GfxTL::Vector2Df > *bbox, MiscLib::Vector< std::pair< float, float > > *params, size_t *uextent, size_t *vextent)
void Description(std::string *s) const
bool Init(const Vec3f &pointA, const Vec3f &pointB, const Vec3f &normalA, const Vec3f &normalB)
void Parameters(const Vec3f &p, std::pair< float, float > *param) const
bool InSpace(float u, float v, Vec3f *p, Vec3f *n) const
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Cylinder.cpp:439
float Radius() const
Definition Cylinder.cpp:318
Point & Min()
Definition AABox.hpp:68
Point & Max()
Definition AABox.hpp:82
const Point * const_iterator
Definition Vector.h:25
size_type size() const
Definition Vector.h:215
void push_back(const T &v)
Definition Vector.h:354
Definition Plane.h:19
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Plane.cpp:200
float Distance(const Vec3f &pos) const
Definition Plane.h:47
virtual void Visit(const PlanePrimitiveShape &plane)=0
PrimtiveShape is a shape primitive in conjunction with a parametrization.
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Sphere.cpp:399
float Distance(const Vec3f &p) const
Definition Sphere.h:260
bool Init(const MiscLib::Vector< Vec3f > &samples)
Definition Sphere.cpp:172
Definition basic.h:18
#define q
VectorXD< 3, float > Vector3Df
Definition VectorXD.h:718
clock_t performance_t
Definition Performance.h:31