]> Shamusworld >> Repos - architektonas/blob - src/utils.cpp
More miscellaneous changes.
[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 //
320 // This is used to remove hovered objects from one container in order to delete
321 // them from the same container.
322 //
323 void RemoveHoveredObjects(VPVector & v)
324 {
325         VPVectorIter i = v.begin();
326
327         while (i != v.end())
328         {
329                 Object * obj = (Object *)(*i);
330
331                 if (obj->hovered)
332                         v.erase(i);
333                 else
334                         i++;
335         }
336 }
337
338 void SavePointsFrom(VPVector & v, std::vector<Object> & save)
339 {
340         save.clear();
341         Object o;
342
343         for(VPVectorIter i=v.begin(); i!=v.end(); i++)
344         {
345                 memcpy(&o, (Object *)(*i), sizeof(Object));
346                 save.push_back(o);
347         }
348 }
349
350 void RestorePointsTo(VPVector & v, std::vector<Object> & s)
351 {
352         std::vector<Object>::iterator i;
353         VPVectorIter j;
354
355         for(i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
356         {
357                 Object * obj2 = (Object *)(*j);
358                 obj2->p[0] = (*i).p[0];
359                 obj2->p[1] = (*i).p[1];
360                 obj2->angle[0] = (*i).angle[0];
361                 obj2->angle[1] = (*i).angle[1];
362 //we don't do this because we want to keep selected & friends from changing
363 //              memcpy(obj2, *j, sizeof(Object));
364         }
365 }
366
367 void RestorePointsTo(VPVector & v, VPVector & s)
368 {
369         for(VPVectorIter i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
370         {
371                 Object * objS = (Object *)(*i);
372                 Object * objV = (Object *)(*j);
373
374                 if (objV->type == OTContainer)
375                 {
376                         RestorePointsTo(((Container *)objV)->objects, ((Container *)objS)->objects);
377                         return;
378                 }
379
380                 objV->p[0] = objS->p[0];
381                 objV->p[1] = objS->p[1];
382                 objV->angle[0] = objS->angle[0];
383                 objV->angle[1] = objS->angle[1];
384 //we don't do this because we want to keep selected & friends from changing
385 //              memcpy(obj2, *j, sizeof(Object));
386         }
387 }
388
389 //
390 // Translate a single object; it it's a Container, translate all its contents,
391 // including subcontainers.
392 //
393 void TranslateObject(Object * obj, Point delta)
394 {
395         if (obj->type == OTContainer)
396         {
397                 Container * c = (Container *)obj;
398
399                 for(VPVectorIter i=c->objects.begin(); i!=c->objects.end(); i++)
400                         TranslateObject((Object *)*i, delta);
401         }
402
403         obj->p[0] += delta;
404         obj->p[1] += delta;
405 }
406
407 /*
408 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.
409 */
410 void TranslateContainer(Container * c, Point point, Point delta)
411 {
412         if (c->clicked == NULL)
413 //      {
414 //              TranslateObject((Object *)c, delta);
415                 return;
416 //      }
417
418 //static int i=0;
419 //printf("TranslateContainer: boop (%i)\n", i++);
420 //we can set this to "point" and it won't move...
421 //do it *this* way, and non-enumerated clicks will do the right thing
422         Point clickedPoint = point - delta;
423
424         switch (c->clicked->type)
425         {
426         case OTLine:
427                 if (c->clicked->hitPoint[0])
428                         clickedPoint = c->clicked->p[0];
429                 else if (c->clicked->hitPoint[1])
430                         clickedPoint = c->clicked->p[1];
431                 else if (c->clicked->hitObject)
432 //Weirdness: some lines get a midpoint, some don't...
433                         clickedPoint = Geometry::Midpoint((Line *)(c->clicked));
434
435                 break;
436
437         case OTCircle:
438                 if (c->clicked->hitPoint[0])
439                         clickedPoint = c->clicked->p[0];
440 //              else if (c->clicked->hitObject)
441 //                      clickedPoint = point - delta;
442
443                 break;
444
445         case OTArc:
446                 if (c->clicked->hitPoint[0])
447                         clickedPoint = c->clicked->p[0];
448                 else if (c->clicked->hitPoint[1])
449                         clickedPoint = c->clicked->p[0] + (Vector(cos(c->clicked->angle[0]), sin(c->clicked->angle[0])) * c->clicked->radius[0]);
450                 else if (c->clicked->hitPoint[2])
451                         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]);
452 //              else if (c->clicked->hitObject)
453 //                      clickedPoint = point - delta;
454
455                 break;
456
457         case OTDimension:
458                 break;
459
460         case OTText:
461                 break;
462         }
463
464         Point clickedDelta = point - clickedPoint;
465         TranslateObject((Object *)c, clickedDelta);
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 // This does not *copy* the objects, it simply flattens out the pointers in the
490 // Container and all sub-Containers.
491 //
492 VPVector Flatten(Container * src)
493 {
494         VPVector flat;
495
496         for(VPVectorIter i=src->objects.begin(); i!=src->objects.end(); i++)
497         {
498                 flat.push_back(*i);
499                 Object * obj = (Object *)(*i);
500
501                 // Recursively add objects to the flat vector, if necessary
502                 if (obj->type == OTContainer)
503                 {
504                         VPVector sub = Flatten((Container *)obj);
505                         flat.insert(flat.end(), sub.begin(), sub.end());
506                 }
507         }
508
509         return flat;
510 }
511
512 //
513 // This does not *copy* the objects, it simply flattens out the pointers in the
514 // vector and all sub-Containers in the vector.
515 //
516 VPVector Flatten(VPVector src)
517 {
518         VPVector flat;
519
520         for(VPVectorIter i=src.begin(); i!=src.end(); i++)
521         {
522                 flat.push_back(*i);
523                 Object * obj = (Object *)(*i);
524
525                 // Recursively add objects to the flat vector, if necessary
526                 if (obj->type == OTContainer)
527                 {
528                         VPVector sub = Flatten(((Container *)obj)->objects);
529                         flat.insert(flat.end(), sub.begin(), sub.end());
530                 }
531         }
532
533         return flat;
534 }