Cylinder.h
Go to the documentation of this file.
1#ifndef CYLINDER_HEADER
2#define CYLINDER_HEADER
3#include <stdio.h>
4
5#include <istream>
6#include <ostream>
7#include <stdexcept>
8#include <utility>
9
10#include "LevMarFitting.h"
11#include "LevMarLSWeight.h"
12#include "PointCloud.h"
13#include "basic.h"
16#include <MiscLib/Vector.h>
17
18#ifndef DLL_LINKAGE
19#define DLL_LINKAGE
20#endif
21
23{
24public:
25 struct ParallelNormalsError : public std::runtime_error
26 {
28 };
29
30 enum
31 {
33 };
34
35 Cylinder();
36 Cylinder(const Vec3f& axisDir, const Vec3f& axisPos, float radius);
37 Cylinder(const Vec3f& pointA, const Vec3f& pointB, const Vec3f& normalA, const Vec3f& normalB);
38 bool Init(const MiscLib::Vector<Vec3f>& samples);
39 bool InitAverage(const MiscLib::Vector<Vec3f>& samples);
40 bool Init(const Vec3f& axisDir, const Vec3f& axisPos, float radius);
41 bool Init(const Vec3f& pointA, const Vec3f& pointB, const Vec3f& normalA, const Vec3f& normalB);
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* normal) const;
47 inline float DistanceAndNormal(const Vec3f& p, Vec3f* normal) const;
48 inline float SignedDistance(const Vec3f& p) const;
49 void Project(const Vec3f& p, Vec3f* pp) const;
50 // parameters are (height, angle)
51 void Parameters(const Vec3f& p, std::pair<float, float>* param) const;
52 float Radius() const;
53 float& Radius();
54 const Vec3f& AxisDirection() const;
55 Vec3f& AxisDirection();
56 const Vec3f& AxisPosition() const;
57 Vec3f& AxisPosition();
58 const Vec3f AngularDirection() const;
59 void RotateAngularDirection(float radians);
60 bool LeastSquaresFit(const PointCloud& pc,
63 template <class IteratorT>
64 bool LeastSquaresFit(IteratorT begin, IteratorT end);
65
66 bool
73
74 static bool Interpolate(const MiscLib::Vector<Cylinder>& cylinders,
75 const MiscLib::Vector<float>& weights,
76 Cylinder* ic);
77 void Serialize(bool binary, std::ostream* o) const;
78 static size_t SerializedSize();
79 void Serialize(FILE* o) const;
80 void Serialize(float* array) const;
81 static size_t SerializedFloatSize();
82
83 void Transform(float scale, const Vec3f& translate);
84 void Transform(const GfxTL::MatrixXX<3, 3, float>& rot, const GfxTL::Vector3Df& trans);
85 inline unsigned int
86 Intersect(const Vec3f& p, const Vec3f& r, float* first, float* second) const;
87
88private:
89 template <class WeightT>
90 class LevMarCylinder : public WeightT
91 {
92 public:
93 enum
94 {
95 NumParams = 7
96 };
97
98 typedef float ScalarType;
99
100 template <class IteratorT>
101 ScalarType
102 Chi(const ScalarType* params,
103 IteratorT begin,
104 IteratorT end,
105 ScalarType* values,
106 ScalarType* temp) const
107 {
108 ScalarType chi = 0;
109 int size = end - begin;
110#pragma omp parallel for schedule(static) reduction(+ : chi)
111 for (int idx = 0; idx < size; ++idx)
112 {
113 Vec3f s;
114 for (unsigned int j = 0; j < 3; ++j)
115 {
116 s[j] = begin[idx][j] - params[j];
117 }
118 ScalarType u = params[5] * s[1] - params[4] * s[2];
119 u *= u;
120 ScalarType v = params[3] * s[2] - params[5] * s[0];
121 u += v * v;
122 v = params[4] * s[0] - params[3] * s[1];
123 u += v * v;
124 temp[idx] = std::sqrt(u);
125 chi += (values[idx] = WeightT::Weigh(temp[idx] - params[6])) * values[idx];
126 }
127 return chi;
128 }
129
130 template <class IteratorT>
131 void
132 Derivatives(const ScalarType* params,
133 IteratorT begin,
134 IteratorT end,
135 const ScalarType* values,
136 const ScalarType* temp,
137 ScalarType* matrix) const
138 {
139 int size = end - begin;
140#pragma omp parallel for schedule(static)
141 for (int idx = 0; idx < size; ++idx)
142 {
143 Vec3f s;
144 for (unsigned int j = 0; j < 3; ++j)
145 {
146 s[j] = begin[idx][j] - params[j];
147 }
148 ScalarType g = s[0] * begin[idx][0] + s[1] * begin[idx][1] + s[2] * begin[idx][2];
149 if (temp[idx] < 1e-6)
150 {
151 matrix[idx * NumParams + 0] = std::sqrt(1 - params[3] * params[3]);
152 matrix[idx * NumParams + 1] = std::sqrt(1 - params[4] * params[4]);
153 matrix[idx * NumParams + 2] = std::sqrt(1 - params[5] * params[5]);
154 }
155 else
156 {
157 matrix[idx * NumParams + 0] = (params[3] * g - s[0]) / temp[idx];
158 matrix[idx * NumParams + 1] = (params[4] * g - s[1]) / temp[idx];
159 matrix[idx * NumParams + 2] = (params[5] * g - s[2]) / temp[idx];
160 }
161 matrix[idx * NumParams + 3] = g * matrix[idx * NumParams + 0];
162 matrix[idx * NumParams + 4] = g * matrix[idx * NumParams + 1];
163 matrix[idx * NumParams + 5] = g * matrix[idx * NumParams + 2];
164 matrix[idx * NumParams + 6] = -1;
165 WeightT::template DerivWeigh<NumParams>(temp[idx] - params[6],
166 matrix + idx * NumParams);
167 }
168 }
169
170 void
171 Normalize(ScalarType* params) const
172 {
173 ScalarType l =
174 std::sqrt(params[3] * params[3] + params[4] * params[4] + params[5] * params[5]);
175 for (unsigned int i = 3; i < 6; ++i)
176 {
177 params[i] /= l;
178 }
179 // find point on axis closest to origin
180 float lambda = -(params[0] * params[3] + params[1] * params[4] + params[2] * params[5]);
181 for (unsigned int i = 0; i < 3; ++i)
182 {
183 params[i] = params[i] + lambda * params[i + 3];
184 }
185 }
186 };
187
188private:
189 Vec3f m_axisDir;
190 Vec3f m_axisPos;
191 float m_radius;
192 GfxTL::HyperplaneCoordinateSystem<float, 3> m_hcs;
193 float m_angularRotatedRadians;
194};
195
196inline float
198{
199 Vec3f diff = p - m_axisPos;
200 float lambda = m_axisDir.dot(diff);
201 float axisDist = (diff - lambda * m_axisDir).length();
202 return abs(axisDist - m_radius);
203}
204
205inline void
206Cylinder::Normal(const Vec3f& p, Vec3f* normal) const
207{
208 Vec3f diff = p - m_axisPos;
209 float lambda = m_axisDir.dot(diff);
210 *normal = diff - lambda * m_axisDir;
211 normal->normalize();
212}
213
214inline float
216{
217 Vec3f diff = p - m_axisPos;
218 float lambda = m_axisDir.dot(diff);
219 *normal = diff - lambda * m_axisDir;
220 float axisDist = normal->length();
221 if (axisDist > 0)
222 {
223 *normal /= axisDist;
224 }
225 return abs(axisDist - m_radius);
226}
227
228inline float
230{
231 Vec3f diff = p - m_axisPos;
232 float lambda = m_axisDir.dot(diff);
233 float axisDist = (diff - lambda * m_axisDir).length();
234 return axisDist - m_radius;
235}
236
237template <class IteratorT>
238bool
239Cylinder::LeastSquaresFit(IteratorT begin, IteratorT end)
240{
241 float param[7];
242 for (size_t i = 0; i < 3; ++i)
243 {
244 param[i] = m_axisPos[i];
245 }
246 for (size_t i = 0; i < 3; ++i)
247 {
248 param[i + 3] = m_axisDir[i];
249 }
250 param[6] = m_radius;
251 LevMarCylinder<LevMarLSWeight> levMarCylinder;
252 if (!LevMar(begin, end, levMarCylinder, param))
253 {
254 return false;
255 }
256 for (size_t i = 0; i < 3; ++i)
257 {
258 m_axisPos[i] = param[i];
259 }
260 for (size_t i = 0; i < 3; ++i)
261 {
262 m_axisDir[i] = param[i + 3];
263 }
264 m_radius = param[6];
265 m_hcs.FromNormal(m_axisDir);
266 m_angularRotatedRadians = 0;
267 return true;
268}
269
270inline unsigned int
271Cylinder::Intersect(const Vec3f& p, const Vec3f& r, float* first, float* second) const
272{
273 using namespace std;
274 // Create a coordinate system for the cylinder. In this system, the
275 // cylinder segment center C is the origin and the cylinder axis direction
276 // W is the z-axis. U and V are the other coordinate axis directions.
277 // If P = x*U+y*V+z*W, the cylinder is x^2 + y^2 = r^2, where r is the
278 // cylinder radius. The end caps are |z| = h/2, where h is the cylinder
279 // height.
280 float fRSqr = m_radius * m_radius;
281
282 // convert incoming line origin to cylinder coordinates
283 Vec3f kDiff = p - m_axisPos;
284 Vec3f kP(kDiff.dot(m_hcs[0]), kDiff.dot(m_hcs[1]), m_axisDir.dot(kDiff));
285
286 // Get the z-value, in cylinder coordinates, of the incoming line's
287 // unit-length direction.
288 float fDz = m_axisDir.dot(r);
289
290 if (abs(fDz) >= 1.f - 1e-7f)
291 // The line is parallel to the cylinder axis.
292 {
293 return 0;
294 }
295
296 // convert incoming line unit-length direction to cylinder coordinates
297 Vec3f kD(r.dot(m_hcs[0]), r.dot(m_hcs[1]), r.dot(m_axisDir));
298
299 float fA0, fA1, fA2, fDiscr, fRoot, fInv;
300
301 // Test intersection of line P+t*D with infinite cylinder
302 // x^2+y^2 = r^2. This reduces to computing the roots of a
303 // quadratic equation. If P = (px,py,pz) and D = (dx,dy,dz),
304 // then the quadratic equation is
305 // (dx^2+dy^2)*t^2 + 2*(px*dx+py*dy)*t + (px^2+py^2-r^2) = 0
306 fA0 = kP[0] * kP[0] + kP[1] * kP[1] - fRSqr;
307 fA1 = kP[0] * kD[0] + kP[1] * kD[1];
308 fA2 = kD[0] * kD[0] + kD[1] * kD[1];
309 fDiscr = fA1 * fA1 - fA0 * fA2;
310 if (fDiscr < 0)
311 // line does not intersect cylinder
312 {
313 return 0;
314 }
315 else if (fDiscr > 1e-7f)
316 {
317 // line intersects cylinder in two places
318 fRoot = sqrt(fDiscr);
319 fInv = (1.f) / fA2;
320 *first = (-fA1 - fRoot) * fInv;
321 *second = (-fA1 + fRoot) * fInv;
322 return 2;
323 }
324 // line is tangent to the cylinder
325 *first = -fA1 / fA2;
326 return 1;
327}
328
329#endif
bool LevMar(IteratorT begin, IteratorT end, FuncT &func, typename FuncT::ScalarType *param)
#define DLL_LINKAGE
Definition basic.h:12
float SignedDistance(const Vec3f &p) const
Definition Cylinder.h:229
float DistanceAndNormal(const Vec3f &p, Vec3f *normal) const
Definition Cylinder.h:215
bool LeastSquaresFit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Cylinder.cpp:439
@ RequiredSamples
Definition Cylinder.h:32
void Normal(const Vec3f &p, Vec3f *normal) const
Definition Cylinder.h:206
bool Fit(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end)
Definition Cylinder.h:67
float Distance(const Vec3f &p) const
Definition Cylinder.h:197
unsigned int Intersect(const Vec3f &p, const Vec3f &r, float *first, float *second) const
Definition Cylinder.h:271
Definition basic.h:18
float length() const
Definition basic.h:135
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
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39