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