LibreCAD
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
geobezier.cpp
Go to the documentation of this file.
1 #include "geobezier.h"
2 
3 using namespace lc;
4 using namespace geo;
5 
6 Bezier::Bezier(const Coordinate& point_a, const Coordinate& point_b, const Coordinate& point_c)
7  : _pointA(point_a), _pointB(point_b), _pointC(point_c) {
8 }
9 
10 Bezier::Bezier(const Bezier &bez) :
11  _pointA(bez._pointA), _pointB(bez._pointB),
12  _pointC(bez._pointC) {
13 
14 }
15 
16 const std::vector<geo::Coordinate> Bezier::getCP() const {
17  return {_pointA, _pointB, _pointC };
18 }
19 
20 
21 const Area Bezier::boundingBox() const {
22 
23  /*
24  * T = A-B/(A - 2B + C)
25  */
26  auto tx_ = (_pointA.x() - _pointB.x())/(_pointA.x() - (_pointB.x()*2.0) + _pointC.x());
27  auto ty_ = (_pointA.y() - _pointB.y())/(_pointA.y() - (_pointB.y()*2.0) + _pointC.y());
28  std::vector<double> x_{_pointA.x(), _pointC.x() };
29  std::vector<double> y_{_pointA.y(), _pointC.y() };
30 
31  if(tx_ > 0. && tx_ < 1.0) {
32  auto bez1 = DirectValueAt(tx_);
33  x_.push_back(bez1.x());
34  y_.push_back(bez1.y());
35  }
36 
37  if(ty_ > 0. && ty_ < 1.0) {
38  auto bez2 = DirectValueAt(ty_);
39  x_.push_back(bez2.x());
40  y_.push_back(bez2.y());
41  }
42 
43  std::sort(x_.begin(), x_.end());
44  std::sort(y_.begin(), y_.end());
45 
46  return Area(geo::Coordinate(x_.front(), y_.front()), geo::Coordinate (x_.back() ,y_.back()));
47 }
48 
50 
51  /*
52  * Difference between nearest point on path and
53  * nearest point on entity for a bezier curve is that
54  * for calculating the nearest point on entity you check
55  * that if the value of "t" is between 0 and 1
56  * whereas for nearest point on path, you don't check that
57  */
58 
59  auto min_distance = std::numeric_limits<double>::max();
60  Coordinate ret;
61 
62  auto tValues = nearestPointTValue(coord);
63 
64  for (auto val : tValues) {
65  geo::Coordinate point_on_path = DirectValueAt(val);
66  auto raw_distance = coord.distanceTo(point_on_path);
67  if(raw_distance < min_distance) {
68  ret = point_on_path;
69  min_distance = raw_distance;
70  }
71  }
72 
73  return returnCasesForNearestPoint(min_distance, coord, ret);
74 }
75 
77  auto min_distance = std::numeric_limits<double>::max();
78 
79  Coordinate ret;
80 
81  auto tValues = nearestPointTValue(coord);
82 
83  for (auto val : tValues) {
84  if(val > 0 && val < 1) {
85  geo::Coordinate point_on_path = DirectValueAt(val);
86  auto raw_distance = coord.distanceTo(point_on_path);
87  if(raw_distance < min_distance) {
88  ret = point_on_path;
89  min_distance = raw_distance;
90  }
91  }
92  }
93 
94  return returnCasesForNearestPoint(min_distance, coord, ret);
95 }
96 
102 std::vector<double> Bezier::nearestPointTValue(const lc::geo::Coordinate &coord) const {
103  auto pos = _pointA - coord;
104 
105  auto Ax = _pointB.x() - _pointA.x();
106  auto Ay = _pointB.y() - _pointA.y();
107  auto Bx = _pointA.x() - (_pointB.x()*2.0) + _pointC.x();
108  auto By = _pointA.y() - (_pointB.y()*2.0) + _pointC.y();
109 
110  auto a = Bx * Bx + By * By;
111  auto b = (3 * (Ax * Bx + Ay * By)) / a;
112  auto c = (2 * (Ax * Ax + Ay * Ay) + pos.x() * Bx + pos.y() * By) / a;
113  auto d = (pos.x() * Ax + pos.y() * Ay) / a;
114 
115  return lc::Math::cubicSolver({b, c, d});
116 }
117 
118 
128  double min_distance, const lc::geo::Coordinate &coord,
129  const lc::geo::Coordinate &ret) const {
130  auto distance_to_A = coord.distanceTo(_pointA);
131  auto distance_to_C = coord.distanceTo(_pointC);
132 
133  // Point is on curve
134  if(min_distance < distance_to_A && min_distance < distance_to_C) {
135  return ret;
136  }
137  // Point is on starting of Curve
138  if (distance_to_A < distance_to_C) {
139  return _pointA;
140  }
141  // Point is end of curve
142  return _pointC;
143 }
144 
145 Coordinate Bezier::CasteljauAt(std::vector<Coordinate> points, double t) const {
146  if(points.size() == 1) return points.front();
147  else {
148  int size_ = points.size();
149  std::vector<Coordinate> new_vec;
150  for(int i = 1; i < size_; i++) {
151  new_vec.push_back(points[i-1] * (1.0-t) + points[i] * t);
152  }
153  return CasteljauAt(new_vec, t);
154  }
155 }
156 
158  auto one_minus_t = 1 - t;
159  auto t_square = t*t;
160  auto one_minus_t_square = one_minus_t * one_minus_t;
161  auto two_a_b = 2 * one_minus_t * t;
162  return (_pointA * one_minus_t_square) + (_pointB * two_a_b) + (_pointC * t_square);
163 }
164 
165 const std::vector<Coordinate> Bezier::Curve(double precession) {
166  std::vector<Coordinate> v = { _pointA, _pointB, _pointC };
167  std::vector<Coordinate> ret;
168  for(auto i = 0.; i < 1.; i+=precession) {
169  ret.push_back(CasteljauAt(v, i));
170  }
171  return ret;
172 }
173 
174 const double Bezier::length() const {
175 
176  auto Bx = 2*(_pointB.x() - _pointA.x());
177  auto By = 2*(_pointB.y() - _pointA.y());
178  auto Ax = _pointA.x() - (_pointB.x()*2.0) + _pointC.x();
179  auto Ay = _pointA.y() - (_pointB.y()*2.0) + _pointC.y();
180 
181  auto A = 4*(Ax*Ax + Ay*Ay);
182  auto B = 4*(Ax*Bx + Ay*By);
183  auto C = Bx*Bx + By*By;
184 
185  auto Sabc = 2*std::sqrt(A+B+C);
186  auto A_2 = std::sqrt(A);
187  auto A_32 = 2*A*A_2;
188  auto C_2 = 2*std::sqrt(C);
189  auto BA = B/A_2;
190 
191  return ( A_32 * Sabc + A_2 * B * (Sabc - C_2) + (4 * C * A - B * B) * std::log((2* A_2 + BA + Sabc)/(BA + C_2))) / (4 * A_32);
192 }
193 
194 BB_CSPtr Bezier::rotate(const geo::Coordinate& center, double angle) const {
195  auto z = std::make_shared<const Bezier>(_pointA.rotate(center, angle),
196  _pointB.rotate(center, angle),
197  _pointC.rotate(center, angle));
198  return z;
199 }
200 
201 BB_CSPtr Bezier::scale(const geo::Coordinate& center, const geo::Coordinate& factor) const {
202  auto z = std::make_shared<const Bezier>(_pointA.scale(center, factor),
203  _pointB.scale(center, factor),
204  _pointC.scale(center, factor)
205  );
206  return z;
207 }
208 
209 BB_CSPtr Bezier::move(const geo::Coordinate& offset) const {
210  auto z = std::make_shared<const Bezier>(_pointA + offset,
211  _pointB + offset,
212  _pointC + offset
213  );
214  return z;
215 }
216 
217 const Coordinate Bezier::tangent(double t) const {
218  auto Bx = _pointB.x() - _pointA.x();
219  auto By = _pointB.y() - _pointA.y();
220  auto Ax = _pointA.x() - (_pointB.x()*2.0) + _pointC.x();
221  auto Ay = _pointA.y() - (_pointB.y()*2.0) + _pointC.y();
222  auto tanx = Ax * t + Bx;
223  auto tany = Ay * t + By;
224  return Coordinate(tanx, tany);
225 }
226 
227 const Coordinate Bezier::normal(double t) const {
228  auto Bx = _pointB.x() - _pointA.x();
229  auto By = _pointB.y() - _pointA.y();
230  auto Ax = _pointA.x() - (_pointB.x()*2.0) + _pointC.x();
231  auto Ay = _pointA.y() - (_pointB.y()*2.0) + _pointC.y();
232 
233  auto tanx = Ay * t + By;
234  auto tany = -(Ax * t + Bx);
235 
236  auto lNorm = std::sqrt(tanx * tanx + tany * tany);
237 
238  if (lNorm > 0) {
239  tanx /= lNorm;
240  tany /= lNorm;
241  }
242 
243  return Coordinate(tanx, tany);
244 }
245 
246 BB_CSPtr Bezier::mirror(const geo::Coordinate& axis1, const geo::Coordinate& axis2) const {
247  auto z = std::make_shared<const Bezier>(_pointA.mirror(axis1, axis2),
248  _pointB.mirror(axis1, axis2),
249  _pointC.mirror(axis1, axis2)
250  );
251  return z;
252 }
253 
254 std::vector<BB_CSPtr> Bezier::splitHalf() const {
255  auto AB = (_pointA + _pointB) / 2;
256  auto BC = (_pointB + _pointC) / 2;
257  auto D = (AB + BC)/2;
258 
259  BB_CSPtr b1 = std::make_shared<Bezier>(Bezier(_pointA, AB, D));
260  BB_CSPtr b2 = std::make_shared<Bezier>(Bezier(D, BC, _pointC));
261 
262  return {b1, b2};
263 }
264 
266  //auto tx_ = (_pointA.x() - _pointB.x())/(_pointA.x() - (_pointB.x()*2.0) + _pointC.x());
267  //auto ty_ = (_pointA.y() - _pointB.y())/(_pointA.y() - (_pointB.y()*2.0) + _pointC.y());
268 
269 // if(tx_ > 0. && tx_ < 1.0) {
270 // auto bez1 = DirectValueAt(tx_);
271 // x_.push_back(bez1.x());
272 // y_.push_back(bez1.y());
273 // }
274 
275 // if(ty_ > 0. && ty_ < 1.0) {
276 // auto bez2 = DirectValueAt(ty_);
277 // x_.push_back(bez2.x());
278 // y_.push_back(bez2.y());
279 // }
280 
281  return NULL; // TODO: no return statement
282 }
283 
284 BB_CSPtr Bezier::splitAtT(double t) const {
285  auto x1 = _pointA.x();
286  auto y1 = _pointA.y();
287 
288  auto x2 = _pointB.x();
289  auto y2 = _pointB.y();
290 
291  auto x3 = _pointC.x();
292  auto y3 = _pointC.y();
293 
294  auto x12 = (x2-x1)*t+x1;
295  auto y12 = (y2-y1)*t+y1;
296 
297  auto x23 = (x3-x2)*t+x2;
298  auto y23 = (y3-y2)*t+y2;
299 
300  auto x123 = (x23-x12)*t+x12;
301  auto y123 = (y23-y12)*t+y12;
302 
303  return std::make_shared<Bezier>(Bezier({x1, y1}, {x12, y12}, {x123, y123}));
304 }
305 
Coordinate _pointC
Definition: geobezier.h:157
Coordinate mirror(const Coordinate &axis1, const Coordinate &axis2) const
mirror a coordinate
static std::vector< double > cubicSolver(const std::vector< double > &ce)
Definition: lcmath.cpp:102
virtual std::vector< BB_CSPtr > splitHalf() const override
splitHalf Splits the bezier into two halves.
Definition: geobezier.cpp:254
virtual const Coordinate tangent(double t) const override
tangent of the bezeir
Definition: geobezier.cpp:217
double x() const
Returns x of Coordinate.
Definition: geocoordinate.h:26
virtual const std::vector< Coordinate > getCP() const override
getCP Returns the control points of the bezier
Definition: geobezier.cpp:16
virtual Coordinate DirectValueAt(double t) const override
DirectValueAt Coordinate of bezier at time t calculated numerically.
Definition: geobezier.cpp:157
std::vector< double > nearestPointTValue(const Coordinate &coord) const override
Bezier::nearestPointTValue.
Definition: geobezier.cpp:102
virtual BB_CSPtr scale(const geo::Coordinate &center, const geo::Coordinate &factor) const override
scale the bezier at specific center by some factor
Definition: geobezier.cpp:201
double y() const
Returns y of Coordinate.
Definition: geocoordinate.h:34
Coordinate scale(const double &scale_factor) const
virtual Coordinate nearestPointOnPath(const Coordinate &coord) const override
nearestPointOnPath of the bezier
Definition: geobezier.cpp:49
virtual Coordinate CasteljauAt(std::vector< Coordinate > points, double t) const override
CasteljauAt Coordinate of bezier at time t.
Definition: geobezier.cpp:145
Definition: cadentity.h:12
virtual BB_CSPtr rotate(const geo::Coordinate &center, double angle) const override
rotate the bezier at specific center and some angle
Definition: geobezier.cpp:194
const lc::geo::Coordinate returnCasesForNearestPoint(double min_distance, const lc::geo::Coordinate &coord, const Coordinate &ret) const override
Bezier::returnCasesForNearestPoint.
Definition: geobezier.cpp:127
Coordinate _pointB
Definition: geobezier.h:156
Coordinate rotate(const Coordinate &angleVector) const
rotate around (0.,0.) with a given angle vector
Coordinate _pointA
Definition: geobezier.h:155
std::shared_ptr< const BezierBase > BB_CSPtr
Definition: geobezierbase.h:15
virtual BB_CSPtr move(const geo::Coordinate &offset) const override
move the bezeir by some offset
Definition: geobezier.cpp:209
virtual const Coordinate normal(double t) const override
normal of the bezier at time t
Definition: geobezier.cpp:227
virtual BB_CSPtr mirror(const geo::Coordinate &axis1, const geo::Coordinate &axis2) const override
mirror a bezier around a line
Definition: geobezier.cpp:246
virtual Coordinate nearestPointOnEntity(const Coordinate &coord) const override
nearestPointOnEntity of the bezier
Definition: geobezier.cpp:76
double distanceTo(const geo::Coordinate &c) const
virtual BB_CSPtr splitAtT(double t) const override
splitAtT Splits bezier at specific time.
Definition: geobezier.cpp:284
virtual const std::vector< Coordinate > Curve(double precession) override
Curve Creates a bezier curve for drawing with some precession value.
Definition: geobezier.cpp:165
virtual BB_CSPtr offset(const geo::Coordinate &offset) const override
offset offsets the bezier.
Definition: geobezier.cpp:265
Bezier(const Coordinate &point_a, const Coordinate &point_b, const Coordinate &point_c)
Definition: geobezier.cpp:6
virtual const Area boundingBox() const override
boundingBox of the bezier
Definition: geobezier.cpp:21
virtual const double length() const override
length of the Bezier
Definition: geobezier.cpp:174