1 // circle.cpp: Circle object
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 03/28/2011 Created this file
12 // JLH 09/26/2011 Added hover effects
13 // JLH 09/26/2011 Major cleanup of this class
23 Circle::Circle(Vector p1, double r, Object * p/*= NULL*/): Object(p1, p), radius(r),
24 draggingEdge(false), draggingCenter(false), hitCenter(false), hitCircle(false)
35 /*virtual*/ void Circle::Draw(Painter * painter)
37 if (state == OSSelected || hitCircle || hitCenter)
38 painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
40 painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
43 // QBrush brush(Qt::DiagCrossPattern);
44 // brush.setColor(QColor(255, 255, 0));
45 // painter->SetBrush(brush);
46 painter->SetBrush(QBrush(Qt::NoBrush));
49 painter->DrawEllipse(position, radius, radius);
51 // & draw handles (if needed)
52 if (state == OSSelected || hitCenter)
53 painter->DrawHandle(position);
55 if (state == OSSelected && draggingEdge && objectWasDragged)
56 painter->DrawHandle(dragPoint);
58 // If resizing the circle, draw an information panel showing the new radius.
61 QString text = QObject::tr("Radius: %1\nScale: %2%");
62 text = text.arg(radius, 0, 'd', 4).arg(radius / oldRadius * 100.0, 0, 'd', 0);
64 QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
66 painter->SetBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
67 QRectF textRect(10.0, 10.0, 270.0, 70.0); // x, y, w, h
68 painter->DrawRoundedRect(textRect, 7.0, 7.0);
70 textRect.setLeft(textRect.left() + 14);
71 painter->SetFont(*Object::font);
72 pen = QPen(QColor(0x00, 0x5F, 0xDF));
74 painter->DrawText(textRect, Qt::AlignVCenter, text);
76 painter->DrawInformativeText(text);
82 /*virtual*/ Vector Circle::Center(void)
88 /*virtual*/ bool Circle::Collided(Vector point)
90 // Someone told us to fuck off, so we'll fuck off. :-)
94 // We can assume this, since this is a mouse down event here.
95 objectWasDragged = false;
98 // Now that we've done our hit testing on the non-snapped point, snap it if
101 point = SnapPointToGrid(point);
103 if (snapPointIsValid)
106 draggingCenter = hitCenter;
107 draggingEdge = hitCircle;
109 if (hitCenter || hitCircle)
118 // We didn't hit anything, so deselect this object and report failure to hit
124 /*virtual*/ bool Circle::PointerMoved(Vector point)
126 if (selectionInProgress)
128 // Check for whether or not the rect contains this circle
129 // if (selection.normalized().contains(Extents()))
130 if (selection.contains(Extents()))
139 Note that we can separate this out in the TLC, and it would probably make more sense
140 to do it there as then we can be assured that all hit testing is done before we do
141 any snapping. !!! FIX !!!
143 // Hit test tells us what we hit (if anything) through boolean variables. It
144 // also tells us whether or not the state changed.
146 bool hovered = HitTest(point);
147 needUpdate = HitStateChanged();
150 point = SnapPointToGrid(point);
152 if (snapPointIsValid)
155 objectWasDragged = (draggingEdge | draggingCenter);
157 if (objectWasDragged)
161 radius = Vector::Magnitude(point, position);
162 else if (draggingCenter)
165 // Save this point so the rendering code knows where to draw the handle...
171 /*virtual*/ void Circle::PointerReleased(void)
173 // Mouse went up, so our dragging is done (if any *was* done, that is)
174 draggingEdge = draggingCenter = false;
175 hitCenter = hitCircle = false;
177 // If the object was dragged, then revert to the old state.
178 // Otherwise, we were probably just clicked, and want to stay in the selected state.
179 if (objectWasDragged)
184 /*virtual*/ bool Circle::HitTest(Point point)
187 hitCenter = hitCircle = false;
188 double length = Vector::Magnitude(position, point);
189 //printf("Circle::length = %lf, radius = %lf\n", length, radius);
190 //How to translate this into pixels from Document space???
191 //Maybe we need to pass a scaling factor in here from the caller? That would make
192 //sense, as the caller knows about the zoom factor and all that good kinda crap
194 Document passes in the correct Cartesian coordinates being pointed to by the mouse.
195 So all we have to be concerned with is properly scaling our hot zones/handle sizes,
196 since we generally *don't* want those to scale with the zoom level. ;-)
198 What is going on here?
199 If we're zoomed out to, say, 50%, & our radius is 10.0 (absolute), then on screen
200 the radius will be 5.0. By multiplying the length by the zoom factor, we align our
201 pointed at length with our on screen length.
203 if ((length * Painter::zoom) < 8.0)
207 // Make sure we don't try to snap to ourselves...!
210 snapPoint = position;
211 snapPointIsValid = true;
214 //wrong: else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
215 /*NB: The following should be identical to what we have down below, but it doesn't work out that way... :-P */
216 //close, but no else if (((length * Painter::zoom) < ((radius * Painter::zoom) + 2.0)) && ((length * Painter::zoom) > ((radius * Painter::zoom) - 2.0)))
217 //really wrong! else if (((length * Painter::zoom) < (radius + 2.0)) && ((length * Painter::zoom) > (radius - 2.0)))
218 // close again, but sill no else if (((length * Painter::zoom) < ((radius + 2.0) * Painter::zoom)) && ((length * Painter::zoom) > ((radius - 2.0) * Painter::zoom)))
219 else if ((fabs(length - radius) * Painter::zoom) < 2.0)
222 // return HitStateChanged();
223 return (hitCenter || hitCircle ? true : false);
227 /*virtual*/ QRectF Circle::Extents(void)
229 return QRectF(QPointF(position.x - radius, position.y - radius), QPointF(position.x + radius, position.y + radius));
233 void Circle::SaveHitState(void)
235 oldHitCenter = hitCenter;
236 oldHitCircle = hitCircle;
240 bool Circle::HitStateChanged(void)
242 if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
249 /*virtual*/ void Circle::Enumerate(FILE * file)
251 fprintf(file, "CIRCLE %i (%lf,%lf) %lf\n", layer, position.x, position.y, radius);
255 /*virtual*/ Object * Circle::Copy(void)
257 #warning "!!! This doesn't take care of attached Dimensions !!!"
259 This is a real problem. While having a pointer in the Dimension to this line's points
260 is fast & easy, it creates a huge problem when trying to replicate an object like this.
262 Maybe a way to fix that then, is to have reference numbers instead of pointers. That
263 way, if you copy them, ... you might still have problems. Because you can't be sure if
264 a copy will be persistant or not, you then *definitely* do not want them to have the
265 same reference number.
267 return new Circle(position, radius, parent);
271 /*virtual*/ void Circle::Rotate(Point point, double angle)
273 Point c1 = Geometry::RotatePointAroundPoint(position, point, angle);
278 /*virtual*/ void Circle::Mirror(Point p1, Point p2)
280 Point c1 = Geometry::MirrorPointAroundLine(position, p1, p2);
285 /*virtual*/ void Circle::Save(void)
292 /*virtual*/ void Circle::Restore(void)