3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 05/28/2010 Added this text. :-)
17 #include "rs_circle.h"
19 #include "rs_constructionline.h"
20 #include "rs_information.h"
21 #include "rs_linetypepattern.h"
22 #include "graphicview.h"
23 #include "paintinterface.h"
26 * Default constructor.
28 RS_Circle::RS_Circle(RS_EntityContainer * parent, const RS_CircleData & d):
29 RS_AtomicEntity(parent), data(d)
34 /*virtual*/ RS_Circle::~RS_Circle()
38 /*virtual*/ RS_Entity * RS_Circle::clone()
40 RS_Circle * c = new RS_Circle(*this);
45 /** @return RS2::EntityCircle */
46 /*virtual*/ RS2::EntityType RS_Circle::rtti() const
48 return RS2::EntityCircle;
52 /*virtual*/ bool RS_Circle::isEdge() const
57 /** @return Copy of data that defines the circle. **/
58 RS_CircleData RS_Circle::getData()
63 VectorSolutions RS_Circle::getRefPoints()
65 Vector v1(data.radius, 0.0);
66 Vector v2(0.0, data.radius);
68 VectorSolutions ret(data.center, data.center + v1, data.center + v2, data.center - v1, data.center - v2);
72 /*virtual*/ Vector RS_Circle::getStartpoint() const
74 return data.center + Vector(data.radius, 0.0);
77 /*virtual*/ Vector RS_Circle::getEndpoint() const
79 return data.center + Vector(data.radius, 0.0);
83 * @return Direction 1. The angle at which the arc starts at
86 double RS_Circle::getDirection1() const
92 * @return Direction 2. The angle at which the arc starts at
95 double RS_Circle::getDirection2() const
97 return M_PI / 2.0 * 3.0;
100 /** @return The center point (x) of this arc */
101 Vector RS_Circle::getCenter()
106 /** Sets new center. */
107 void RS_Circle::setCenter(const Vector & c)
112 /** @return The radius of this arc */
113 double RS_Circle::getRadius()
118 /** Sets new radius. */
119 void RS_Circle::setRadius(double r)
124 void RS_Circle::calculateBorders()
126 Vector r(data.radius, data.radius, 0.0);
127 minV = data.center - r;
128 maxV = data.center + r;
132 * @return Angle length in rad.
134 double RS_Circle::getAngleLength() const
140 * @return Length of the circle which is the circumference.
142 double RS_Circle::getLength()
144 return 2 * M_PI * data.radius;
148 * Creates this circle from a center point and a radius.
153 bool RS_Circle::createFromCR(const Vector & c, double r)
155 if (fabs(r) > RS_TOLERANCE)
157 data.radius = fabs(r);
163 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFromCR(): "
164 "Cannot create a circle with radius 0.0.");
170 * Creates this circle from two opposite points.
172 * @param p1 1st point.
173 * @param p2 2nd point.
175 bool RS_Circle::createFrom2P(const Vector & p1, const Vector & p2)
177 if (p1.distanceTo(p2) > RS_TOLERANCE)
179 data.radius = p1.distanceTo(p2) / 2.0;
180 data.center = p1 + (p2 - p1) / 2.0;
185 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom2P(): "
186 "Cannot create a circle with radius 0.0.");
192 * Creates this circle from 3 given points which define the circle line.
194 * @param p1 1st point.
195 * @param p2 2nd point.
196 * @param p3 3rd point.
198 bool RS_Circle::createFrom3P(const Vector & p1, const Vector & p2, const Vector & p3)
200 if (p1.distanceTo(p2) > RS_TOLERANCE
201 && p2.distanceTo(p3) > RS_TOLERANCE
202 && p3.distanceTo(p1) > RS_TOLERANCE)
204 // middle points between 3 points:
209 // intersection of two middle lines
210 mp1 = (p1 + p2) / 2.0;
211 a1 = p1.angleTo(p2) + M_PI / 2.0;
212 dir1.setPolar(100.0, a1);
213 mp2 = (p2 + p3) / 2.0;
214 a2 = p2.angleTo(p3) + M_PI / 2.0;
215 dir2.setPolar(100.0, a2);
217 RS_ConstructionLineData d1(mp1, mp1 + dir1);
218 RS_ConstructionLineData d2(mp2, mp2 + dir2);
219 RS_ConstructionLine midLine1(NULL, d1);
220 RS_ConstructionLine midLine2(NULL, d2);
222 VectorSolutions sol =
223 RS_Information::getIntersection(&midLine1, &midLine2);
225 data.center = sol.get(0);
226 data.radius = data.center.distanceTo(p3);
228 if (sol.get(0).valid && data.radius < 1.0e14 && data.radius > RS_TOLERANCE)
232 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
233 "Cannot create a circle with inf radius.");
239 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
240 "Cannot create a circle with radius 0.0.");
246 * @return Always an invalid vector.
248 Vector RS_Circle::getNearestEndpoint(const Vector & /*coord*/, double * dist)
251 *dist = RS_MAXDOUBLE;
252 return Vector(false);
255 Vector RS_Circle::getNearestPointOnEntity(const Vector & coord, bool /*onEntity*/, double * dist, RS_Entity ** entity)
262 double angle = (coord - data.center).angle();
263 vec.setPolar(data.radius, angle);
267 *dist = fabs((vec - data.center).magnitude() - data.radius);
272 Vector RS_Circle::getNearestCenter(const Vector & coord, double * dist)
275 *dist = coord.distanceTo(data.center);
279 Vector RS_Circle::getNearestMiddle(const Vector & /*coord*/, double * dist)
282 *dist = RS_MAXDOUBLE;
283 return Vector(false);
286 Vector RS_Circle::getNearestDist(double /*distance*/, const Vector & /*coord*/, double * dist)
289 *dist = RS_MAXDOUBLE;
290 return Vector(false);
293 Vector RS_Circle::getNearestDist(double /*distance*/, bool /*startp*/)
295 return Vector(false);
298 double RS_Circle::getDistanceToPoint(const Vector & coord, RS_Entity * * entity, RS2::ResolveLevel, double)
303 return fabs((coord - data.center).magnitude() - data.radius);
306 void RS_Circle::move(Vector offset)
308 data.center.move(offset);
312 void RS_Circle::rotate(Vector center, double angle)
314 data.center.rotate(center, angle);
318 void RS_Circle::scale(Vector center, Vector factor)
320 data.center.scale(center, factor);
321 data.radius *= factor.x;
325 void RS_Circle::mirror(Vector axisPoint1, Vector axisPoint2)
327 data.center.mirror(axisPoint1, axisPoint2);
331 void RS_Circle::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
333 if (painter == NULL || view == NULL)
336 // simple style-less lines
337 if (getPen().getLineType() == RS2::SolidLine
339 || view->getDrawingMode() == RS2::ModePreview)
341 painter->drawArc(view->toGui(getCenter()),
342 getRadius() * view->getFactor().x,
347 double styleFactor = getStyleFactor(view);
349 if (styleFactor < 0.0)
351 painter->drawArc(view->toGui(getCenter()),
352 getRadius() * view->getFactor().x,
359 RS_LineTypePattern * pat;
362 pat = &patternSelected;
364 pat = view->getPattern(getPen().getLineType());
369 if (getRadius() < 1.0e-6)
372 // Pen to draw pattern is always solid:
373 RS_Pen pen = painter->getPen();
374 pen.setLineType(RS2::SolidLine);
375 painter->setPen(pen);
377 double * da; // array of distances in x.
378 int i; // index counter
380 double length = getAngleLength();
383 da = new double[pat->num];
385 for (i = 0; i < pat->num; ++i)
386 da[i] = fabs(pat->pattern[i] * styleFactor) / getRadius();
392 //double cx = getCenter().x * factor.x + offsetX;
393 //double cy = - a->getCenter().y * factor.y + getHeight() - offsetY;
394 Vector cp = view->toGui(getCenter());
395 double r = getRadius() * view->getFactor().x;
399 if (pat->pattern[i] * styleFactor > 0.0)
401 if (tot + fabs(da[i]) < length)
402 painter->drawArc(cp, r,
407 painter->drawArc(cp, r,
427 void RS_Circle::moveRef(const Vector & ref, const Vector & offset)
429 Vector v1(data.radius, 0.0);
430 Vector v2(0.0, data.radius);
432 if (ref.distanceTo(data.center + v1) < 1.0e-4)
433 data.radius = data.center.distanceTo(data.center + v1 + offset);
434 else if (ref.distanceTo(data.center + v2) < 1.0e-4)
435 data.radius = data.center.distanceTo(data.center + v2 + offset);
436 else if (ref.distanceTo(data.center - v1) < 1.0e-4)
437 data.radius = data.center.distanceTo(data.center - v1 + offset);
438 else if (ref.distanceTo(data.center - v2) < 1.0e-4)
439 data.radius = data.center.distanceTo(data.center - v2 + offset);
443 * Dumps the circle's data to stdout.
445 std::ostream & operator<<(std::ostream & os, const RS_Circle & a)
447 os << " Circle: " << a.data << "\n";