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