src/ldObject.cc

branch
projects
changeset 935
8d98ee0dc917
parent 930
ab77deb851fa
parent 934
be8128aff739
child 936
aee883858c90
equal deleted inserted replaced
930:ab77deb851fa 935:8d98ee0dc917
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 - 2015 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "main.h"
21 #include "ldObject.h"
22 #include "ldDocument.h"
23 #include "miscallenous.h"
24 #include "mainWindow.h"
25 #include "editHistory.h"
26 #include "glRenderer.h"
27 #include "colors.h"
28 #include "glCompiler.h"
29
30 CFGENTRY (String, DefaultName, "")
31 CFGENTRY (String, DefaultUser, "")
32 CFGENTRY (Bool, UseCALicense, true)
33
34 // List of all LDObjects
35 QMap<long, LDObjectWeakPtr> g_allObjects;
36 static int32 g_idcursor = 1; // 0 shalt be null
37 static constexpr int32 g_maxID = (1 << 24);
38
39 #define LDOBJ_DEFAULT_CTOR(T,BASE) \
40 T :: T (LDObjectPtr* selfptr) : \
41 BASE (selfptr) {}
42
43 // =============================================================================
44 // LDObject constructors
45 //
46 LDObject::LDObject (LDObjectPtr* selfptr) :
47 m_isHidden (false),
48 m_isSelected (false),
49 m_isDestructed (false),
50 qObjListEntry (null)
51 {
52 *selfptr = LDObjectPtr (this, [](LDObject* obj){ obj->finalDelete(); });
53 memset (m_coords, 0, sizeof m_coords);
54 m_self = selfptr->toWeakRef();
55 chooseID();
56 g_allObjects[id()] = self();
57 setRandomColor (QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128));
58 }
59
60 LDSubfile::LDSubfile (LDObjectPtr* selfptr) :
61 LDMatrixObject (selfptr) {}
62
63 LDOBJ_DEFAULT_CTOR (LDEmpty, LDObject)
64 LDOBJ_DEFAULT_CTOR (LDError, LDObject)
65 LDOBJ_DEFAULT_CTOR (LDLine, LDObject)
66 LDOBJ_DEFAULT_CTOR (LDTriangle, LDObject)
67 LDOBJ_DEFAULT_CTOR (LDCondLine, LDLine)
68 LDOBJ_DEFAULT_CTOR (LDQuad, LDObject)
69 LDOBJ_DEFAULT_CTOR (LDOverlay, LDObject)
70 LDOBJ_DEFAULT_CTOR (LDBFC, LDObject)
71 LDOBJ_DEFAULT_CTOR (LDComment, LDObject)
72
73 // =============================================================================
74 //
75 void LDObject::chooseID()
76 {
77 // If this is the first pass we can just use a global ID counter for each
78 // unique object. Let's hope that nobody goes to create 17 million objects
79 // anytime soon.
80 if (g_idcursor < g_maxID)
81 {
82 setID (g_idcursor++);
83 return;
84 }
85
86 // In case someone does, we cannot really continue execution. We must abort,
87 // give the user a chance to save their documents though.
88 Critical ("Created too many objects. Execution cannot continue. You have a "
89 "chance to save any changes to documents, then restart.");
90 (void) IsSafeToCloseAll();
91 Exit();
92 }
93
94 // =============================================================================
95 //
96 void LDObject::setVertexCoord (int i, Axis ax, double value)
97 {
98 Vertex v = vertex (i);
99 v.setCoordinate (ax, value);
100 setVertex (i, v);
101 }
102
103 // =============================================================================
104 //
105 QString LDComment::asText() const
106 {
107 return format ("0 %1", text());
108 }
109
110 // =============================================================================
111 //
112 QString LDSubfile::asText() const
113 {
114 QString val = format ("1 %1 %2 ", color(), position());
115 val += transform().toString();
116 val += ' ';
117 val += fileInfo()->name();
118 return val;
119 }
120
121 // =============================================================================
122 //
123 QString LDLine::asText() const
124 {
125 QString val = format ("2 %1", color());
126
127 for (int i = 0; i < 2; ++i)
128 val += format (" %1", vertex (i));
129
130 return val;
131 }
132
133 // =============================================================================
134 //
135 QString LDTriangle::asText() const
136 {
137 QString val = format ("3 %1", color());
138
139 for (int i = 0; i < 3; ++i)
140 val += format (" %1", vertex (i));
141
142 return val;
143 }
144
145 // =============================================================================
146 //
147 QString LDQuad::asText() const
148 {
149 QString val = format ("4 %1", color());
150
151 for (int i = 0; i < 4; ++i)
152 val += format (" %1", vertex (i));
153
154 return val;
155 }
156
157 // =============================================================================
158 //
159 QString LDCondLine::asText() const
160 {
161 QString val = format ("5 %1", color());
162
163 // Add the coordinates
164 for (int i = 0; i < 4; ++i)
165 val += format (" %1", vertex (i));
166
167 return val;
168 }
169
170 // =============================================================================
171 //
172 QString LDError::asText() const
173 {
174 return contents();
175 }
176
177 // =============================================================================
178 //
179 QString LDEmpty::asText() const
180 {
181 return "";
182 }
183
184 // =============================================================================
185 //
186 const char* LDBFC::StatementStrings[] =
187 {
188 "CERTIFY CCW",
189 "CCW",
190 "CERTIFY CW",
191 "CW",
192 "NOCERTIFY",
193 "INVERTNEXT",
194 "CLIP",
195 "CLIP CCW",
196 "CLIP CW",
197 "NOCLIP",
198 };
199
200 QString LDBFC::asText() const
201 {
202 return format ("0 BFC %1", StatementStrings[int (m_statement)]);
203 }
204
205 // =============================================================================
206 //
207 QList<LDTrianglePtr> LDQuad::splitToTriangles()
208 {
209 // Create the two triangles based on this quadrilateral:
210 // 0---3 0---3 3
211 // | | | / /|
212 // | | ==> | / / |
213 // | | |/ / |
214 // 1---2 1 1---2
215 LDTrianglePtr tri1 (LDSpawn<LDTriangle> (vertex (0), vertex (1), vertex (3)));
216 LDTrianglePtr tri2 (LDSpawn<LDTriangle> (vertex (1), vertex (2), vertex (3)));
217
218 // The triangles also inherit the quad's color
219 tri1->setColor (color());
220 tri2->setColor (color());
221
222 return {tri1, tri2};
223 }
224
225 // =============================================================================
226 //
227 void LDObject::replace (LDObjectPtr other)
228 {
229 long idx = lineNumber();
230 assert (idx != -1);
231
232 // Replace the instance of the old object with the new object
233 document().toStrongRef()->setObject (idx, other);
234
235 // Remove the old object
236 destroy();
237 }
238
239 // =============================================================================
240 //
241 void LDObject::swap (LDObjectPtr other)
242 {
243 assert (document() == other->document());
244 document().toStrongRef()->swapObjects (self(), other);
245 }
246
247 // =============================================================================
248 //
249 LDLine::LDLine (LDObjectPtr* selfptr, Vertex v1, Vertex v2) :
250 LDObject (selfptr)
251 {
252 setVertex (0, v1);
253 setVertex (1, v2);
254 }
255
256 // =============================================================================
257 //
258 LDTriangle::LDTriangle (LDObjectPtr* selfptr, const Vertex& v1, const Vertex& v2, const Vertex& v3) :
259 LDObject (selfptr)
260 {
261 setVertex (0, v1);
262 setVertex (1, v2);
263 setVertex (2, v3);
264 }
265
266 // =============================================================================
267 //
268 LDQuad::LDQuad (LDObjectPtr* selfptr, const Vertex& v1, const Vertex& v2,
269 const Vertex& v3, const Vertex& v4) :
270 LDObject (selfptr)
271 {
272 setVertex (0, v1);
273 setVertex (1, v2);
274 setVertex (2, v3);
275 setVertex (3, v4);
276 }
277
278 // =============================================================================
279 //
280 LDCondLine::LDCondLine (LDObjectPtr* selfptr, const Vertex& v0, const Vertex& v1,
281 const Vertex& v2, const Vertex& v3) :
282 LDLine (selfptr)
283 {
284 setVertex (0, v0);
285 setVertex (1, v1);
286 setVertex (2, v2);
287 setVertex (3, v3);
288 }
289
290 // =============================================================================
291 //
292 LDObject::~LDObject() {}
293
294 // =============================================================================
295 //
296 void LDObject::destroy()
297 {
298 // Don't bother during program termination
299 if (IsExiting() or isDestructed())
300 return;
301
302 // If this object was selected, unselect it now
303 if (isSelected() and document() != null)
304 deselect();
305
306 // If this object was associated to a file, remove it off it now
307 if (document() != null)
308 document().toStrongRef()->forgetObject (self());
309
310 // Delete the GL lists
311 if (g_win != null)
312 g_win->R()->forgetObject (self());
313
314 // Remove this object from the list of LDObjects
315 g_allObjects.erase (g_allObjects.find (id()));
316 setDestructed (true);
317 }
318
319 //
320 // Deletes the object. Only the shared pointer is to call this!
321 //
322 void LDObject::finalDelete()
323 {
324 if (not isDestructed())
325 destroy();
326
327 delete this;
328 }
329
330 // =============================================================================
331 //
332 void LDObject::setDocument (const LDDocumentWeakPtr& a)
333 {
334 m_document = a;
335
336 if (a == null)
337 setSelected (false);
338 }
339
340 // =============================================================================
341 //
342 static void TransformObject (LDObjectPtr obj, Matrix transform, Vertex pos, LDColor parentcolor)
343 {
344 switch (obj->type())
345 {
346 case OBJ_Line:
347 case OBJ_CondLine:
348 case OBJ_Triangle:
349 case OBJ_Quad:
350 for (int i = 0; i < obj->numVertices(); ++i)
351 {
352 Vertex v = obj->vertex (i);
353 v.transform (transform, pos);
354 obj->setVertex (i, v);
355 }
356
357 break;
358
359 case OBJ_Subfile:
360 {
361 LDSubfilePtr ref = qSharedPointerCast<LDSubfile> (obj);
362 Matrix newMatrix = transform * ref->transform();
363 Vertex newpos = ref->position();
364 newpos.transform (transform, pos);
365 ref->setPosition (newpos);
366 ref->setTransform (newMatrix);
367 break;
368 }
369
370 default:
371 break;
372 }
373
374 if (obj->color() == MainColor())
375 obj->setColor (parentcolor);
376 }
377
378 // =============================================================================
379 // -----------------------------------------------------------------------------
380 LDObjectList LDSubfile::inlineContents (bool deep, bool render)
381 {
382 LDObjectList objs = fileInfo()->inlineContents (deep, render);
383
384 // Transform the objects
385 for (LDObjectPtr obj : objs)
386 {
387 // assert (obj->type() != OBJ_Subfile);
388 // Set the parent now so we know what inlined the object.
389 obj->setParent (self());
390 TransformObject (obj, transform(), position(), color());
391 }
392
393 return objs;
394 }
395
396 // =============================================================================
397 //
398 LDPolygon* LDObject::getPolygon()
399 {
400 LDObjectType ot = type();
401 int num = (ot == OBJ_Line) ? 2
402 : (ot == OBJ_Triangle) ? 3
403 : (ot == OBJ_Quad) ? 4
404 : (ot == OBJ_CondLine) ? 5
405 : 0;
406
407 if (num == 0)
408 return null;
409
410 LDPolygon* data = new LDPolygon;
411 data->id = id();
412 data->num = num;
413 data->color = color().index();
414
415 for (int i = 0; i < data->numVertices(); ++i)
416 data->vertices[i] = vertex (i);
417
418 return data;
419 }
420
421 // =============================================================================
422 //
423 QList<LDPolygon> LDSubfile::inlinePolygons()
424 {
425 QList<LDPolygon> data = fileInfo()->inlinePolygons();
426
427 for (LDPolygon& entry : data)
428 {
429 for (int i = 0; i < entry.numVertices(); ++i)
430 entry.vertices[i].transform (transform(), position());
431 }
432
433 return data;
434 }
435
436 // =============================================================================
437 // -----------------------------------------------------------------------------
438 long LDObject::lineNumber() const
439 {
440 assert (document() != null);
441
442 for (int i = 0; i < document().toStrongRef()->getObjectCount(); ++i)
443 {
444 if (document().toStrongRef()->getObject (i) == this)
445 return i;
446 }
447
448 return -1;
449 }
450
451 // =============================================================================
452 //
453 void LDObject::moveObjects (LDObjectList objs, const bool up)
454 {
455 if (objs.isEmpty())
456 return;
457
458 // If we move down, we need to iterate the array in reverse order.
459 long const start = up ? 0 : (objs.size() - 1);
460 long const end = up ? objs.size() : -1;
461 long const incr = up ? 1 : -1;
462 LDObjectList objsToCompile;
463 LDDocumentPtr file = objs[0]->document();
464
465 for (long i = start; i != end; i += incr)
466 {
467 LDObjectPtr obj = objs[i];
468
469 long const idx = obj->lineNumber();
470 long const target = idx + (up ? -1 : 1);
471
472 if ((up and idx == 0) or (not up and idx == (long) file->objects().size() - 1l))
473 {
474 // One of the objects hit the extrema. If this happens, this should be the first
475 // object to be iterated on. Thus, nothing has changed yet and it's safe to just
476 // abort the entire operation.
477 assert (i == start);
478 return;
479 }
480
481 objsToCompile << obj;
482 objsToCompile << file->getObject (target);
483
484 obj->swap (file->getObject (target));
485 }
486
487 RemoveDuplicates (objsToCompile);
488
489 // The objects need to be recompiled, otherwise their pick lists are left with
490 // the wrong index colors which messes up selection.
491 for (LDObjectPtr obj : objsToCompile)
492 g_win->R()->compileObject (obj);
493 }
494
495 // =============================================================================
496 //
497 QString LDObject::typeName (LDObjectType type)
498 {
499 return LDObject::getDefault (type)->typeName();
500 }
501
502 // =============================================================================
503 //
504 QString LDObject::describeObjects (const LDObjectList& objs)
505 {
506 QString text;
507
508 if (objs.isEmpty())
509 return "nothing"; // :)
510
511 for (LDObjectType objType = OBJ_FirstType; objType < OBJ_NumTypes; ++objType)
512 {
513 int count = 0;
514
515 for (LDObjectPtr obj : objs)
516 {
517 if (obj->type() == objType)
518 count++;
519 }
520
521 if (count == 0)
522 continue;
523
524 if (not text.isEmpty())
525 text += ", ";
526
527 QString noun = format ("%1%2", typeName (objType), Plural (count));
528 text += format ("%1 %2", count, noun);
529 }
530
531 return text;
532 }
533
534 // =============================================================================
535 //
536 LDObjectPtr LDObject::topLevelParent()
537 {
538 if (parent() == null)
539 return self();
540
541 LDObjectWeakPtr it (self());
542
543 while (it.toStrongRef()->parent() != null)
544 it = it.toStrongRef()->parent();
545
546 return it.toStrongRef();
547 }
548
549 // =============================================================================
550 //
551 LDObjectPtr LDObject::next() const
552 {
553 long idx = lineNumber();
554 assert (idx != -1);
555
556 if (idx == (long) document().toStrongRef()->getObjectCount() - 1)
557 return LDObjectPtr();
558
559 return document().toStrongRef()->getObject (idx + 1);
560 }
561
562 // =============================================================================
563 //
564 LDObjectPtr LDObject::previous() const
565 {
566 long idx = lineNumber();
567 assert (idx != -1);
568
569 if (idx == 0)
570 return LDObjectPtr();
571
572 return document().toStrongRef()->getObject (idx - 1);
573 }
574
575 // =============================================================================
576 //
577 bool LDObject::previousIsInvertnext (LDBFCPtr& ptr)
578 {
579 LDObjectPtr prev (previous());
580
581 if (prev != null and prev->type() == OBJ_BFC and
582 prev.staticCast<LDBFC>()->statement() == BFCStatement::InvertNext)
583 {
584 ptr = prev.staticCast<LDBFC>();
585 return true;
586 }
587
588 return false;
589 }
590
591 // =============================================================================
592 //
593 void LDObject::move (Vertex vect)
594 {
595 if (hasMatrix())
596 {
597 LDMatrixObjectPtr mo = self().toStrongRef().dynamicCast<LDMatrixObject>();
598 mo->setPosition (mo->position() + vect);
599 }
600 else
601 {
602 for (int i = 0; i < numVertices(); ++i)
603 setVertex (i, vertex (i) + vect);
604 }
605 }
606
607 // =============================================================================
608 //
609 LDObjectPtr LDObject::getDefault (const LDObjectType type)
610 {
611 switch (type)
612 {
613 case OBJ_Comment: return LDSpawn<LDComment>();
614 case OBJ_BFC: return LDSpawn<LDBFC>();
615 case OBJ_Line: return LDSpawn<LDLine>();
616 case OBJ_CondLine: return LDSpawn<LDCondLine>();
617 case OBJ_Subfile: return LDSpawn<LDSubfile>();
618 case OBJ_Triangle: return LDSpawn<LDTriangle>();
619 case OBJ_Quad: return LDSpawn<LDQuad>();
620 case OBJ_Empty: return LDSpawn<LDEmpty>();
621 case OBJ_Error: return LDSpawn<LDError>();
622 case OBJ_Overlay: return LDSpawn<LDOverlay>();
623 case OBJ_NumTypes: assert (false);
624 }
625 return LDObjectPtr();
626 }
627
628 // =============================================================================
629 //
630 void LDObject::invert() {}
631 void LDBFC::invert() {}
632 void LDEmpty::invert() {}
633 void LDComment::invert() {}
634 void LDError::invert() {}
635
636 // =============================================================================
637 //
638 void LDTriangle::invert()
639 {
640 // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1.
641 // Thus, we swap 1 and 2.
642 Vertex tmp = vertex (1);
643 setVertex (1, vertex (2));
644 setVertex (2, tmp);
645
646 return;
647 }
648
649 // =============================================================================
650 //
651 void LDQuad::invert()
652 {
653 // Quad: 0 -> 1 -> 2 -> 3
654 // rev: 0 -> 3 -> 2 -> 1
655 // Thus, we swap 1 and 3.
656 Vertex tmp = vertex (1);
657 setVertex (1, vertex (3));
658 setVertex (3, tmp);
659 }
660
661 // =============================================================================
662 //
663 void LDSubfile::invert()
664 {
665 if (document() == null)
666 return;
667
668 // Check whether subfile is flat
669 int axisSet = (1 << X) | (1 << Y) | (1 << Z);
670 LDObjectList objs = fileInfo()->inlineContents (true, false);
671
672 for (LDObjectPtr obj : objs)
673 {
674 for (int i = 0; i < obj->numVertices(); ++i)
675 {
676 Vertex const& vrt = obj->vertex (i);
677
678 if (axisSet & (1 << X) and vrt.x() != 0.0)
679 axisSet &= ~(1 << X);
680
681 if (axisSet & (1 << Y) and vrt.y() != 0.0)
682 axisSet &= ~(1 << Y);
683
684 if (axisSet & (1 << Z) and vrt.z() != 0.0)
685 axisSet &= ~(1 << Z);
686 }
687
688 if (axisSet == 0)
689 break;
690 }
691
692 if (axisSet != 0)
693 {
694 // Subfile has all vertices zero on one specific plane, so it is flat.
695 // Let's flip it.
696 Matrix matrixModifier = IdentityMatrix;
697
698 if (axisSet & (1 << X))
699 matrixModifier[0] = -1;
700
701 if (axisSet & (1 << Y))
702 matrixModifier[4] = -1;
703
704 if (axisSet & (1 << Z))
705 matrixModifier[8] = -1;
706
707 setTransform (transform() * matrixModifier);
708 return;
709 }
710
711 // Subfile is not flat. Resort to invertnext.
712 int idx = lineNumber();
713
714 if (idx > 0)
715 {
716 LDBFCPtr bfc = previous().dynamicCast<LDBFC>();
717
718 if (not bfc.isNull() and bfc->statement() == BFCStatement::InvertNext)
719 {
720 // This is prefixed with an invertnext, thus remove it.
721 bfc->destroy();
722 return;
723 }
724 }
725
726 // Not inverted, thus prefix it with a new invertnext.
727 document().toStrongRef()->insertObj (idx, LDSpawn<LDBFC> (BFCStatement::InvertNext));
728 }
729
730 // =============================================================================
731 //
732 void LDLine::invert()
733 {
734 // For lines, we swap the vertices.
735 Vertex tmp = vertex (0);
736 setVertex (0, vertex (1));
737 setVertex (1, tmp);
738 }
739
740 // =============================================================================
741 //
742 void LDCondLine::invert()
743 {
744 // I don't think that a conditional line's control points need to be
745 // swapped, do they?
746 Vertex tmp = vertex (0);
747 setVertex (0, vertex (1));
748 setVertex (1, tmp);
749 }
750
751 // =============================================================================
752 //
753 LDLinePtr LDCondLine::toEdgeLine()
754 {
755 LDLinePtr replacement (LDSpawn<LDLine>());
756
757 for (int i = 0; i < replacement->numVertices(); ++i)
758 replacement->setVertex (i, vertex (i));
759
760 replacement->setColor (color());
761
762 replace (replacement);
763 return replacement;
764 }
765
766 // =============================================================================
767 //
768 LDObjectPtr LDObject::fromID (int id)
769 {
770 auto it = g_allObjects.find (id);
771
772 if (it != g_allObjects.end())
773 return *it;
774
775 return LDObjectPtr();
776 }
777
778 // =============================================================================
779 //
780 QString LDOverlay::asText() const
781 {
782 return format ("0 !LDFORGE OVERLAY %1 %2 %3 %4 %5 %6",
783 fileName(), camera(), x(), y(), width(), height());
784 }
785
786 void LDOverlay::invert() {}
787
788 // =============================================================================
789 //
790 // Hook the set accessors of certain properties to this changeProperty function.
791 // It takes care of history management so we can capture low-level changes, this
792 // makes history stuff work out of the box.
793 //
794 template<typename T>
795 static void changeProperty (LDObjectPtr obj, T* ptr, const T& val)
796 {
797 long idx;
798
799 if (*ptr == val)
800 return;
801
802 if (obj->document() != null and (idx = obj->lineNumber()) != -1)
803 {
804 QString before = obj->asText();
805 *ptr = val;
806 QString after = obj->asText();
807
808 if (before != after)
809 {
810 obj->document().toStrongRef()->addToHistory (new EditHistory (idx, before, after));
811 g_win->R()->compileObject (obj);
812 CurrentDocument()->redoVertices();
813 }
814 }
815 else
816 *ptr = val;
817 }
818
819 // =============================================================================
820 //
821 void LDObject::setColor (LDColor const& val)
822 {
823 changeProperty (self(), &m_color, val);
824 }
825
826 // =============================================================================
827 //
828 const Vertex& LDObject::vertex (int i) const
829 {
830 return m_coords[i];
831 }
832
833 // =============================================================================
834 //
835 void LDObject::setVertex (int i, const Vertex& vert)
836 {
837 changeProperty (self(), &m_coords[i], vert);
838 }
839
840 // =============================================================================
841 //
842 void LDMatrixObject::setPosition (const Vertex& a)
843 {
844 changeProperty (self(), &m_position, a);
845 }
846
847 // =============================================================================
848 //
849 void LDMatrixObject::setTransform (const Matrix& val)
850 {
851 changeProperty (self(), &m_transform, val);
852 }
853
854 // =============================================================================
855 //
856 void LDObject::select()
857 {
858 assert (document() != null);
859 document().toStrongRef()->addToSelection (self());
860
861 // If this object is inverted with INVERTNEXT, pick the INVERTNEXT as well.
862 /*
863 LDBFCPtr invertnext;
864
865 if (previousIsInvertnext (invertnext))
866 invertnext->select();
867 */
868 }
869
870 // =============================================================================
871 //
872 void LDObject::deselect()
873 {
874 assert (document() != null);
875 document().toStrongRef()->removeFromSelection (self());
876
877 // If this object is inverted with INVERTNEXT, deselect the INVERTNEXT as well.
878 LDBFCPtr invertnext;
879
880 if (previousIsInvertnext (invertnext))
881 invertnext->deselect();
882 }
883
884 // =============================================================================
885 //
886 QString PreferredLicenseText()
887 {
888 return (cfg::UseCALicense ? CALicenseText : "");
889 }
890
891 // =============================================================================
892 //
893 LDObjectPtr LDObject::createCopy() const
894 {
895 LDObjectPtr copy = ParseLine (asText());
896 return copy;
897 }
898
899 // =============================================================================
900 //
901 void LDSubfile::setFileInfo (const LDDocumentPtr& a)
902 {
903 changeProperty (self(), &m_fileInfo, a);
904
905 // If it's an immediate subfile reference (i.e. this subfile belongs in an
906 // explicit file), we need to pre-compile the GL polygons for the document
907 // if they don't exist already.
908 if (a != null and
909 a->isImplicit() == false and
910 a->polygonData().isEmpty())
911 {
912 a->initializeCachedData();
913 }
914 };
915
916 void LDObject::getVertices (QVector<Vertex>& verts) const
917 {
918 for (int i = 0; i < numVertices(); ++i)
919 verts << vertex (i);
920 }
921
922 void LDSubfile::getVertices (QVector<Vertex>& verts) const
923 {
924 verts << fileInfo()->inlineVertices();
925 }

mercurial