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 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/28/2010 Added this text. :-)
15 #include "rs_circle.h"
17 #include "rs_constructionline.h"
18 #include "rs_information.h"
19 #include "rs_linetypepattern.h"
20 #include "graphicview.h"
21 #include "paintinterface.h"
24 * Default constructor.
26 RS_Circle::RS_Circle(RS_EntityContainer * parent, const RS_CircleData & d):
27 RS_AtomicEntity(parent), data(d)
32 /*virtual*/ RS_Circle::~RS_Circle()
36 /*virtual*/ RS_Entity * RS_Circle::clone()
38 RS_Circle * c = new RS_Circle(*this);
43 /** @return RS2::EntityCircle */
44 /*virtual*/ RS2::EntityType RS_Circle::rtti() const
46 return RS2::EntityCircle;
50 /*virtual*/ bool RS_Circle::isEdge() const
55 /** @return Copy of data that defines the circle. **/
56 RS_CircleData RS_Circle::getData()
61 VectorSolutions RS_Circle::getRefPoints()
63 Vector v1(data.radius, 0.0);
64 Vector v2(0.0, data.radius);
66 VectorSolutions ret(data.center, data.center + v1, data.center + v2, data.center - v1, data.center - v2);
70 /*virtual*/ Vector RS_Circle::getStartpoint() const
72 return data.center + Vector(data.radius, 0.0);
75 /*virtual*/ Vector RS_Circle::getEndpoint() const
77 return data.center + Vector(data.radius, 0.0);
81 * @return Direction 1. The angle at which the arc starts at
84 double RS_Circle::getDirection1() const
90 * @return Direction 2. The angle at which the arc starts at
93 double RS_Circle::getDirection2() const
95 return M_PI / 2.0 * 3.0;
98 /** @return The center point (x) of this arc */
99 Vector RS_Circle::getCenter()
104 /** Sets new center. */
105 void RS_Circle::setCenter(const Vector & c)
110 /** @return The radius of this arc */
111 double RS_Circle::getRadius()
116 /** Sets new radius. */
117 void RS_Circle::setRadius(double r)
122 void RS_Circle::calculateBorders()
124 Vector r(data.radius, data.radius, 0.0);
125 minV = data.center - r;
126 maxV = data.center + r;
130 * @return Angle length in rad.
132 double RS_Circle::getAngleLength() const
138 * @return Length of the circle which is the circumference.
140 double RS_Circle::getLength()
142 return 2 * M_PI * data.radius;
146 * Creates this circle from a center point and a radius.
151 bool RS_Circle::createFromCR(const Vector & c, double r)
153 if (fabs(r) > RS_TOLERANCE)
155 data.radius = fabs(r);
161 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFromCR(): "
162 "Cannot create a circle with radius 0.0.");
168 * Creates this circle from two opposite points.
170 * @param p1 1st point.
171 * @param p2 2nd point.
173 bool RS_Circle::createFrom2P(const Vector & p1, const Vector & p2)
175 if (p1.distanceTo(p2) > RS_TOLERANCE)
177 data.radius = p1.distanceTo(p2) / 2.0;
178 data.center = p1 + (p2 - p1) / 2.0;
183 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom2P(): "
184 "Cannot create a circle with radius 0.0.");
190 * Creates this circle from 3 given points which define the circle line.
192 * @param p1 1st point.
193 * @param p2 2nd point.
194 * @param p3 3rd point.
196 bool RS_Circle::createFrom3P(const Vector & p1, const Vector & p2, const Vector & p3)
198 if (p1.distanceTo(p2) > RS_TOLERANCE
199 && p2.distanceTo(p3) > RS_TOLERANCE
200 && p3.distanceTo(p1) > RS_TOLERANCE)
202 // middle points between 3 points:
207 // intersection of two middle lines
208 mp1 = (p1 + p2) / 2.0;
209 a1 = p1.angleTo(p2) + M_PI / 2.0;
210 dir1.setPolar(100.0, a1);
211 mp2 = (p2 + p3) / 2.0;
212 a2 = p2.angleTo(p3) + M_PI / 2.0;
213 dir2.setPolar(100.0, a2);
215 RS_ConstructionLineData d1(mp1, mp1 + dir1);
216 RS_ConstructionLineData d2(mp2, mp2 + dir2);
217 RS_ConstructionLine midLine1(NULL, d1);
218 RS_ConstructionLine midLine2(NULL, d2);
220 VectorSolutions sol =
221 RS_Information::getIntersection(&midLine1, &midLine2);
223 data.center = sol.get(0);
224 data.radius = data.center.distanceTo(p3);
226 if (sol.get(0).valid && data.radius < 1.0e14 && data.radius > RS_TOLERANCE)
230 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
231 "Cannot create a circle with inf radius.");
237 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
238 "Cannot create a circle with radius 0.0.");
244 * @return Always an invalid vector.
246 Vector RS_Circle::getNearestEndpoint(const Vector & /*coord*/, double * dist)
249 *dist = RS_MAXDOUBLE;
250 return Vector(false);
253 Vector RS_Circle::getNearestPointOnEntity(const Vector & coord, bool /*onEntity*/, double * dist, RS_Entity ** entity)
260 double angle = (coord - data.center).angle();
261 vec.setPolar(data.radius, angle);
265 *dist = fabs((vec - data.center).magnitude() - data.radius);
270 Vector RS_Circle::getNearestCenter(const Vector & coord, double * dist)
273 *dist = coord.distanceTo(data.center);
277 Vector RS_Circle::getNearestMiddle(const Vector & /*coord*/, double * dist)
280 *dist = RS_MAXDOUBLE;
281 return Vector(false);
284 Vector RS_Circle::getNearestDist(double /*distance*/, const Vector & /*coord*/, double * dist)
287 *dist = RS_MAXDOUBLE;
288 return Vector(false);
291 Vector RS_Circle::getNearestDist(double /*distance*/, bool /*startp*/)
293 return Vector(false);
296 double RS_Circle::getDistanceToPoint(const Vector & coord, RS_Entity * * entity, RS2::ResolveLevel, double)
301 return fabs((coord - data.center).magnitude() - data.radius);
304 void RS_Circle::move(Vector offset)
306 data.center.move(offset);
310 void RS_Circle::rotate(Vector center, double angle)
312 data.center.rotate(center, angle);
316 void RS_Circle::scale(Vector center, Vector factor)
318 data.center.scale(center, factor);
319 data.radius *= factor.x;
323 void RS_Circle::mirror(Vector axisPoint1, Vector axisPoint2)
325 data.center.mirror(axisPoint1, axisPoint2);
329 void RS_Circle::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
331 if (painter == NULL || view == NULL)
334 // simple style-less lines
335 if (getPen().getLineType() == RS2::SolidLine
337 || view->getDrawingMode() == RS2::ModePreview)
339 painter->drawArc(view->toGui(getCenter()),
340 getRadius() * view->getFactor().x,
345 double styleFactor = getStyleFactor(view);
347 if (styleFactor < 0.0)
349 painter->drawArc(view->toGui(getCenter()),
350 getRadius() * view->getFactor().x,
357 RS_LineTypePattern * pat;
360 pat = &patternSelected;
362 pat = view->getPattern(getPen().getLineType());
367 if (getRadius() < 1.0e-6)
370 // Pen to draw pattern is always solid:
371 RS_Pen pen = painter->getPen();
372 pen.setLineType(RS2::SolidLine);
373 painter->setPen(pen);
375 double * da; // array of distances in x.
376 int i; // index counter
378 double length = getAngleLength();
381 da = new double[pat->num];
383 for (i = 0; i < pat->num; ++i)
384 da[i] = fabs(pat->pattern[i] * styleFactor) / getRadius();
390 //double cx = getCenter().x * factor.x + offsetX;
391 //double cy = - a->getCenter().y * factor.y + getHeight() - offsetY;
392 Vector cp = view->toGui(getCenter());
393 double r = getRadius() * view->getFactor().x;
397 if (pat->pattern[i] * styleFactor > 0.0)
399 if (tot + fabs(da[i]) < length)
400 painter->drawArc(cp, r,
405 painter->drawArc(cp, r,
425 void RS_Circle::moveRef(const Vector & ref, const Vector & offset)
427 Vector v1(data.radius, 0.0);
428 Vector v2(0.0, data.radius);
430 if (ref.distanceTo(data.center + v1) < 1.0e-4)
431 data.radius = data.center.distanceTo(data.center + v1 + offset);
432 else if (ref.distanceTo(data.center + v2) < 1.0e-4)
433 data.radius = data.center.distanceTo(data.center + v2 + offset);
434 else if (ref.distanceTo(data.center - v1) < 1.0e-4)
435 data.radius = data.center.distanceTo(data.center - v1 + offset);
436 else if (ref.distanceTo(data.center - v2) < 1.0e-4)
437 data.radius = data.center.distanceTo(data.center - v2 + offset);
441 * Dumps the circle's data to stdout.
443 std::ostream & operator<<(std::ostream & os, const RS_Circle & a)
445 os << " Circle: " << a.data << "\n";