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. :-)
19 #include "constructionline.h"
21 #include "graphicview.h"
22 #include "information.h"
23 #include "linetypepattern.h"
24 #include "paintinterface.h"
27 * Default constructor.
29 Circle::Circle(EntityContainer * parent, const CircleData & d):
30 AtomicEntity(parent), data(d)
35 /*virtual*/ Circle::~Circle()
39 /*virtual*/ Entity * Circle::clone()
41 Circle * c = new Circle(*this);
46 /** @return RS2::EntityCircle */
47 /*virtual*/ RS2::EntityType Circle::rtti() const
49 return RS2::EntityCircle;
53 /*virtual*/ bool Circle::isEdge() const
58 /** @return Copy of data that defines the circle. **/
59 CircleData Circle::getData()
64 VectorSolutions Circle::getRefPoints()
66 Vector v1(data.radius, 0.0);
67 Vector v2(0.0, data.radius);
69 VectorSolutions ret(data.center, data.center + v1, data.center + v2, data.center - v1, data.center - v2);
73 /*virtual*/ Vector Circle::getStartpoint() const
75 return data.center + Vector(data.radius, 0.0);
78 /*virtual*/ Vector Circle::getEndpoint() const
80 return data.center + Vector(data.radius, 0.0);
84 * @return Direction 1. The angle at which the arc starts at
87 double Circle::getDirection1() const
93 * @return Direction 2. The angle at which the arc starts at
96 double Circle::getDirection2() const
98 return M_PI / 2.0 * 3.0;
101 /** @return The center point (x) of this arc */
102 Vector Circle::getCenter()
107 /** Sets new center. */
108 void Circle::setCenter(const Vector & c)
113 /** @return The radius of this arc */
114 double Circle::getRadius()
119 /** Sets new radius. */
120 void Circle::setRadius(double r)
125 void Circle::calculateBorders()
127 Vector r(data.radius, data.radius, 0.0);
128 minV = data.center - r;
129 maxV = data.center + r;
133 * @return Angle length in rad.
135 double Circle::getAngleLength() const
141 * @return Length of the circle which is the circumference.
143 double Circle::getLength()
145 return 2 * M_PI * data.radius;
149 * Creates this circle from a center point and a radius.
154 bool Circle::createFromCR(const Vector & c, double r)
156 if (fabs(r) > RS_TOLERANCE)
158 data.radius = fabs(r);
164 DEBUG->print(Debug::D_WARNING, "Circle::createFromCR(): "
165 "Cannot create a circle with radius 0.0.");
171 * Creates this circle from two opposite points.
173 * @param p1 1st point.
174 * @param p2 2nd point.
176 bool Circle::createFrom2P(const Vector & p1, const Vector & p2)
178 if (p1.distanceTo(p2) > RS_TOLERANCE)
180 data.radius = p1.distanceTo(p2) / 2.0;
181 data.center = p1 + (p2 - p1) / 2.0;
186 DEBUG->print(Debug::D_WARNING, "Circle::createFrom2P(): "
187 "Cannot create a circle with radius 0.0.");
193 * Creates this circle from 3 given points which define the circle line.
195 * @param p1 1st point.
196 * @param p2 2nd point.
197 * @param p3 3rd point.
199 bool Circle::createFrom3P(const Vector & p1, const Vector & p2, const Vector & p3)
201 if (p1.distanceTo(p2) > RS_TOLERANCE
202 && p2.distanceTo(p3) > RS_TOLERANCE
203 && p3.distanceTo(p1) > RS_TOLERANCE)
205 // middle points between 3 points:
210 // intersection of two middle lines
211 mp1 = (p1 + p2) / 2.0;
212 a1 = p1.angleTo(p2) + M_PI / 2.0;
213 dir1.setPolar(100.0, a1);
214 mp2 = (p2 + p3) / 2.0;
215 a2 = p2.angleTo(p3) + M_PI / 2.0;
216 dir2.setPolar(100.0, a2);
218 ConstructionLineData d1(mp1, mp1 + dir1);
219 ConstructionLineData d2(mp2, mp2 + dir2);
220 ConstructionLine midLine1(NULL, d1);
221 ConstructionLine midLine2(NULL, d2);
223 VectorSolutions sol =
224 Information::getIntersection(&midLine1, &midLine2);
226 data.center = sol.get(0);
227 data.radius = data.center.distanceTo(p3);
229 if (sol.get(0).valid && data.radius < 1.0e14 && data.radius > RS_TOLERANCE)
233 DEBUG->print(Debug::D_WARNING, "Circle::createFrom3P(): "
234 "Cannot create a circle with inf radius.");
240 DEBUG->print(Debug::D_WARNING, "Circle::createFrom3P(): "
241 "Cannot create a circle with radius 0.0.");
247 * @return Always an invalid vector.
249 Vector Circle::getNearestEndpoint(const Vector & /*coord*/, double * dist)
252 *dist = RS_MAXDOUBLE;
253 return Vector(false);
256 Vector Circle::getNearestPointOnEntity(const Vector & coord, bool /*onEntity*/, double * dist, Entity ** entity)
263 double angle = (coord - data.center).angle();
264 vec.setPolar(data.radius, angle);
268 *dist = fabs((vec - data.center).magnitude() - data.radius);
273 Vector Circle::getNearestCenter(const Vector & coord, double * dist)
276 *dist = coord.distanceTo(data.center);
280 Vector Circle::getNearestMiddle(const Vector & /*coord*/, double * dist)
283 *dist = RS_MAXDOUBLE;
284 return Vector(false);
287 Vector Circle::getNearestDist(double /*distance*/, const Vector & /*coord*/, double * dist)
290 *dist = RS_MAXDOUBLE;
291 return Vector(false);
294 Vector Circle::getNearestDist(double /*distance*/, bool /*startp*/)
296 return Vector(false);
299 double Circle::getDistanceToPoint(const Vector & coord, Entity * * entity, RS2::ResolveLevel, double)
304 return fabs((coord - data.center).magnitude() - data.radius);
307 void Circle::move(Vector offset)
309 data.center.move(offset);
313 void Circle::rotate(Vector center, double angle)
315 data.center.rotate(center, angle);
319 void Circle::scale(Vector center, Vector factor)
321 data.center.scale(center, factor);
322 data.radius *= factor.x;
326 void Circle::mirror(Vector axisPoint1, Vector axisPoint2)
328 data.center.mirror(axisPoint1, axisPoint2);
332 void Circle::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
334 if (painter == NULL || view == NULL)
337 // simple style-less lines
338 if (getPen().getLineType() == RS2::SolidLine
340 || view->getDrawingMode() == RS2::ModePreview)
342 painter->drawArc(view->toGui(getCenter()),
343 getRadius() * view->getFactor().x,
348 double styleFactor = getStyleFactor(view);
350 if (styleFactor < 0.0)
352 painter->drawArc(view->toGui(getCenter()),
353 getRadius() * view->getFactor().x,
360 LineTypePattern * pat;
363 pat = &patternSelected;
365 pat = view->getPattern(getPen().getLineType());
370 if (getRadius() < 1.0e-6)
373 // Pen to draw pattern is always solid:
374 Pen pen = painter->getPen();
375 pen.setLineType(RS2::SolidLine);
376 painter->setPen(pen);
378 double * da; // array of distances in x.
379 int i; // index counter
381 double length = getAngleLength();
384 da = new double[pat->num];
386 for (i = 0; i < pat->num; ++i)
387 da[i] = fabs(pat->pattern[i] * styleFactor) / getRadius();
393 //double cx = getCenter().x * factor.x + offsetX;
394 //double cy = - a->getCenter().y * factor.y + getHeight() - offsetY;
395 Vector cp = view->toGui(getCenter());
396 double r = getRadius() * view->getFactor().x;
400 if (pat->pattern[i] * styleFactor > 0.0)
402 if (tot + fabs(da[i]) < length)
403 painter->drawArc(cp, r,
408 painter->drawArc(cp, r,
428 void Circle::moveRef(const Vector & ref, const Vector & offset)
430 Vector v1(data.radius, 0.0);
431 Vector v2(0.0, data.radius);
433 if (ref.distanceTo(data.center + v1) < 1.0e-4)
434 data.radius = data.center.distanceTo(data.center + v1 + offset);
435 else if (ref.distanceTo(data.center + v2) < 1.0e-4)
436 data.radius = data.center.distanceTo(data.center + v2 + offset);
437 else if (ref.distanceTo(data.center - v1) < 1.0e-4)
438 data.radius = data.center.distanceTo(data.center - v1 + offset);
439 else if (ref.distanceTo(data.center - v2) < 1.0e-4)
440 data.radius = data.center.distanceTo(data.center - v2 + offset);
444 * Dumps the circle's data to stdout.
446 std::ostream & operator<<(std::ostream & os, const Circle & a)
448 os << " Circle: " << a.data << "\n";