]> Shamusworld >> Repos - architektonas/blob - src/circle.cpp
1f350b0341615f7cc2abbde872c0448c13e68b66
[architektonas] / src / circle.cpp
1 // circle.cpp: Circle object
2 //
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
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
14 //
15
16 #include "circle.h"
17
18 #include <QtGui>
19 #include "painter.h"
20
21
22 Circle::Circle(Vector p1, double r, Object * p/*= NULL*/): Object(p1, p), radius(r),
23         draggingEdge(false), draggingCenter(false), hitCenter(false), hitCircle(false)
24 {
25         type = OTCircle;
26 }
27
28
29 Circle::~Circle()
30 {
31 }
32
33
34 /*virtual*/ void Circle::Draw(Painter * painter)
35 {
36         if (state == OSSelected || hitCircle || hitCenter)
37                 painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
38         else
39                 painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
40
41         // Hatch/Fill...
42 //      QBrush brush(Qt::DiagCrossPattern);
43 //      brush.setColor(QColor(255, 255, 0));
44 //      painter->SetBrush(brush);
45         painter->SetBrush(QBrush(Qt::NoBrush));
46
47         // Draw the object...
48         painter->DrawEllipse(position, radius, radius);
49
50         // & draw handles (if needed)
51         if (state == OSSelected || hitCenter)
52                 painter->DrawHandle(position);
53
54         if (state == OSSelected && draggingEdge && objectWasDragged)
55                 painter->DrawHandle(dragPoint);
56 }
57
58
59 /*virtual*/ Vector Circle::Center(void)
60 {
61         return position;
62 }
63
64
65 /*virtual*/ bool Circle::Collided(Vector point)
66 {
67         // We can assume this, since this is a mouse down event here.
68         objectWasDragged = false;
69         HitTest(point);
70
71         draggingCenter = hitCenter;
72         draggingEdge = hitCircle;
73
74         if (hitCenter || hitCircle)
75         {
76                 dragPoint = point;
77                 oldState = state;
78                 state = OSSelected;
79                 return true;
80         }
81
82         // We didn't hit anything, so deselect this object and report failure to hit
83         state = OSInactive;
84         return false;
85 }
86
87
88 /*virtual*/ void Circle::PointerMoved(Vector point)
89 {
90         if (selectionInProgress)
91         {
92                 // Check for whether or not the rect contains this circle
93                 if (selection.normalized().contains(Extents()))
94                         state = OSSelected;
95                 else
96                         state = OSInactive;
97
98                 return;
99         }
100
101         // Hit test tells us what we hit (if anything) through boolean variables. It
102         // also tells us whether or not the state changed.
103         needUpdate = HitTest(point);
104         objectWasDragged = (draggingEdge | draggingCenter);
105
106         if (draggingEdge)
107                 radius = Vector::Magnitude(point, position);
108         else if (draggingCenter)
109                 position = point;
110
111         // Save this point so the rendering code knows where to draw the handle...
112         dragPoint = point;
113 }
114
115
116 /*virtual*/ void Circle::PointerReleased(void)
117 {
118         // Mouse went up, so our dragging is done (if any *was* done, that is)
119         draggingEdge = draggingCenter = false;
120         hitCenter = hitCircle = false;
121
122         // If the object was dragged, then revert to the old state.
123         // Otherwise, we were probably just clicked, and want to stay in the selected state.
124         if (objectWasDragged)
125                 state = oldState;
126 }
127
128
129 /*virtual*/ bool Circle::HitTest(Point point)
130 {
131         SaveState();
132         hitCenter = hitCircle = false;
133         double length = Vector::Magnitude(position, point);
134 //printf("Circle::length = %lf, radius = %lf\n", length, radius);
135 //How to translate this into pixels from Document space???
136 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
137 //the caller knows about the zoom factor and all that good kinda crap
138 /*
139 Document passes in the correct Cartesian coordinates being pointed to by the mouse.
140 So all we have to be concerned with is properly scaling our hot zones/handle sizes,
141 since we generally *don't* want those to scale with the zoom level. ;-)
142
143 What is going on here?
144 If we're zoomed out to, say, 50%, & our radius is 10.0 (absolute), then on screen
145 the radius will be 5.0. By multiplying the length by the zoom factor, we align our
146 pointed at length with our on screen length.
147 */
148         if ((length * Painter::zoom) < 8.0)
149                 hitCenter = true;
150 //wrong:        else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
151 /*NB: The following should be identical to what we have down below, but it doesn't work out that way... :-P */
152 //close, but no else if (((length * Painter::zoom) < ((radius * Painter::zoom) + 2.0)) && ((length * Painter::zoom) > ((radius * Painter::zoom) - 2.0)))
153 //really wrong! else if (((length * Painter::zoom) < (radius + 2.0)) && ((length * Painter::zoom) > (radius - 2.0)))
154 // close again, but sill no     else if (((length * Painter::zoom) < ((radius + 2.0) * Painter::zoom)) && ((length * Painter::zoom) > ((radius - 2.0) * Painter::zoom)))
155         else if ((fabs(length - radius) * Painter::zoom) < 2.0)
156                 hitCircle = true;
157
158         return StateChanged();
159 }
160
161
162 /*virtual*/ QRectF Circle::Extents(void)
163 {
164         return QRectF(QPointF(position.x - radius, position.y - radius), QPointF(position.x + radius, position.y + radius));
165 }
166
167
168 void Circle::SaveState(void)
169 {
170         oldHitCenter = hitCenter;
171         oldHitCircle = hitCircle;
172 }
173
174
175 bool Circle::StateChanged(void)
176 {
177         if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
178                 return true;
179
180         return false;
181 }
182
183
184 /*virtual*/ void Circle::Enumerate(FILE * file)
185 {
186         fprintf(file, "CIRCLE (%lf,%lf) %lf\n", position.x, position.y, radius);
187 }
188