LibreCAD
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
geoellipse.cpp
Go to the documentation of this file.
1 #include "geoellipse.h"
2 
3 #include "math.h"
4 #include <cad/math/lcmath.h>
5 
6 
7 using namespace lc;
8 using namespace geo;
9 
10 Ellipse::Ellipse(const Coordinate& center, const Coordinate& majorP, double minorRadius, double startAngle, double endAngle, bool reversed) :
11  _center(center),
12  _majorP(majorP),
13  _minorRadius(minorRadius),
14  _startAngle(startAngle),
15  _endAngle(endAngle),
16  _isReversed(reversed) {
17 
18 }
19 
20 const Coordinate Ellipse::center() const {
21  return _center;
22 }
23 
24 const Coordinate Ellipse::majorP() const {
25  return _majorP;
26 }
27 
28 double Ellipse::minorRadius() const {
29  return _minorRadius;
30 }
31 
32 double Ellipse::startAngle() const {
33  return _startAngle;
34 }
35 
36 double Ellipse::majorRadius() const {
37  return _majorP.magnitude();
38 }
39 
40 double Ellipse::getAngle() const {
41  return _majorP.angle();
42 }
43 
44 Ellipse Ellipse::geoscale(const Coordinate& center, const Coordinate &factor) const {
45  geo::Coordinate vp1(this->majorP());
46  double a(vp1.magnitude());
47  geo::Coordinate vp2(vp1.x() * 1. / a, vp1.y() * 1. / a);
50 
51  if (isArc()) {
52  startPoint = this->startPoint();
53  endPoint = this->endPoint();
54  }
55 
56  double ct = vp2.x();
57  double ct2 = ct * ct; // cos^2 angle
58  double st = vp2.y();
59  double st2 = 1.0 - ct2; // sin^2 angle
60  double kx2 = factor.x() * factor.x();
61  double ky2 = factor.y() * factor.y();
62  double b = (this->minorRadius() / this->majorP().magnitude()) * a;
63  double cA = 0.5 * a * a * (kx2 * ct2 + ky2 * st2);
64  double cB = 0.5 * b * b * (kx2 * st2 + ky2 * ct2);
65  double cC = a * b * ct * st * (ky2 - kx2);
66  geo::Coordinate vp(cA - cB, cC);
67  geo::Coordinate vp3(a, b);
68  geo::Coordinate vp4(vp3.scale(geo::Coordinate(vp.angle() * 0.5)));
69  geo::Coordinate vp5(vp4.rotate(geo::Coordinate(ct, st)));
70  geo::Coordinate vp6(vp5.scale(factor));
71  double z = cA + cB;
72  double x = vp.magnitude();
73  double ratio = std::sqrt((z - x) / (z + x));
74  double minor_ = vp6.magnitude() * ratio;
75 
76  return Ellipse(this->center().scale(center, factor), vp6,
77  minor_,
78  isArc() ? this->getEllipseAngle(startPoint) : 0.,
79  isArc() ? this->getEllipseAngle(endPoint) : 2.*M_PI);
80 }
81 
82 Ellipse Ellipse::georotate(const geo::Coordinate& rotation_center, const double rotation_angle) const {
83  return Ellipse(center().rotate(rotation_center, rotation_angle),
84  majorP().rotate(rotation_center, rotation_angle),
86 }
87 
88 std::vector<Coordinate> Ellipse::findPotentialNearestPoints(const Coordinate &coord) const {
89  std::vector<Coordinate> pnp;
90  pnp.push_back(this->startPoint());
91  pnp.push_back(this->endPoint());
92 
93  double ellipseAngle = this->getAngle();
94 
95  Coordinate trcoord = coord-_center;
96  trcoord = trcoord.rotate(Coordinate(0, 0), -ellipseAngle);
97 
98  double b = _minorRadius;
99  double a = _majorP.magnitude();
100 
101  double x=trcoord.x(),y=trcoord.y();
102 
103  double twoa2b2=2*(a*a-b*b);
104  double twoax=2*a*x;
105  double twoby=2*b*y;
106  double a0=twoa2b2*twoa2b2;
107  std::vector<double> ce(4,0.);
108  std::vector<double> roots(0,0.);
109 
110  if(a0 > LCTOLERANCE) { // a != b , ellipse
111  ce[0]=-2.*twoax/twoa2b2;
112  ce[1]= (twoax*twoax+twoby*twoby)/a0-1.;
113  ce[2]= - ce[0];
114  ce[3]= -twoax*twoax/a0;
115  //std::cout<<"1::find cosine, variable c, solve(c^4 +("<<ce[0]<<")*c^3+("<<ce[1]<<")*c^2+("<<ce[2]<<")*c+("<<ce[3]<<")=0,c)\n";
116  roots=Math::quarticSolver(ce);
117  } else {//a=b, quadratic equation for circle
118  a0=twoby/twoax;
119  roots.push_back(sqrt(1./(1.+a0*a0)));
120  roots.push_back(-roots[0]);
121  }
122 
123  if(roots.size() == 0) {
124  //this should not happen
125  std::cout<<"(a= "<<a<<" b= "<<b<<" x= "<<x<<" y= "<<y<<" )\n";
126  std::cout<<"finding minimum for ("<<x<<"-"<<a<<"*cos(t))^2+("<<y<<"-"<<b<<"*sin(t))^2\n";
127  std::cout<<"2::find cosine, variable c, solve(c^4 +("<<ce[0]<<")*c^3+("<<ce[1]<<")*c^2+("<<ce[2]<<")*c+("<<ce[3]<<")=0,c)\n";
128  std::cout<<ce[0]<<' '<<ce[1]<<' '<<ce[2]<<' '<<ce[3]<<std::endl;
129  std::cerr<<"lcmath::geoellipse::findPotentialNearestPoints() finds no root from quartic, this should not happen\n";
130  return pnp;
131  }
132 
133 
134  for(size_t i=0; i<roots.size(); i++) {
135  double const s=twoby*roots[i]/(twoax-twoa2b2*roots[i]); //sine
136  double const d2=twoa2b2+(twoax-2.*roots[i]*twoa2b2)*roots[i]+twoby*s;
137  if (d2<0) continue; // fartherest
138  Coordinate t(a*roots[i], b*s);
139  //double d=(t-trcoord).magnitude();
140  //double angle = atan2(roots[i],s);
141  // std::cout<<i<<" Find Point: cos= "<<roots[i]<<" sin= "<<s<<" angle= "<<angle<<" ds2= "<<d<<" d="<<d2<<std::endl;
142  t = t.rotate(ellipseAngle);
143  t = t + _center;
144  pnp.push_back(t);
145  }
146  return pnp;
147 }
148 
150  Coordinate res;
151  auto minDist = DBL_MAX;
152  std::vector<Coordinate> potencialPoinst = this->findPotentialNearestPoints(coord);
153 
154  for (auto& verifiedPoint: potencialPoinst)
155  {
156  double d = verifiedPoint.distanceTo(coord);
157  if (d<minDist)
158  {
159  minDist = verifiedPoint.distanceTo(coord);
160  res = verifiedPoint;
161  }
162  };
163 
164  return res;
165 }
166 
168  Coordinate res;
169  double minDist = DBL_MAX;
170  std::vector<Coordinate> potencialPoinst = this->findPotentialNearestPoints(coord);
171 
172 
173  for (auto verifiedPoint: potencialPoinst)
174  {
175  if (this->isAngleBetween(verifiedPoint.angle()))
176  {
177  double d = verifiedPoint.distanceTo(coord);
178  if (d<minDist)
179  {
180  minDist = verifiedPoint.distanceTo(coord);
181  res = verifiedPoint;
182  }
183  }
184  };
185 
186  return res;
187 }
188 
189 double Ellipse::endAngle() const {
190  return _endAngle;
191 }
192 
193 Coordinate Ellipse::getPoint(const double& angle) const {
194  const double a = majorP().magnitude();
195  const double b = minorRadius();
196  return _center + Coordinate(a * cos(angle), b * sin(angle)).rotate(Coordinate(0., 0.), majorP().angle());
197 }
198 
200  return getPoint(startAngle());
201 }
203  return getPoint(endAngle());
204 }
205 
206 bool Ellipse::isReversed() const {
207  return _isReversed;
208 }
209 
210 double Ellipse::ratio() const {
211  return _majorP.magnitude() / _minorRadius;
212 }
213 
214 bool Ellipse::isArc() const {
216 }
217 
218 double Ellipse::getEllipseAngle(const Coordinate& coord) const {
219  Coordinate offset = coord - _center;
220  Coordinate point = offset.rotate(-_majorP.angle());
221  return atan2(point.y() * _majorP.magnitude(), point.x() * _minorRadius);
222 }
static double getAngleDifferenceShort(double a1, double a2, bool CCW)
getAngleDifference, Angle difference between 2 angles
Definition: lcmath.cpp:41
bool isReversed() const
Definition: geoellipse.cpp:206
double startAngle() const
startAngle, Returns Start elliptic!! angle of ellipse
Definition: geoellipse.cpp:32
double x() const
Returns x of Coordinate.
Definition: geocoordinate.h:26
#define LCARCTOLERANCE
Definition: const.h:7
Coordinate startPoint() const
startPoint, start point of ellipse
Definition: geoellipse.cpp:199
double getEllipseAngle(const Coordinate &coord) const
getEllipseAngle
Definition: geoellipse.cpp:218
const double _startAngle
Definition: geoellipse.h:175
Ellipse geoscale(const Coordinate &center, const Coordinate &factor) const
scale an ellipse at some center by some factor
Definition: geoellipse.cpp:44
const double _minorRadius
Definition: geoellipse.h:174
bool isArc() const
isArc
Definition: geoellipse.cpp:214
double y() const
Returns y of Coordinate.
Definition: geocoordinate.h:34
Coordinate scale(const double &scale_factor) const
Ellipse(const Coordinate &center, const Coordinate &majorP, double minorRadius, double startAngle, double endAngle, bool reversed=false)
Definition: geoellipse.cpp:10
double magnitude() const
const Coordinate _majorP
Definition: geoellipse.h:173
double ratio() const
ratio of major radius to minor radius
Definition: geoellipse.cpp:210
const double _endAngle
Definition: geoellipse.h:176
Definition: cadentity.h:12
Coordinate nearestPointOnPath(const Coordinate &coord) const
nearestPointOnPath, (ignore if it arc)
Definition: geoellipse.cpp:149
Coordinate rotate(const Coordinate &angleVector) const
rotate around (0.,0.) with a given angle vector
const Coordinate _center
Definition: geoellipse.h:172
Ellipse georotate(const Coordinate &center, const double rotation_angle) const
rotate an ellipse at a center by an angle
Definition: geoellipse.cpp:82
const bool _isReversed
Definition: geoellipse.h:177
#define LCTOLERANCE
Definition: const.h:6
Coordinate getPoint(const double &angle) const
getPoint, return a point on ellipse with given elliptic angle
Definition: geoellipse.cpp:193
double majorRadius() const
Major Radius.
Definition: geoellipse.cpp:36
#define M_PI
Definition: const.h:16
double getAngle() const
getAngle of MajorP
Definition: geoellipse.cpp:40
double endAngle() const
endAngle, Return the end elliptic!! angle of ellipse
Definition: geoellipse.cpp:189
Coordinate endPoint() const
endPoint, end point of ellipse
Definition: geoellipse.cpp:202
std::vector< Coordinate > findPotentialNearestPoints(const Coordinate &coord) const
findPotentialNearestPoints
Definition: geoellipse.cpp:88
static std::vector< double > quarticSolver(const std::vector< double > &ce)
Definition: lcmath.cpp:127
const Coordinate center() const
center, Returns Center point of Ellipse
Definition: geoellipse.cpp:20
double angle() const
double minorRadius() const
minorRadius, Returns the minor radius of ellipse
Definition: geoellipse.cpp:28
Coordinate nearestPointOnEntity(const Coordinate &coord) const
nearestPointOnEntity, ( not ignore arc)
Definition: geoellipse.cpp:167
const Coordinate majorP() const
majorP, Returns major point of the ellipse, relative to center
Definition: geoellipse.cpp:24
bool isAngleBetween(double angle) const
Definition: geoellipse.h:127