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