1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26
27 #include "lc_hyperbola.h"
28
29 #include "rs_graphic.h"
30 #include "rs_graphicview.h"
31 #include "rs_painter.h"
32 #include "rs_information.h"
33 #include "rs_linetypepattern.h"
34 #include "lc_quadratic.h"
35
LC_HyperbolaData(const RS_Vector & _center,const RS_Vector & _majorP,double _ratio,double _angle1,double _angle2,bool _reversed)36 LC_HyperbolaData::LC_HyperbolaData(const RS_Vector& _center,
37 const RS_Vector& _majorP,
38 double _ratio,
39 double _angle1, double _angle2,
40 bool _reversed):
41 center(_center)
42 ,majorP(_majorP)
43 ,ratio(_ratio)
44 ,angle1(_angle1)
45 ,angle2(_angle2)
46 ,reversed(_reversed)
47 {
48 }
49
operator <<(std::ostream & os,const LC_HyperbolaData & ed)50 std::ostream& operator << (std::ostream& os, const LC_HyperbolaData& ed) {
51 os << "(" << ed.center <<
52 "/" << ed.majorP <<
53 " " << ed.ratio <<
54 " " << ed.angle1 <<
55 "," << ed.angle2 <<
56 ")";
57 return os;
58 }
59
60 #ifdef EMU_C99
61 #include "emu_c99.h" /* C99 math */
62 #endif
63
64 /**
65 * Constructor.
66 */
LC_Hyperbola(RS_EntityContainer * parent,const LC_HyperbolaData & d)67 LC_Hyperbola::LC_Hyperbola(RS_EntityContainer* parent,
68 const LC_HyperbolaData& d)
69 :RS_AtomicEntity(parent)
70 ,data(d)
71 ,m_bValid(true)
72 {
73 if(data.majorP.squared()<RS_TOLERANCE2) {
74 m_bValid=false;
75 return;
76 }
77 //calculateEndpoints();
78 calculateBorders();
79 }
80
81 /** create data based on foci and a point on hyperbola */
LC_HyperbolaData(const RS_Vector & focus0,const RS_Vector & focus1,const RS_Vector & point)82 LC_HyperbolaData::LC_HyperbolaData(const RS_Vector& focus0,
83 const RS_Vector& focus1,
84 const RS_Vector& point):
85 center((focus0+focus1)*0.5)
86 {
87 double ds0=focus0.distanceTo(point);
88 ds0 -= focus1.distanceTo(point);
89
90 majorP= (ds0>0.)?focus0-center:focus1-center;
91 double dc=focus0.distanceTo(focus1);
92 double dd=fabs(ds0);
93 //no hyperbola for middle equidistant
94 if(dc<RS_TOLERANCE||dd<RS_TOLERANCE) {
95 majorP.set(0.,0.);
96 return;
97 }
98 ratio= dc/dd;
99 majorP /= ratio;
100 ratio=sqrt(ratio*ratio - 1.);
101
102 }
103
104 ///** create data based on foci and a point on hyperbola */
105 //LC_Hyperbola::LC_Hyperbola(const RS_Vector& focus0,
106 // const RS_Vector& focus1,
107 // const RS_Vector& point):
108 // data(focus0,focus1,point)
109 //{
110 // m_bValid = data.majorP.squared()> RS_TOLERANCE2;
111 //}
112 /**
113 * Recalculates the endpoints using the angles and the radius.
114 */
115 /*
116 void LC_Hyperbola::calculateEndpoints() {
117 double angle = data.majorP.angle();
118 double radius1 = getMajorRadius();
119 double radius2 = getMinorRadius();
120
121 startpoint.set(data.center.x + cos(data.angle1) * radius1,
122 data.center.y + sin(data.angle1) * radius2);
123 startpoint.rotate(data.center, angle);
124 endpoint.set(data.center.x + cos(data.angle2) * radius1,
125 data.center.y + sin(data.angle2) * radius2);
126 endpoint.rotate(data.center, angle);
127 }
128 */
129
130
131 /**
132 * Calculates the boundary box of this ellipse.
133 */
134
135
clone() const136 RS_Entity* LC_Hyperbola::clone() const {
137 LC_Hyperbola* e = new LC_Hyperbola(*this);
138 e->initId();
139 return e;
140 }
141
142
143 /**
144 * return the foci of ellipse
145 *
146 *@Author: Dongxu Li
147 */
148
getFoci() const149 RS_VectorSolutions LC_Hyperbola::getFoci() const {
150 RS_Vector vp(getMajorP()*sqrt(1.-getRatio()*getRatio()));
151 return RS_VectorSolutions({getCenter()+vp, getCenter()-vp});
152 }
153
getRefPoints() const154 RS_VectorSolutions LC_Hyperbola::getRefPoints() const{
155 RS_VectorSolutions ret({data.center});
156 ret.push_back(getFoci());
157 return ret;
158 }
159
isPointOnEntity(const RS_Vector & coord,double tolerance) const160 bool LC_Hyperbola::isPointOnEntity(const RS_Vector& coord,
161 double tolerance) const
162 {
163 double a=data.majorP.magnitude();
164 double b=a*data.ratio;
165 if(fabs(a)<tolerance || fabs(b)<tolerance) return false;
166 RS_Vector vp(coord - data.center);
167 vp=vp.rotate(-data.majorP.angle());
168 return fabs( vp.x*vp.x/(a*a)- vp.y*vp.y/(b*b) -1.)<tolerance;
169 }
170
171
getQuadratic() const172 LC_Quadratic LC_Hyperbola::getQuadratic() const
173 {
174 std::vector<double> ce(6,0.);
175 ce[0]=data.majorP.squared();
176 ce[2]=-data.ratio*data.ratio*ce[0];
177 if(ce[0]>RS_TOLERANCE2) ce[0]=1./ce[0];
178 if(fabs(ce[2])>RS_TOLERANCE2) ce[2]=1./ce[2];
179 ce[5]=-1.;
180 LC_Quadratic ret(ce);
181 if(ce[0]<RS_TOLERANCE2 || fabs(ce[2])<RS_TOLERANCE2) {
182 ret.setValid(false);
183 return ret;
184 }
185 ret.rotate(data.majorP.angle());
186 ret.move(data.center);
187 return ret;
188 }
189
190 //RS_Vector LC_Hyperbola::getNearestEndpoint(const RS_Vector& /*coord*/,
191 // double* /*dist*/ = NULL) const
192 //{
193 //}
194
195 /**
196 * Dumps the point's data to stdout.
197 */
operator <<(std::ostream & os,const LC_Hyperbola & a)198 std::ostream& operator << (std::ostream& os, const LC_Hyperbola& a) {
199 os << " Hyperbola: " << a.data << "\n";
200 return os;
201 }
202
203