]> Shamusworld >> Repos - architektonas/blob - src/object.cpp
Fix object selection to work while in snap mode.
[architektonas] / src / object.cpp
1 //
2 // object.cpp: Base class for all CAD objects
3 //
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // WHO  WHEN        WHAT
11 // ---  ----------  ------------------------------------------------------------
12 // JLH  03/22/2011  Created this file
13 // JLH  04/01/2011  Added constructor to allow derived objects to have empty
14 //                  constructor bodies, added state querying
15 // JLH  04/02/2001  Added static methods for global states (fixed angle, etc)
16 //
17
18 #include "object.h"
19 #include <stdlib.h>
20 #include <math.h>
21
22 // Initialize static variables
23 bool Object::fixedAngle = false;
24 bool Object::fixedLength = false;
25 QFont * Object::font = 0;
26 int Object::viewportHeight = 0;
27 bool Object::deleteActive = false;
28 bool Object::dimensionActive = false;
29 bool Object::snapToGrid = true;
30 //snapToPoints all well here?
31 bool Object::ignoreClicks = false;
32 bool Object::dontMove = false;
33 bool Object::selectionInProgress = false;
34 QRectF Object::selection;
35 double Object::gridSpacing;
36
37
38 Object::Object(): position(Vector(0, 0)), parent(0), type(OTObject),
39         state(OSInactive), oldState(OSInactive), needUpdate(false)
40         //, attachedDimension(0)
41 {
42 }
43
44
45 Object::Object(Vector v,  Object * passedInParent/*= 0*/): position(v),
46         parent(passedInParent), state(OSInactive), oldState(OSInactive),
47         needUpdate(false)//, attachedDimension(0)
48 {
49 }
50
51
52 Object::~Object()
53 {
54 printf("Object: Destroyed!\n");
55         for(uint i=0; i<connected.size(); i++)
56                 connected[i].object->DisconnectAll(this);
57 }
58
59
60 /*virtual*/ void Object::Draw(Painter *)
61 {
62 }
63
64
65 /*virtual*/ Vector Object::Center(void)
66 {
67         return Vector();
68 }
69
70
71 /*virtual*/ bool Object::Collided(Vector)
72 {
73         return false;
74 }
75
76
77 /*virtual*/ void Object::PointerMoved(Vector)
78 {
79 }
80
81
82 /*virtual*/ void Object::PointerReleased(void)
83 {
84 }
85
86
87 /*virtual*/ bool Object::NeedsUpdate(void)
88 {
89         return needUpdate;
90 }
91
92
93 /*virtual*/ bool Object::HitTest(Point)
94 {
95         return false;
96 }
97
98
99 // This is intended to be overridden by the Container class, for object morphing
100 /*virtual*/ void Object::Transmute(Object *, Object *)
101 {
102 }
103
104
105 /*virtual*/ Object * Object::GetParent(void)
106 {
107         return parent;
108 }
109
110
111 /*virtual*/ void Object::Add(Object *)
112 {
113 }
114
115
116 // This returns a pointer to the point passed in, if it coincides. Otherwise returns NULL.
117 /*virtual*/ Vector * Object::GetPointAt(Vector)
118 {
119         return 0;
120 }
121
122
123 // This is meant for writing object data to a file.
124 /*virtual*/ void Object::Enumerate(FILE *)
125 {
126 }
127
128
129 /*virtual*/ Object * Object::Copy(void)
130 {
131         return new Object(position, parent);
132 }
133
134
135 // This returns a point on the object at 'parameter', which is between 0 and 1.
136 // Default is to return the object's position.
137 /*virtual*/ Vector Object::GetPointAtParameter(double)
138 {
139         return position;
140 }
141
142
143 // Since these functions are pretty much non-object specific, we can implement
144 // them here. :-)
145 /*virtual*/ void Object::Connect(Object * obj, double parameter)
146 {
147         connected.push_back(Connection(obj, parameter));
148 }
149
150
151 /*virtual*/ void Object::Disconnect(Object * obj, double parameter)
152 {
153 #if 0
154         for(uint i=0; i<connected.size(); i++)
155         {
156                 if (connected[i].object == obj && connected[i].t == parameter)
157                 {
158                         connected.erase(connected.begin() + i);
159                         return;
160                 }
161         }
162 #else
163         std::vector<Connection>::iterator i;
164
165         for(i=connected.begin(); i!=connected.end(); i++)
166         {
167                 if (((*i).object == obj) && ((*i).t == parameter))
168                 {
169                         connected.erase(i);
170                         return;
171                 }
172         }
173 #endif
174 }
175
176
177 /*virtual*/ void Object::DisconnectAll(Object * obj)
178 {
179 #if 0
180         // According the std::vector docs, only items at position i and beyond are
181         // invalidated, everything before i is still valid. So we use that here.
182         for(uint i=0; i<connected.size();)
183         {
184                 // If we found our object, erase it from the vector but don't advance
185                 // the iterator. Otherwise, advance the iterator. :-)
186                 if (connected[i].object == obj)
187                         connected.erase(connected.begin() + i);
188                 else
189                         i++;
190         }
191 #else
192         std::vector<Connection>::iterator i;
193
194         for(i=connected.begin(); i!=connected.end(); )
195         {
196                 if ((*i).object == obj)
197                         connected.erase(i);
198                 else
199                         i++;
200         }
201 #endif
202 }
203
204
205 /*virtual*/ QRectF Object::Extents(void)
206 {
207         // Generic object returns an empty rect...
208         return QRectF();
209 }
210
211
212 #if 0
213 /*virtual*/ ObjectType Object::Type(void)
214 {
215         return OTObject;
216 }
217 #endif
218
219
220 /*virtual*/ void Object::Translate(Vector amount)
221 {
222         position += amount;
223 }
224
225
226 /*virtual*/ void Object::Rotate(Vector, double)
227 {
228 }
229
230
231 /*virtual*/ void Object::Scale(Vector, double)
232 {
233 }
234
235
236 ObjectState Object::GetState(void)
237 {
238         return state;
239 }
240
241
242 void Object::Reparent(Object * newParent)
243 {
244         parent = newParent;
245 }
246
247
248 /*Dimension * Object::GetAttachedDimension(void)
249 {
250         return attachedDimension;
251 }*/
252
253
254 // Class methods...
255
256 void Object::SetFixedAngle(bool state/*= true*/)
257 {
258         fixedAngle = state;
259 }
260
261
262 void Object::SetFixedLength(bool state/*= true*/)
263 {
264         fixedLength = state;
265 }
266
267
268 void Object::SetFont(QFont * f)
269 {
270         font = f;
271 }
272
273
274 void Object::SetViewportHeight(int height)
275 {
276         viewportHeight = height;
277 }
278
279
280 void Object::SetDeleteActive(bool state/*= true*/)
281 {
282         deleteActive = state;
283 }
284
285
286 void Object::SetDimensionActive(bool state/*= true*/)
287 {
288         dimensionActive = state;
289 }
290
291
292 void Object::SetSnapMode(bool state/*= true*/)
293 {
294         snapToGrid = state;
295 }
296
297
298 //
299 // This looks strange, but it's really quite simple: We want a point that's
300 // more than half-way to the next grid point to snap there while conversely we
301 // want a point that's less than half-way to to the next grid point then snap
302 // to the one before it. So we add half of the grid spacing to the point, then
303 // divide by it so that we can remove the fractional part, then multiply it
304 // back to get back to the correct answer.
305 //
306 Vector Object::SnapPointToGrid(Vector point)
307 {
308         point += gridSpacing / 2.0;             // *This* adds to Z!!!
309         point /= gridSpacing;
310         point.x = floor(point.x);//need to fix this for negative numbers...
311         point.y = floor(point.y);
312         point.z = 0;                                    // Make *sure* Z doesn't go anywhere!!!
313         point *= gridSpacing;
314         return point;
315 }
316
317