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_graphicview.h"
20 #include "paintintf.h"
23 * Default constructor.
25 RS_Circle::RS_Circle(RS_EntityContainer * parent, const RS_CircleData & d):
26 RS_AtomicEntity(parent), data(d)
31 void RS_Circle::calculateBorders()
33 Vector r(data.radius,data.radius,0.0);
34 minV = data.center - r;
35 maxV = data.center + r;
39 * @return Angle length in rad.
41 double RS_Circle::getAngleLength() const {
48 * @return Length of the circle which is the circumference.
50 double RS_Circle::getLength() {
51 return 2*M_PI*data.radius;
56 * Creates this circle from a center point and a radius.
61 bool RS_Circle::createFromCR(const Vector& c, double r) {
62 if (fabs(r)>RS_TOLERANCE) {
63 data.radius = fabs(r);
67 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFromCR(): "
68 "Cannot create a circle with radius 0.0.");
76 * Creates this circle from two opposite points.
78 * @param p1 1st point.
79 * @param p2 2nd point.
81 bool RS_Circle::createFrom2P(const Vector& p1, const Vector& p2) {
82 if (p1.distanceTo(p2)>RS_TOLERANCE) {
83 data.radius = p1.distanceTo(p2)/2.0;
84 data.center = p1 + (p2-p1)/2.0;
87 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom2P(): "
88 "Cannot create a circle with radius 0.0.");
96 * Creates this circle from 3 given points which define the circle line.
98 * @param p1 1st point.
99 * @param p2 2nd point.
100 * @param p3 3rd point.
102 bool RS_Circle::createFrom3P(const Vector& p1, const Vector& p2,
104 if (p1.distanceTo(p2)>RS_TOLERANCE &&
105 p2.distanceTo(p3)>RS_TOLERANCE &&
106 p3.distanceTo(p1)>RS_TOLERANCE) {
108 // middle points between 3 points:
113 // intersection of two middle lines
115 a1 = p1.angleTo(p2) + M_PI/2.0;
116 dir1.setPolar(100.0, a1);
118 a2 = p2.angleTo(p3) + M_PI/2.0;
119 dir2.setPolar(100.0, a2);
121 RS_ConstructionLineData d1(mp1, mp1 + dir1);
122 RS_ConstructionLineData d2(mp2, mp2 + dir2);
123 RS_ConstructionLine midLine1(NULL, d1);
124 RS_ConstructionLine midLine2(NULL, d2);
126 VectorSolutions sol =
127 RS_Information::getIntersection(&midLine1, &midLine2);
129 data.center = sol.get(0);
130 data.radius = data.center.distanceTo(p3);
132 if (sol.get(0).valid && data.radius<1.0e14 && data.radius>RS_TOLERANCE) {
135 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
136 "Cannot create a circle with inf radius.");
140 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): "
141 "Cannot create a circle with radius 0.0.");
148 VectorSolutions RS_Circle::getRefPoints() {
149 Vector v1(data.radius, 0.0);
150 Vector v2(0.0, data.radius);
152 VectorSolutions ret(data.center,
153 data.center+v1, data.center+v2,
154 data.center-v1, data.center-v2);
160 * @return Always an invalid vector.
162 Vector RS_Circle::getNearestEndpoint(const Vector& /*coord*/, double* dist) {
164 *dist = RS_MAXDOUBLE;
166 return Vector(false);
171 Vector RS_Circle::getNearestPointOnEntity(const Vector& coord,
172 bool /*onEntity*/, double* dist, RS_Entity** entity) {
179 double angle = (coord-data.center).angle();
180 vec.setPolar(data.radius, angle);
184 *dist = fabs((vec-data.center).magnitude()-data.radius);
192 Vector RS_Circle::getNearestCenter(const Vector& coord,
195 *dist = coord.distanceTo(data.center);
202 Vector RS_Circle::getNearestMiddle(const Vector& /*coord*/,
205 *dist = RS_MAXDOUBLE;
207 return Vector(false);
212 Vector RS_Circle::getNearestDist(double /*distance*/,
213 const Vector& /*coord*/,
217 *dist = RS_MAXDOUBLE;
219 return Vector(false);
222 Vector RS_Circle::getNearestDist(double /*distance*/,
225 return Vector(false);
230 double RS_Circle::getDistanceToPoint(const Vector& coord,
232 RS2::ResolveLevel, double) {
237 return fabs((coord-data.center).magnitude() - data.radius);
242 void RS_Circle::move(Vector offset) {
243 data.center.move(offset);
249 void RS_Circle::rotate(Vector center, double angle) {
250 data.center.rotate(center, angle);
256 void RS_Circle::scale(Vector center, Vector factor) {
257 data.center.scale(center, factor);
258 data.radius *= factor.x;
264 void RS_Circle::mirror(Vector axisPoint1, Vector axisPoint2) {
265 data.center.mirror(axisPoint1, axisPoint2);
269 void RS_Circle::draw(PaintInterface * painter, RS_GraphicView * view, double /*patternOffset*/)
271 if (painter == NULL || view == NULL)
274 // simple style-less lines
275 if (getPen().getLineType()==RS2::SolidLine ||
277 view->getDrawingMode()==RS2::ModePreview) {
279 painter->drawArc(view->toGui(getCenter()),
280 getRadius() * view->getFactor().x,
284 double styleFactor = getStyleFactor(view);
285 if (styleFactor<0.0) {
286 painter->drawArc(view->toGui(getCenter()),
287 getRadius() * view->getFactor().x,
294 RS_LineTypePattern* pat;
296 pat = &patternSelected;
298 pat = view->getPattern(getPen().getLineType());
305 if (getRadius()<1.0e-6) {
309 // Pen to draw pattern is always solid:
310 RS_Pen pen = painter->getPen();
311 pen.setLineType(RS2::SolidLine);
312 painter->setPen(pen);
314 double* da; // array of distances in x.
315 int i; // index counter
317 double length = getAngleLength();
320 da = new double[pat->num];
322 for (i=0; i<pat->num; ++i) {
323 da[i] = fabs(pat->pattern[i] * styleFactor)/getRadius();
330 //double cx = getCenter().x * factor.x + offsetX;
331 //double cy = - a->getCenter().y * factor.y + getHeight() - offsetY;
332 Vector cp = view->toGui(getCenter());
333 double r = getRadius() * view->getFactor().x;
336 if (pat->pattern[i] * styleFactor > 0.0) {
337 if (tot+fabs(da[i])<length) {
338 painter->drawArc(cp, r,
343 painter->drawArc(cp, r,
365 void RS_Circle::moveRef(const Vector& ref, const Vector& offset) {
366 Vector v1(data.radius, 0.0);
367 Vector v2(0.0, data.radius);
369 if (ref.distanceTo(data.center + v1)<1.0e-4) {
370 data.radius = data.center.distanceTo(data.center + v1 + offset);
371 } else if (ref.distanceTo(data.center + v2)<1.0e-4) {
372 data.radius = data.center.distanceTo(data.center + v2 + offset);
373 } else if (ref.distanceTo(data.center - v1)<1.0e-4) {
374 data.radius = data.center.distanceTo(data.center - v1 + offset);
375 } else if (ref.distanceTo(data.center - v2)<1.0e-4) {
376 data.radius = data.center.distanceTo(data.center - v2 + offset);
382 * Dumps the circle's data to stdout.
384 std::ostream& operator << (std::ostream& os, const RS_Circle& a) {
385 os << " Circle: " << a.data << "\n";