]> Shamusworld >> Repos - architektonas/blob - src/utils.cpp
Whitespace changes. :-P
[architektonas] / src / utils.cpp
1 //
2 // utils.cpp: Stuff that's useful to have kicking around, in one spot
3 //
4 // Part of the Architektonas Project
5 // (C) 2020 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  05/01/2015  Created this file
13 //
14
15 #include "utils.h"
16 #include <math.h>
17 #include <string.h>             // For memcpy()
18 #include "geometry.h"
19
20 //
21 // Copy objects in one vector to another, creating copies and placing them in
22 // the other vector. Clearing & etc. of vectors is responsibility of the caller!
23 //
24 void CopyObjects(VPVector & from, VPVector & to)
25 {
26         for(VPVectorIter i=from.begin(); i!=from.end(); i++)
27         {
28                 Object * obj = (Object *)(*i);
29                 Object * newObject = CopyObject(obj);
30                 to.push_back(newObject);
31         }
32 }
33
34 VPVector CopyObjects(VPVector & src)
35 {
36         VPVector copy;
37
38         for(VPVectorIter i=src.begin(); i!=src.end(); i++)
39         {
40                 Object * newObject = CopyObject2((Object *)(*i));
41                 copy.push_back(newObject);
42         }
43
44         return copy;
45 }
46
47 //
48 // Create a copy of the passed in object.
49 //
50 Object * CopyObject(Object * obj)
51 {
52         void * newObject = NULL;
53
54         switch (obj->type)
55         {
56         case OTLine:
57                 newObject = new Line();
58                 memcpy(newObject, obj, sizeof(Line));
59                 break;
60         case OTCircle:
61                 newObject = new Circle();
62                 memcpy(newObject, obj, sizeof(Circle));
63                 break;
64         case OTEllipse:
65                 newObject = new Ellipse();
66                 memcpy(newObject, obj, sizeof(Ellipse));
67                 break;
68         case OTArc:
69                 newObject = new Arc();
70                 memcpy(newObject, obj, sizeof(Arc));
71                 break;
72         case OTDimension:
73                 newObject = new Dimension();
74                 memcpy(newObject, obj, sizeof(Dimension));
75                 break;
76         case OTSpline:
77                 newObject = new Spline();
78                 memcpy(newObject, obj, sizeof(Spline));
79                 break;
80         case OTText:
81                 newObject = new Text();
82                 memcpy(newObject, obj, sizeof(Text));
83                 ((Text *)newObject)->s = ((Text *)obj)->s;
84                 break;
85         case OTContainer:
86                 newObject = new Container();
87 //this won't work...
88 //              memcpy(newObject, obj, sizeof(Line));
89                 ((Container *)newObject)->p[0] = obj->p[0];
90                 ((Container *)newObject)->p[1] = obj->p[1];
91                 ((Container *)newObject)->layer = obj->layer;
92                 CopyObjects(((Container *)obj)->objects, ((Container *)newObject)->objects);
93                 break;
94         default:
95                 break;
96         }
97
98         // Fix objectID
99         if (newObject && (((Object *)newObject)->type != OTContainer))
100                 ((Object *)newObject)->id = Global::objectID++;
101
102         return (Object *)newObject;
103 }
104
105 //
106 // Create a copy of the passed in object.  This version calls the second
107 // version of CopyObjects() (with one parameter and a vector return value).
108 //
109 Object * CopyObject2(Object * obj)
110 {
111         void * newObject = NULL;
112
113         switch (obj->type)
114         {
115         case OTLine:
116                 newObject = new Line();
117                 memcpy(newObject, obj, sizeof(Line));
118                 break;
119
120         case OTCircle:
121                 newObject = new Circle();
122                 memcpy(newObject, obj, sizeof(Circle));
123                 break;
124
125         case OTEllipse:
126                 newObject = new Ellipse();
127                 memcpy(newObject, obj, sizeof(Ellipse));
128                 break;
129
130         case OTArc:
131                 newObject = new Arc();
132                 memcpy(newObject, obj, sizeof(Arc));
133                 break;
134
135         case OTDimension:
136                 newObject = new Dimension();
137                 memcpy(newObject, obj, sizeof(Dimension));
138                 break;
139
140         case OTSpline:
141                 newObject = new Spline();
142                 memcpy(newObject, obj, sizeof(Spline));
143                 break;
144
145         case OTText:
146                 newObject = new Text();
147                 memcpy(newObject, obj, sizeof(Text));
148                 ((Text *)newObject)->s = ((Text *)obj)->s;
149                 break;
150
151         case OTContainer:
152                 newObject = new Container();
153                 ((Container *)newObject)->p[0] = obj->p[0];
154                 ((Container *)newObject)->p[1] = obj->p[1];
155                 ((Container *)newObject)->layer = obj->layer;
156                 ((Container *)newObject)->objects = CopyObjects(((Container *)obj)->objects);
157                 break;
158         }
159
160         // Fix objectID
161         if (newObject && (((Object *)newObject)->type != OTContainer))
162                 ((Object *)newObject)->id = Global::objectID++;
163
164         return (Object *)newObject;
165 }
166
167 void MoveSelectedObjectsTo(VPVector & dest, VPVector & from)
168 {
169         VPVectorIter i = from.begin();
170
171         while (i != from.end())
172         {
173                 Object * obj = (Object *)(*i);
174
175                 if (obj->selected)
176                 {
177                         dest.push_back(*i);
178                         from.erase(i);
179                 }
180                 else
181                         i++;
182         }
183 }
184
185 VPVector MoveSelectedObjectsFrom(VPVector & from)
186 {
187         VPVector objects;
188         VPVectorIter i = from.begin();
189
190         while (i != from.end())
191         {
192                 Object * obj = (Object *)(*i);
193
194                 if (obj->selected)
195                 {
196                         objects.push_back(*i);
197                         from.erase(i);
198                 }
199                 else
200                         i++;
201         }
202
203         return objects;
204 }
205
206 //hmm, this won't work, as these are just pointers...
207 //[should work now]
208 void CopySelectedObjectsTo(VPVector & dest, VPVector & from)
209 {
210         for(VPVectorIter i=from.begin(); i!=from.end(); i++)
211         {
212                 Object * obj = (Object *)(*i);
213
214                 if (obj->selected)
215                         dest.push_back(CopyObject2(obj));
216         }
217 }
218
219 VPVector CopySelectedObjects(VPVector & src)
220 {
221         VPVector copy;
222
223         for(VPVectorIter i=src.begin(); i!=src.end(); i++)
224         {
225                 Object * obj = (Object *)(*i);
226
227                 if (obj->selected)
228                         copy.push_back(CopyObject2(obj));
229         }
230
231         return copy;
232 }
233
234 void AddObjectsTo(VPVector & dest, VPVector & from)
235 {
236         for(VPVectorIter i=from.begin(); i!=from.end(); i++)
237                 dest.push_back(*i);
238 }
239
240 void ClearSelected(VPVector & v)
241 {
242         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
243                 ((Object *)(*i))->selected = false;
244 }
245
246 //
247 // Select all *visible* objects.  If an object's layer is invisible, skip it.
248 //
249 void SelectAll(VPVector & v)
250 {
251         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
252         {
253                 Object * obj = (Object *)(*i);
254                 bool visible = !Global::layerHidden[obj->layer];
255                 obj->selected = visible;
256         }
257 }
258
259 //
260 // Recursively go down thru the Container's vectors, deleting all the objects
261 // contained therein.  Once that is done, the main Container can be deleted.
262 // We don't have to worry about the underlying std::vectors, as they have their
263 // own destructors--plus they don't take ownership of objects, which is why we
264 // have to keep track of that stuff ourselves.  :-P  Believe it or not, this is
265 // a Good Thing(TM).  ;-)
266 //
267 void DeleteContents(VPVector & v)
268 {
269         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
270         {
271                 Object * obj = (Object *)(*i);
272
273                 if (obj->type == OTContainer)
274                         DeleteContents(((Container *)obj)->objects);
275
276                 delete obj;
277         }
278
279         v.clear();
280 }
281
282 void DeleteSelectedObjects(VPVector & v)
283 {
284         VPVectorIter i = v.begin();
285
286         while (i != v.end())
287         {
288                 Object * obj = (Object *)(*i);
289
290                 if (obj->selected)
291                 {
292                         delete obj;
293                         v.erase(i);
294                 }
295                 else
296                         i++;
297         }
298 }
299
300 //
301 // This is used to remove selected objects from one container in order to move
302 // them to a different container.
303 //
304 void RemoveSelectedObjects(VPVector & v)
305 {
306         VPVectorIter i = v.begin();
307
308         while (i != v.end())
309         {
310                 Object * obj = (Object *)(*i);
311
312                 if (obj->selected)
313                         v.erase(i);
314                 else
315                         i++;
316         }
317 }
318
319 void SavePointsFrom(VPVector & v, std::vector<Object> & save)
320 {
321         save.clear();
322         Object o;
323
324         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
325         {
326                 memcpy(&o, (Object *)(*i), sizeof(Object));
327                 save.push_back(o);
328         }
329 }
330
331 void RestorePointsTo(VPVector & v, std::vector<Object> & s)
332 {
333         std::vector<Object>::iterator i;
334         VPVectorIter j;
335
336         for(i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
337         {
338                 Object * obj2 = (Object *)(*j);
339                 obj2->p[0] = (*i).p[0];
340                 obj2->p[1] = (*i).p[1];
341                 obj2->angle[0] = (*i).angle[0];
342                 obj2->angle[1] = (*i).angle[1];
343 //we don't do this because we want to keep selected & friends from changing
344 //              memcpy(obj2, *j, sizeof(Object));
345         }
346 }
347
348 void RestorePointsTo(VPVector & v, VPVector & s)
349 {
350         for(VPVectorIter i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
351         {
352                 Object * objS = (Object *)(*i);
353                 Object * objV = (Object *)(*j);
354
355                 if (objV->type == OTContainer)
356                 {
357                         RestorePointsTo(((Container *)objV)->objects, ((Container *)objS)->objects);
358                         return;
359                 }
360
361                 objV->p[0] = objS->p[0];
362                 objV->p[1] = objS->p[1];
363                 objV->angle[0] = objS->angle[0];
364                 objV->angle[1] = objS->angle[1];
365 //we don't do this because we want to keep selected & friends from changing
366 //              memcpy(obj2, *j, sizeof(Object));
367         }
368 }
369
370 //
371 // Translate a single object; it it's a Container, translate all its contents,
372 // including subcontainers.
373 //
374 void TranslateObject(Object * obj, Point delta)
375 {
376         if (obj->type == OTContainer)
377         {
378                 Container * c = (Container *)obj;
379
380                 for(VPVectorIter i=c->objects.begin(); i!=c->objects.end(); i++)
381                         TranslateObject((Object *)*i, delta);
382         }
383
384         obj->p[0] += delta;
385         obj->p[1] += delta;
386 }
387
388 /*
389 So we need to make it so that we pick the container's point clicked on, and translate all the other parts *not* clicked on.
390 */
391 void TranslateContainer(Container * c, Point point, Point delta)
392 {
393         if (c->clicked == NULL)
394 //      {
395 //              TranslateObject((Object *)c, delta);
396                 return;
397 //      }
398
399 //static int i=0;
400 //printf("TranslateContainer: boop (%i)\n", i++);
401 //we can set this to "point" and it won't move...
402 //do it *this* way, and non-enumerated clicks will do the right thing
403         Point clickedPoint = point - delta;
404
405         switch (c->clicked->type)
406         {
407         case OTLine:
408                 if (c->clicked->hitPoint[0])
409                         clickedPoint = c->clicked->p[0];
410                 else if (c->clicked->hitPoint[1])
411                         clickedPoint = c->clicked->p[1];
412                 else if (c->clicked->hitObject)
413 //Weirdness: some lines get a midpoint, some don't...
414                         clickedPoint = Geometry::Midpoint((Line *)(c->clicked));
415
416                 break;
417
418         case OTCircle:
419                 if (c->clicked->hitPoint[0])
420                         clickedPoint = c->clicked->p[0];
421 //              else if (c->clicked->hitObject)
422 //                      clickedPoint = point - delta;
423
424                 break;
425
426         case OTArc:
427                 if (c->clicked->hitPoint[0])
428                         clickedPoint = c->clicked->p[0];
429                 else if (c->clicked->hitPoint[1])
430                         clickedPoint = c->clicked->p[0] + (Vector(cos(c->clicked->angle[0]), sin(c->clicked->angle[0])) * c->clicked->radius[0]);
431                 else if (c->clicked->hitPoint[2])
432                         clickedPoint = c->clicked->p[0] + (Vector(cos(c->clicked->angle[0] + c->clicked->angle[1]), sin(c->clicked->angle[0] + c->clicked->angle[1])) * c->clicked->radius[0]);
433 //              else if (c->clicked->hitObject)
434 //                      clickedPoint = point - delta;
435
436                 break;
437
438         case OTDimension:
439                 break;
440
441         case OTText:
442                 break;
443         }
444
445         Point clickedDelta = point - clickedPoint;
446         TranslateObject((Object *)c, clickedDelta);
447 }
448
449 //
450 // Translate all objects in the passed in vector, including Containers and all
451 // the objects they contain.
452 //
453 void TranslateObjects(VPVector & v, Point delta)
454 {
455         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
456         {
457                 Object * obj = (Object *)(*i);
458                 obj->p[0] += delta;
459                 obj->p[1] += delta;
460
461                 if (obj->type == OTContainer)
462                 {
463                         Container * c = (Container *)obj;
464                         TranslateObjects(c->objects, delta);
465                 }
466         }
467 }
468
469 //
470 // This does not *copy* the objects, it simply flattens out the pointers in the
471 // Container and all sub-Containers.
472 //
473 VPVector Flatten(Container * src)
474 {
475         VPVector flat;
476
477         for(VPVectorIter i=src->objects.begin(); i!=src->objects.end(); i++)
478         {
479                 flat.push_back(*i);
480                 Object * obj = (Object *)(*i);
481
482                 // Recursively add objects to the flat vector, if necessary
483                 if (obj->type == OTContainer)
484                 {
485                         VPVector sub = Flatten((Container *)obj);
486                         flat.insert(flat.end(), sub.begin(), sub.end());
487                 }
488         }
489
490         return flat;
491 }
492
493 //
494 // This does not *copy* the objects, it simply flattens out the pointers in the
495 // vector and all sub-Containers in the vector.
496 //
497 VPVector Flatten(VPVector src)
498 {
499         VPVector flat;
500
501         for(VPVectorIter i=src.begin(); i!=src.end(); i++)
502         {
503                 flat.push_back(*i);
504                 Object * obj = (Object *)(*i);
505
506                 // Recursively add objects to the flat vector, if necessary
507                 if (obj->type == OTContainer)
508                 {
509                         VPVector sub = Flatten(((Container *)obj)->objects);
510                         flat.insert(flat.end(), sub.begin(), sub.end());
511                 }
512         }
513
514         return flat;
515 }