Ponca  93eea5457c48839cb5d16642765afa89fc7cfe66
Point Cloud Analysis library
Loading...
Searching...
No Matches
pointGeneration.h
1/*
2This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5*/
6
7#pragma once
8
13#include "Eigen/Eigen"
14#include "./defines.h"
15
16#define MIN_NOISE 0.99
17#define MAX_NOISE 1.01
18
19namespace Ponca {
20
22 template<typename DataPoint>
23 [[nodiscard]] DataPoint getPointOnSphere(
24 const typename DataPoint::Scalar _radius,
25 const typename DataPoint::VectorType _vCenter,
26 const bool _bAddPositionNoise = true,
27 const bool _bAddNormalNoise = true,
28 const bool _bReverseNormals = false
29 ) {
30 typedef typename DataPoint::Scalar Scalar;
31 typedef typename DataPoint::VectorType VectorType;
32
33 VectorType vNormal = VectorType::Random().normalized();
34 VectorType vPosition = _vCenter + vNormal * _radius;
35
36 if(_bAddPositionNoise)
37 {
38 vPosition = vPosition + VectorType::Random().normalized() *
39 Eigen::internal::random<Scalar>(Scalar(0.), Scalar(1. - MIN_NOISE));
40 vNormal = (vPosition - _vCenter).normalized();
41 }
42
43 if(_bAddNormalNoise)
44 {
45 VectorType vTempPos = vPosition + VectorType::Random().normalized() *
46 Eigen::internal::random<Scalar>(Scalar(0.), Scalar(1. - MIN_NOISE));
47 vNormal = (vTempPos - _vCenter).normalized();
48 }
49 if(_bReverseNormals)
50 {
51 const float reverse = Eigen::internal::random<float>(0.f, 1.f);
52 if(reverse > 0.5f)
53 vNormal = -vNormal;
54 }
55
56 return DataPoint(vPosition, vNormal);
57 }
58
60 template<typename VectorType>
61 [[nodiscard]] VectorType getPointOnCircle(
62 typename VectorType::Scalar _radius,
63 VectorType _vCenter
64 ) {
65 using Scalar = typename VectorType::Scalar;
66 // Generate random angle
67 double theta = Eigen::internal::random<Scalar>(0,2.*EIGEN_PI);
68
69 // Generate random radius (adjusted for uniform area distribution)
70 double r = _radius * std::sqrt(Eigen::internal::random<Scalar>(0,1));
71
72 // Convert to Cartesian coordinates
73 VectorType p = _vCenter;
74 p.x() += r * std::cos(theta);
75 p.y() += r * std::sin(theta);
76
77 return p;
78 }
79
81 template<typename DataPoint>
82 [[nodiscard]] DataPoint getPointOnRectangularPlane(
83 const typename DataPoint::VectorType& _vPosition,
84 const typename DataPoint::VectorType& /*_vNormal*/,
85 const typename DataPoint::Scalar& _width,
86 const typename DataPoint::Scalar& _height,
87 const typename DataPoint::VectorType& _localxAxis,
88 const typename DataPoint::VectorType& _localyAxis,
89 const bool _bAddPositionNoise = true
90 ) {
91 typedef typename DataPoint::Scalar Scalar;
92 typedef typename DataPoint::VectorType VectorType;
93
94 const Scalar u = Eigen::internal::random<Scalar>(
95 -_width /Scalar(2), _width /Scalar(2) );
96 const Scalar v = Eigen::internal::random<Scalar>(
97 -_height/Scalar(2), _height/Scalar(2) );
98
99 VectorType vRandomPosition = _vPosition + u*_localxAxis + v*_localyAxis;
100
101 if(_bAddPositionNoise)
102 {
103 vRandomPosition = vRandomPosition +
104 VectorType::Random().normalized() *
105 Eigen::internal::random<Scalar>(0., 1. - MIN_NOISE);
106 }
107
108 return DataPoint(vRandomPosition);
109 }
110
112 template<typename DataPoint>
113 [[nodiscard]] DataPoint getPointOnPlane(
114 const typename DataPoint::VectorType _vPosition,
115 const typename DataPoint::VectorType _vNormal,
116 const typename DataPoint::Scalar _radius,
117 const bool _bAddPositionNoise = true,
118 const bool _bAddNormalNoise = true,
119 const bool _bReverseNormals = false
120 ) {
121 typedef typename DataPoint::Scalar Scalar;
122 typedef typename DataPoint::VectorType VectorType;
123 typedef Eigen::Quaternion<Scalar> QuaternionType;
124
125 VectorType vRandom;
126 VectorType vRandomDirection = VectorType::Zero();
127 VectorType vRandomPoint = VectorType::Zero();
128 VectorType vLocalUp = _vNormal;
129
130 do
131 {
132 vRandom = VectorType::Random().normalized(); // Direction in the unit sphere
133 vRandomDirection = vRandom.cross(vLocalUp);
134 }
135 while(vRandomDirection == VectorType::Zero());
136
137 vRandomDirection = vRandomDirection.normalized();
138 vRandomPoint = vRandomDirection * _radius;
139 vRandomPoint += _vPosition;
140
141 if(_bAddPositionNoise)
142 {
143 vRandomPoint = vRandomPoint + VectorType::Random().normalized() *
144 Eigen::internal::random<Scalar>(Scalar(0), Scalar(1. - MIN_NOISE));
145 }
146
147 if(_bAddNormalNoise)
148 {
149 VectorType vLocalLeft = vLocalUp.cross(vRandomDirection);
150 VectorType vLocalFront = vLocalLeft.cross(vLocalUp);
151
152 Scalar rotationAngle = Eigen::internal::random<Scalar>(Scalar(-M_PI / 16.), Scalar(M_PI / 16.));
153 VectorType vRotationAxis = vLocalLeft;
154 QuaternionType qRotation = QuaternionType(Eigen::AngleAxis<Scalar>(rotationAngle, vRotationAxis));
155 qRotation = qRotation.normalized();
156 vLocalUp = qRotation * vLocalUp;
157
158 rotationAngle = Eigen::internal::random<Scalar>(Scalar(-M_PI / 16.), Scalar(M_PI / 16.));
159 vRotationAxis = vLocalFront;
160 qRotation = QuaternionType(Eigen::AngleAxis<Scalar>(rotationAngle, vRotationAxis));
161 qRotation = qRotation.normalized();
162 vLocalUp = qRotation * vLocalUp;
163 }
164
165 if(_bReverseNormals)
166 {
167 const float reverse = Eigen::internal::random<float>(0.f, 1.f);
168 if(reverse > 0.5f)
169 vLocalUp = -vLocalUp;
170
171 }
172
173 return DataPoint(vRandomPoint, vLocalUp);
174 }
175
176 namespace internal {
178 template<typename Scalar>
179 [[nodiscard]] inline Scalar getParaboloidZ(
180 const Scalar _x,
181 const Scalar _y,
182 const Scalar _a,
183 const Scalar _b
184 ) {
185 return _a*_x*_x + _b*_y*_y;
186 }
187
189 template<typename Scalar>
190 [[nodiscard]] inline Scalar
191 getParaboloidZ(Scalar _x,
192 Scalar _y,
193 Scalar _a,
194 Scalar _b,
195 Scalar _c,
196 Scalar _d,
197 Scalar _e,
198 Scalar _f)
199 {
200 return _a*_x*_x + _b*_y*_y + _c*_x*_y + _d*_x + _e*_y + _f;
201 }
202
204 template<typename VectorType>
205 [[nodiscard]] inline VectorType getParaboloidNormal(
206 const VectorType& in,
207 const typename VectorType::Scalar _a,
208 const typename VectorType::Scalar _b
209 ) {
210 return VectorType((_a * in.x()), (_b * in.y()), -1.).normalized();;
211 }
212 template<typename DataPoint>
213 inline typename std::enable_if<Ponca::hasNormal<DataPoint>::value, void>::type
214 getParaboloidNormal(DataPoint& in,
215 typename DataPoint::Scalar _a,
216 typename DataPoint::Scalar _b,
217 typename DataPoint::Scalar _c,
218 typename DataPoint::Scalar _d,
219 typename DataPoint::Scalar _e,
220 typename DataPoint::Scalar _f)
221 {
222 static constexpr typename DataPoint::Scalar two {2};
223 auto& pos = in.pos();
224 in.normal() = typename DataPoint::VectorType(two*_a * pos.x() + _c*pos.y() + _d,
225 two*_b * pos.y() + _c*pos.x() + _d,
226 -1.).normalized();
227 }
228
229 template<typename DataPoint>
230 inline typename std::enable_if<! Ponca::hasNormal<DataPoint>::value, void>::type
231 getParaboloidNormal(DataPoint& in,
232 typename DataPoint::Scalar _a,
233 typename DataPoint::Scalar _b,
234 typename DataPoint::Scalar _c,
235 typename DataPoint::Scalar _d,
236 typename DataPoint::Scalar _e,
237 typename DataPoint::Scalar _f)
238 { }
239 }
240
245 template<typename DataPoint>
246 [[nodiscard]] DataPoint getPointOnParaboloid(
247 const typename DataPoint::Scalar _a,
248 const typename DataPoint::Scalar _b,
249 const typename DataPoint::Scalar _s,
250 const bool _bAddNoise = true
251 ) {
252 typedef typename DataPoint::Scalar Scalar;
253 typedef typename DataPoint::VectorType VectorType;
254
255 VectorType vNormal;
256 VectorType vPosition;
257
258 const Scalar x = Eigen::internal::random<Scalar>(-_s, _s),
259 y = Eigen::internal::random<Scalar>(-_s, _s);
260
261 vPosition = { x, y, internal::getParaboloidZ(x, y, _a, _b)};
262 vNormal = internal::getParaboloidNormal(vPosition, _a, _b);
263
264 if(_bAddNoise) // spherical noise
265 vPosition += VectorType::Random().normalized() * Eigen::internal::random<Scalar>(Scalar(0), Scalar(1. - MIN_NOISE));
266
267 return DataPoint(vPosition, vNormal);
268 }
269
273 template<typename DataPoint>
274 [[nodiscard]] DataPoint
275 getPointOnParaboloid(typename DataPoint::Scalar _a,
276 typename DataPoint::Scalar _b,
277 typename DataPoint::Scalar _c,
278 typename DataPoint::Scalar _d,
279 typename DataPoint::Scalar _e,
280 typename DataPoint::Scalar _f,
281 typename DataPoint::Scalar _s,
282 bool _bAddNoise = true)
283 {
284 typedef typename DataPoint::Scalar Scalar;
285 typedef typename DataPoint::VectorType VectorType;
286
287 DataPoint out;
288
289 // generate random position in polar coordinates to get points on the circle
290 out.pos() = getPointOnCircle(_s, VectorType({0,0,0}));
291 out.pos().z() = internal::getParaboloidZ(out.pos().x(), out.pos().y(), _a, _b, _c, _d, _e, _f);
292
293 // does nothing if the point type does not have a normal field.
294 internal::getParaboloidNormal(out, _a, _b, _c, _d, _e, _f);
295
296 if(_bAddNoise) //spherical noise
297 {
298 out.pos() += VectorType::Random().normalized() * Eigen::internal::random<Scalar>(Scalar(0), Scalar(1. - MIN_NOISE));
299 }
300
301 return out;
302 }
303
304
305 template<typename DataPoint, typename Params>
306 [[nodiscard]] DataPoint
307 getPointOnParaboloid(const Params &_params,
308 typename DataPoint::Scalar _s,
309 bool _bAddNoise = true)
310 {
311 return getPointOnParaboloid<DataPoint>(_params(0), _params(1), _params(2),
312 _params(3), _params(4), _params(5), _s, _bAddNoise);
313 }
314
316 template<typename DataPoint>
317 [[nodiscard]] DataPoint getRandomPoint() {
318 typedef typename DataPoint::VectorType VectorType;
319 typedef typename DataPoint::Scalar Scalar;
320 const VectorType n = VectorType::Random().normalized();
321 const VectorType p = n * Eigen::internal::random<Scalar>(MIN_NOISE, MAX_NOISE);
322 return {p, (n + VectorType::Random()*Scalar(0.1)).normalized()};
323 }
324}
VectorType getParaboloidNormal(const VectorType &in, const typename VectorType::Scalar _a, const typename VectorType::Scalar _b)
Generate z value using the equation z = ax^2 + by^2.
Scalar getParaboloidZ(const Scalar _x, const Scalar _y, const Scalar _a, const Scalar _b)
Generate z value using the equation z = ax^2 + by^2.
This Source Code Form is subject to the terms of the Mozilla Public License, v.
DataPoint getPointOnPlane(const typename DataPoint::VectorType _vPosition, const typename DataPoint::VectorType _vNormal, const typename DataPoint::Scalar _radius, const bool _bAddPositionNoise=true, const bool _bAddNormalNoise=true, const bool _bReverseNormals=false)
Generate points on a plane.
DataPoint getPointOnParaboloid(const typename DataPoint::Scalar _a, const typename DataPoint::Scalar _b, const typename DataPoint::Scalar _s, const bool _bAddNoise=true)
Generate point samples on the primitive z = ax^2 + by^2.
DataPoint getRandomPoint()
Generate a random points.
DataPoint getPointOnSphere(const typename DataPoint::Scalar _radius, const typename DataPoint::VectorType _vCenter, const bool _bAddPositionNoise=true, const bool _bAddNormalNoise=true, const bool _bReverseNormals=false)
Generate points on a sphere.
DataPoint getPointOnRectangularPlane(const typename DataPoint::VectorType &_vPosition, const typename DataPoint::VectorType &, const typename DataPoint::Scalar &_width, const typename DataPoint::Scalar &_height, const typename DataPoint::VectorType &_localxAxis, const typename DataPoint::VectorType &_localyAxis, const bool _bAddPositionNoise=true)
Generate points on a plane without normals.
VectorType getPointOnCircle(typename VectorType::Scalar _radius, VectorType _vCenter)
Sample points on a circle in the xy plane.