3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/01/2010 Added this text. :-)
17 #include "modification.h"
19 #include "clipboard.h"
23 #include "information.h"
30 * Default constructor.
32 * @param container The container to which we will add
33 * entities. Usually that's an Drawing entity but
34 * it can also be a polyline, text, ...
35 * @param graphicView Pointer to graphic view or NULL if you don't want the
36 * any views to be updated.
37 * @param handleUndo true: Handle undo functionalitiy.
39 Modification::Modification(EntityContainer & container,
40 GraphicView * graphicView, bool handleUndo)
42 this->container = &container;
43 this->graphicView = graphicView;
44 this->handleUndo = handleUndo;
45 graphic = container.getGraphic();
46 document = container.getDocument();
50 * Deletes all selected entities.
52 void Modification::remove()
54 if (container == NULL)
56 DEBUG->print("Modification::remove: no valid container", Debug::D_WARNING);
61 document->startUndoCycle();
64 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
66 if (e && e->isSelected())
68 e->setSelected(false);
72 document->addUndoable(e);
77 document->endUndoCycle();
79 graphicView->redraw();
83 * Changes the attributes of all selected
85 bool Modification::changeAttributes(AttributesData & data)
89 DEBUG->print("Modification::changeAttributes: no valid container", Debug::D_WARNING);
93 QList<Entity *> addList;
96 document->startUndoCycle();
98 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
100 //for (uint i=0; i<container->count(); ++i) {
101 //Entity* e = container->entityAt(i);
102 if (e && e->isSelected())
104 Entity * ec = e->clone();
105 ec->setSelected(false);
107 Pen pen = ec->getPen(false);
109 if (data.changeLayer == true)
110 ec->setLayer(data.layer);
112 if (data.changeColor == true)
113 pen.setColor(data.pen.getColor());
115 if (data.changeLineType == true)
116 pen.setLineType(data.pen.getLineType());
118 if (data.changeWidth == true)
119 pen.setWidth(data.pen.getWidth());
123 //if (data.useCurrentLayer) {
124 // ec->setLayerToActive();
126 //if (data.useCurrentAttributes) {
127 // ec->setPenToActive();
129 //if (ec->rtti()==RS2::EntityInsert) {
130 // ((Insert*)ec)->update();
137 deselectOriginals(true);
138 addNewEntities(addList);
141 document->endUndoCycle();
144 graphicView->redraw();
151 * Copies all selected entities from the given container to the clipboard.
152 * Layers and blocks that are needed are also copied if the container is
153 * or is part of an Drawing.
155 * @param container The entity container.
156 * @param ref Reference point. The entities will be moved by -ref.
157 * @param cut true: cut instead of copying, false: copy
159 void Modification::copy(const Vector& ref, const bool cut) {
161 if (container==NULL) {
162 DEBUG->print("Modification::copy: no valid container",
169 CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
171 CLIPBOARD->getGraphic()->setUnit(RS2::None);
174 // start undo cycle for the container if we're cutting
175 if (cut && document!=NULL) {
176 document->startUndoCycle();
179 // copy entities / layers / blocks
180 for (Entity* e=container->firstEntity(); e!=NULL;
181 e=container->nextEntity()) {
182 //for (uint i=0; i<container->count(); ++i) {
183 //Entity* e = container->entityAt(i);
185 if (e!=NULL && e->isSelected()) {
186 copyEntity(e, ref, cut);
190 if (cut && document!=NULL) {
191 document->endUndoCycle();
198 * Copies the given entity from the given container to the clipboard.
199 * Layers and blocks that are needed are also copied if the container is
200 * or is part of an Drawing.
202 * @param e The entity.
203 * @param ref Reference point. The entities will be moved by -ref.
204 * @param cut true: cut instead of copying, false: copy
206 void Modification::copyEntity(Entity * e, const Vector & ref, const bool cut)
208 if (e && e->isSelected())
210 // delete entity in graphic view:
213 #warning "!!! Old rendering path needs upgrading !!!"
216 graphicView->deleteEntity(e);
219 e->setSelected(false);
223 #warning "!!! Old rendering path needs upgrading !!!"
226 graphicView->deleteEntity(e);
229 e->setSelected(false);
231 #warning "!!! Old rendering path needs upgrading !!!"
234 graphicView->drawEntity(e);
238 // add entity to clipboard:
239 Entity * c = e->clone();
241 CLIPBOARD->addEntity(c);
246 // set layer to the layer clone:
247 Layer * l = e->getLayer();
250 c->setLayer(l->getName());
252 // make sure all sub entities point to layers of the clipboard
253 if (c->isContainer())
255 EntityContainer * ec = (EntityContainer *)c;
257 for(Entity * e2=ec->firstEntity(RS2::ResolveAll); e2!=NULL;
258 e2=ec->nextEntity(RS2::ResolveAll))
260 //Entity* e2 = ec->entityAt(i);
261 Layer * l2 = e2->getLayer();
264 e2->setLayer(l2->getName());
270 e->changeUndoState();
273 document->addUndoable(e);
281 * Copies all layers of the given entity to the clipboard.
283 void Modification::copyLayers(Entity* e) {
289 // add layer(s) of the entity if it's not an insert
290 // (inserts are on layer '0'):
291 if (e->rtti()!=RS2::EntityInsert) {
292 Layer* l = e->getLayer();
294 if (!CLIPBOARD->hasLayer(l->getName())) {
295 CLIPBOARD->addLayer(l->clone());
300 // special handling of inserts:
302 // insert: add layer(s) of subentities:
303 Block* b = ((Insert*)e)->getBlockForInsert();
305 for (Entity* e2=b->firstEntity(); e2!=NULL;
306 e2=b->nextEntity()) {
307 //for (uint i=0; i<b->count(); ++i) {
308 //Entity* e2 = b->entityAt(i);
318 * Copies all blocks of the given entity to the clipboard.
320 void Modification::copyBlocks(Entity* e) {
326 // add block of the entity if it's an insert
327 if (e->rtti()==RS2::EntityInsert) {
328 Block* b = ((Insert*)e)->getBlockForInsert();
330 // add block of an insert:
331 if (!CLIPBOARD->hasBlock(b->getName())) {
332 CLIPBOARD->addBlock((Block*)b->clone());
335 for (Entity* e2=b->firstEntity(); e2!=NULL;
336 e2=b->nextEntity()) {
337 //for (uint i=0; i<b->count(); ++i) {
338 //Entity* e2 = b->entityAt(i);
348 * Pastes all entities from the clipboard into the container.
349 * Layers and blocks that are needed are also copied if the container is
350 * or is part of an Drawing.
352 * @param data Paste data.
353 * @param source The source from where to paste. NULL means the source
356 void Modification::paste(const PasteData& data, Drawing* source) {
359 DEBUG->print(Debug::D_WARNING,
360 "Modification::paste: Graphic is NULL");
367 source = CLIPBOARD->getGraphic();
369 // graphics from the clipboard need to be scaled. from the part lib not:
370 RS2::Unit sourceUnit = source->getUnit();
371 RS2::Unit targetUnit = graphic->getUnit();
372 factor = Units::convert(1.0, sourceUnit, targetUnit);
375 if (document!=NULL) {
376 document->startUndoCycle();
382 Layer* layer = graphic->getActiveLayer();
383 for(uint i=0; i<source->countLayers(); ++i) {
384 Layer* l = source->layerAt(i);
386 if (graphic->findLayer(l->getName())==NULL) {
387 graphic->addLayer(l->clone());
391 graphic->activateLayer(layer);
396 for(uint i=0; i<source->countBlocks(); ++i) {
397 Block* b = source->blockAt(i);
399 if (graphic->findBlock(b->getName())==NULL) {
400 Block* bc = (Block*)b->clone();
401 bc->reparent(container);
402 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
403 // scale block but don't scale inserts in block
404 // (they already scale with their block)
405 for(uint i2=0; i2<bc->count(); ++i2) {
406 Entity* e = bc->entityAt(i2);
407 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
408 e->scale(bc->getBasePoint(),
409 Vector(factor, factor));
411 Vector ip = ((Insert*)e)->getInsertionPoint();
412 ip.scale(bc->getBasePoint(),
413 Vector(factor, factor));
414 ((Insert*)e)->setInsertionPoint(ip);
419 graphic->addBlock(bc);
425 // add entities to this host (graphic or a new block)
426 EntityContainer* host = container;
431 if (data.asInsert==true) {
432 BlockList* blkList = graphic->getBlockList();
434 blockName = blkList->newName(data.blockName);
439 Vector(0.0,0.0), false));
440 graphic->addBlock(blk);
448 //for (uint i=0; i<((EntityContainer*)source)->count(); ++i) {
449 //Entity* e = source->entityAt(i);
450 for (Entity* e=((EntityContainer*)source)->firstEntity();
452 e=((EntityContainer*)source)->nextEntity()) {
456 QString layerName = "0";
457 Layer* layer = e->getLayer();
459 layerName = layer->getName();
461 Entity* e2 = e->clone();
463 if (data.asInsert==false) {
464 e2->move(data.insertionPoint);
466 // don't adjust insert factor - block was already adjusted to unit
467 if (e2->rtti()==RS2::EntityInsert) {
468 Vector ip = ((Insert*)e2)->getInsertionPoint();
469 ip.scale(data.insertionPoint, Vector(factor, factor));
470 ((Insert*)e2)->setInsertionPoint(ip);
473 e2->scale(data.insertionPoint, Vector(factor, factor));
476 e2->setLayer(layerName);
478 // make sure all sub entities point to layers of the container
479 if (e2->isContainer()) {
480 EntityContainer* ec = (EntityContainer*)e2;
482 for (Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
483 e3 = ec->nextEntity(RS2::ResolveAll)) {
485 //Entity* e3 = ec->entityAt(i);
486 Layer* l2 = e3->getLayer();
488 e3->setLayer(l2->getName());
493 if (document!=NULL && data.asInsert==false) {
494 document->addUndoable(e2);
499 if (data.asInsert==true) {
501 new Insert(container,
505 Vector(data.factor, data.factor),
507 1,1,Vector(0.0,0.0)));
508 container->addEntity(ins);
509 ins->setLayerToActive();
510 ins->setPenToActive();
512 if (document!=NULL) {
513 document->addUndoable(ins);
517 if (document!=NULL) {
518 document->endUndoCycle();
524 * Splits a polyline into two leaving out a gap.
526 * @param polyline The original polyline
527 * @param e1 1st entity on which the first cutting point is.
528 * @param v1 1st cutting point.
529 * @param e2 2nd entity on which the first cutting point is.
530 * @param v2 2nd cutting point.
531 * @param polyline1 Pointer to a polyline pointer which will hold the
532 * 1st resulting new polyline. Pass NULL if you don't
533 * need those pointers.
534 * @param polyline2 Pointer to a polyline pointer which will hold the
535 * 2nd resulting new polyline. Pass NULL if you don't
536 * need those pointers.
538 * @todo Support arcs in polylines, check for wrong parameters
542 bool Modification::splitPolyline(Polyline& polyline,
543 Entity& e1, Vector v1,
544 Entity& e2, Vector v2,
545 Polyline** polyline1,
546 Polyline** polyline2) const {
548 if (container==NULL) {
549 DEBUG->print("Modification::splitPolyline: no valid container",
554 Entity* firstEntity = polyline.firstEntity();
555 Vector firstPoint(false);
556 if (firstEntity->rtti()==RS2::EntityLine) {
557 firstPoint = ((Line*)firstEntity)->getStartpoint();
560 new Polyline(container,
561 PolylineData(firstPoint, Vector(0.0,0.0), 0));
562 Polyline* pl2 = new Polyline(container);
563 Polyline* pl = pl1; // Current polyline
567 if (polyline1!=NULL) {
570 if (polyline2!=NULL) {
574 for (Entity* e = polyline.firstEntity();
576 e = polyline.nextEntity()) {
578 if (e->rtti()==RS2::EntityLine) {
581 } else if (e->rtti()==RS2::EntityArc) {
589 if (line!=NULL /*|| arc!=NULL*/) {
591 if (e==&e1 && e==&e2) {
592 // Trim within a single entity:
593 Vector sp = line->getStartpoint();
594 double dist1 = (v1-sp).magnitude();
595 double dist2 = (v2-sp).magnitude();
596 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
598 pl->setStartpoint(dist1<dist2 ? v2 : v1);
599 pl->addVertex(line->getEndpoint(), 0.0);
600 } else if (e==&e1 || e==&e2) {
602 Vector v = (e==&e1 ? v1 : v2);
604 // Trim endpoint of entity to first vector
605 pl->addVertex(v, 0.0);
608 // Trim startpoint of entity to second vector
610 pl->setStartpoint(v);
611 pl->addVertex(line->getEndpoint(), 0.0);
614 // Add entities to polylines
615 if (line!=NULL && pl!=NULL) {
616 pl->addVertex(line->getEndpoint(), 0.0);
622 container->addEntity(pl1);
623 container->addEntity(pl2);
624 //container->removeEntity(&polyline);
625 polyline.changeUndoState();
633 * Adds a node to the given polyline. The new node is placed between
634 * the start and end point of the given segment.
636 * @param node The position of the new node.
638 * @return Pointer to the new polyline or NULL.
641 Polyline* Modification::addPolylineNode(Polyline& polyline,
642 const AtomicEntity& segment,
643 const Vector& node) {
644 DEBUG->print("Modification::addPolylineNode");
646 if (container==NULL) {
647 DEBUG->print("Modification::addPolylineNode: no valid container",
652 if (segment.getParent()!=&polyline) {
653 DEBUG->print("Modification::addPolylineNode: "
654 "segment not part of the polyline",
659 Polyline* newPolyline = new Polyline(container);
660 newPolyline->setClosed(polyline.isClosed());
661 newPolyline->setSelected(polyline.isSelected());
662 newPolyline->setLayer(polyline.getLayer());
663 newPolyline->setPen(polyline.getPen());
665 // copy polyline and add new node:
667 Entity* lastEntity = polyline.lastEntity();
668 for (Entity* e=polyline.firstEntity(); e!=NULL;
669 e=polyline.nextEntity()) {
672 AtomicEntity* ae = (AtomicEntity*)e;
674 if (ae->rtti()==RS2::EntityArc) {
675 DEBUG->print("Modification::addPolylineNode: arc segment");
676 bulge = ((Arc*)ae)->getBulge();
678 DEBUG->print("Modification::addPolylineNode: line segment");
683 DEBUG->print("Modification::addPolylineNode: first segment: %f/%f",
684 ae->getStartpoint().x, ae->getStartpoint().y);
686 newPolyline->setNextBulge(bulge);
687 newPolyline->addVertex(ae->getStartpoint());
693 DEBUG->print("Modification::addPolylineNode: split segment found");
695 DEBUG->print("Modification::addPolylineNode: node: %f/%f",
698 newPolyline->setNextBulge(0.0);
699 newPolyline->addVertex(node);
701 DEBUG->print("Modification::addPolylineNode: after node: %f/%f",
702 ae->getEndpoint().x, ae->getEndpoint().y);
704 if (ae!=lastEntity || polyline.isClosed()==false) {
705 newPolyline->setNextBulge(0.0);
706 newPolyline->addVertex(ae->getEndpoint());
709 DEBUG->print("Modification::addPolylineNode: normal vertex found: %f/%f",
710 ae->getEndpoint().x, ae->getEndpoint().y);
712 if (ae!=lastEntity || polyline.isClosed()==false) {
713 newPolyline->setNextBulge(bulge);
714 newPolyline->addVertex(ae->getEndpoint());
718 DEBUG->print("Modification::addPolylineNode: "
719 "Polyline contains non-atomic entities",
724 newPolyline->setNextBulge(polyline.getClosingBulge());
725 newPolyline->endPolyline();
728 container->addEntity(newPolyline);
729 if (graphicView!=NULL) {
730 graphicView->deleteEntity(&polyline);
731 graphicView->drawEntity(newPolyline);
734 if (document!=NULL && handleUndo) {
735 document->startUndoCycle();
737 polyline.setUndoState(true);
738 document->addUndoable(&polyline);
739 document->addUndoable(newPolyline);
741 document->endUndoCycle();
751 * Deletes a node from a polyline.
753 * @param node The node to delete.
755 * @return Pointer to the new polyline or NULL.
758 Polyline* Modification::deletePolylineNode(Polyline& polyline,
759 const Vector& node) {
761 DEBUG->print("Modification::deletePolylineNode");
763 if (container==NULL) {
764 DEBUG->print("Modification::addPolylineNode: no valid container",
769 if (node.valid==false) {
770 DEBUG->print("Modification::deletePolylineNode: "
776 // check if the polyline is no longer there after deleting the node:
777 if (polyline.count()==1) {
778 Entity* e = polyline.firstEntity();
779 if (e!=NULL && e->isAtomic()) {
780 AtomicEntity* ae = (AtomicEntity*)e;
781 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
782 node.distanceTo(ae->getEndpoint())<1.0e-6) {
784 if (graphicView!=NULL) {
785 graphicView->deleteEntity(&polyline);
788 if (document!=NULL && handleUndo) {
789 document->startUndoCycle();
790 polyline.setUndoState(true);
791 document->addUndoable(&polyline);
792 document->endUndoCycle();
799 Polyline* newPolyline = new Polyline(container);
800 newPolyline->setClosed(polyline.isClosed());
801 newPolyline->setSelected(polyline.isSelected());
802 newPolyline->setLayer(polyline.getLayer());
803 newPolyline->setPen(polyline.getPen());
805 // copy polyline and drop deleted node:
807 bool lastDropped = false;
808 Entity* lastEntity = polyline.lastEntity();
809 for (Entity* e=polyline.firstEntity(); e!=NULL;
810 e=polyline.nextEntity()) {
813 AtomicEntity* ae = (AtomicEntity*)e;
815 if (ae->rtti()==RS2::EntityArc) {
816 DEBUG->print("Modification::deletePolylineNode: arc segment");
817 bulge = ((Arc*)ae)->getBulge();
819 DEBUG->print("Modification::deletePolylineNode: line segment");
823 // last entity is closing entity and will be added below with endPolyline()
824 if (e==lastEntity && polyline.isClosed()) {
828 // first vertex (startpoint)
829 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
830 DEBUG->print("Modification::deletePolylineNode: first node: %f/%f",
831 ae->getStartpoint().x, ae->getStartpoint().y);
833 newPolyline->setNextBulge(bulge);
834 newPolyline->addVertex(ae->getStartpoint());
838 // normal node (not deleted):
839 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
840 DEBUG->print("Modification::deletePolylineNode: normal vertex found: %f/%f",
841 ae->getEndpoint().x, ae->getEndpoint().y);
845 newPolyline->setNextBulge(bulge);
846 newPolyline->addVertex(ae->getEndpoint());
850 // drop deleted node:
852 DEBUG->print("Modification::deletePolylineNode: deleting vertex: %f/%f",
853 ae->getEndpoint().x, ae->getEndpoint().y);
857 DEBUG->print("Modification::deletePolylineNode: "
858 "Polyline contains non-atomic entities",
863 DEBUG->print("Modification::deletePolylineNode: ending polyline");
864 newPolyline->setNextBulge(polyline.getClosingBulge());
865 newPolyline->endPolyline();
867 //if (newPolyline->count()==1) {
871 DEBUG->print("Modification::deletePolylineNode: adding new polyline");
872 container->addEntity(newPolyline);
873 if (graphicView!=NULL) {
874 graphicView->deleteEntity(&polyline);
875 graphicView->drawEntity(newPolyline);
878 DEBUG->print("Modification::deletePolylineNode: handling undo");
879 if (document!=NULL && handleUndo) {
880 document->startUndoCycle();
882 polyline.setUndoState(true);
883 document->addUndoable(&polyline);
884 document->addUndoable(newPolyline);
886 document->endUndoCycle();
896 * Deletes all nodes between the two given nodes (exclusive).
898 * @param node1 First limiting node.
899 * @param node2 Second limiting node.
901 * @return Pointer to the new polyline or NULL.
904 Polyline* Modification::deletePolylineNodesBetween(Polyline& polyline,
905 AtomicEntity& segment, const Vector& node1, const Vector& node2) {
907 DEBUG->print("Modification::deletePolylineNodesBetween");
909 if (container==NULL) {
910 DEBUG->print("Modification::addPolylineNodesBetween: no valid container",
915 if (node1.valid==false || node2.valid==false) {
916 DEBUG->print("Modification::deletePolylineNodesBetween: "
922 if (node1.distanceTo(node2)<1.0e-6) {
923 DEBUG->print("Modification::deletePolylineNodesBetween: "
924 "nodes are identical",
929 // check if there's nothing to delete:
930 for (Entity* e=polyline.firstEntity(); e!=NULL;
931 e=polyline.nextEntity()) {
934 AtomicEntity* ae = (AtomicEntity*)e;
936 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
937 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
938 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
939 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
941 DEBUG->print("Modification::deletePolylineNodesBetween: "
950 // check if the start point is involved:
951 bool startpointInvolved = false;
952 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
953 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
954 startpointInvolved = true;
958 // check which part of the polyline has to be deleted:
959 bool deleteStart = false;
960 if (polyline.isClosed()) {
962 double length1 = 0.0;
963 double length2 = 0.0;
964 Entity* e=polyline.firstEntity();
966 if (startpointInvolved) {
968 AtomicEntity* ae = (AtomicEntity*)e;
969 length1+=ae->getLength();
971 e = polyline.nextEntity();
973 for (; e!=NULL; e=polyline.nextEntity()) {
976 AtomicEntity* ae = (AtomicEntity*)e;
978 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
979 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
985 length2+=ae->getLength();
987 length1+=ae->getLength();
991 if (length1<length2) {
998 Polyline* newPolyline = new Polyline(container);
999 newPolyline->setClosed(polyline.isClosed());
1000 newPolyline->setSelected(polyline.isSelected());
1001 newPolyline->setLayer(polyline.getLayer());
1002 newPolyline->setPen(polyline.getPen());
1004 if (startpointInvolved && deleteStart && polyline.isClosed()) {
1005 newPolyline->setNextBulge(0.0);
1006 newPolyline->addVertex(polyline.getStartpoint());
1009 // copy polyline and drop deleted nodes:
1011 bool removing = deleteStart;
1013 bool nextIsStraight = false;
1014 Entity* lastEntity = polyline.lastEntity();
1017 for (Entity* e=polyline.firstEntity(); e!=NULL;
1018 e=polyline.nextEntity()) {
1020 DEBUG->print("Modification::deletePolylineNodesBetween: entity: %d", i++);
1021 DEBUG->print("Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1023 if (e->isAtomic()) {
1024 AtomicEntity* ae = (AtomicEntity*)e;
1025 if (ae->rtti()==RS2::EntityArc) {
1026 DEBUG->print("Modification::deletePolylineNodesBetween: arc segment");
1027 bulge = ((Arc*)ae)->getBulge();
1029 DEBUG->print("Modification::deletePolylineNodesBetween: line segment");
1033 // last entity is closing entity and will be added below with endPolyline()
1034 if (e==lastEntity && polyline.isClosed()) {
1035 DEBUG->print("Modification::deletePolylineNodesBetween: "
1036 "dropping last vertex of closed polyline");
1040 // first vertex (startpoint)
1043 DEBUG->print("Modification::deletePolylineNodesBetween: first node: %f/%f",
1044 ae->getStartpoint().x, ae->getStartpoint().y);
1045 newPolyline->setNextBulge(bulge);
1046 newPolyline->addVertex(ae->getStartpoint());
1051 // stop removing nodes:
1052 if (removing==true &&
1053 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1054 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1055 DEBUG->print("Modification::deletePolylineNodesBetween: "
1056 "stop removing at: %f/%f",
1057 ae->getEndpoint().x, ae->getEndpoint().y);
1061 nextIsStraight = true;
1065 // normal node (not deleted):
1066 if (removing==false && (done==false || deleteStart==false)) {
1067 DEBUG->print("Modification::deletePolylineNodesBetween: "
1068 "normal vertex found: %f/%f",
1069 ae->getEndpoint().x, ae->getEndpoint().y);
1070 if (nextIsStraight) {
1072 nextIsStraight = false;
1074 newPolyline->setNextBulge(bulge);
1075 newPolyline->addVertex(ae->getEndpoint());
1078 // drop deleted node:
1080 DEBUG->print("Modification::deletePolylineNodesBetween: "
1081 "deleting vertex: %f/%f",
1082 ae->getEndpoint().x, ae->getEndpoint().y);
1085 // start to remove nodes from now on:
1086 if (done==false && removing==false &&
1087 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1088 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1089 DEBUG->print("Modification::deletePolylineNodesBetween: "
1090 "start removing at: %f/%f",
1091 ae->getEndpoint().x, ae->getEndpoint().y);
1099 DEBUG->print("Modification::deletePolylineNodesBetween: "
1100 "Polyline contains non-atomic entities",
1105 DEBUG->print("Modification::deletePolylineNodesBetween: ending polyline");
1106 newPolyline->setNextBulge(polyline.getClosingBulge());
1107 newPolyline->endPolyline();
1109 // add new polyline:
1110 DEBUG->print("Modification::deletePolylineNodesBetween: adding new polyline");
1111 container->addEntity(newPolyline);
1112 if (graphicView!=NULL) {
1113 graphicView->deleteEntity(&polyline);
1114 graphicView->drawEntity(newPolyline);
1117 DEBUG->print("Modification::deletePolylineNodesBetween: handling undo");
1118 if (document!=NULL && handleUndo) {
1119 document->startUndoCycle();
1121 polyline.setUndoState(true);
1122 document->addUndoable(&polyline);
1123 document->addUndoable(newPolyline);
1125 document->endUndoCycle();
1135 * Trims two segments of a polyline all nodes between the two trim segments
1138 * @param polyline The polyline entity.
1139 * @param segment1 First segment to trim.
1140 * @param segment2 Second segment to trim.
1142 * @return Pointer to the new polyline or NULL.
1145 Polyline* Modification::polylineTrim(Polyline& polyline,
1146 AtomicEntity& segment1,
1147 AtomicEntity& segment2) {
1149 DEBUG->print("Modification::polylineTrim");
1151 if (container==NULL) {
1152 DEBUG->print("Modification::addPolylineNodesBetween: no valid container",
1157 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1158 DEBUG->print("Modification::polylineTrim: "
1159 "segments not in polyline",
1164 if (&segment1==&segment2) {
1165 DEBUG->print("Modification::polylineTrim: "
1166 "segments are identical",
1171 VectorSolutions sol;
1172 sol = Information::getIntersection(&segment1, &segment2, false);
1174 if (sol.getNumber()==0) {
1175 DEBUG->print("Modification::polylineTrim: "
1176 "segments cannot be trimmed",
1181 // check which segment comes first in the polyline:
1182 AtomicEntity* firstSegment;
1183 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1184 firstSegment = &segment2;
1186 firstSegment = &segment1;
1189 // find out if we need to trim towards the open part of the polyline
1191 reverseTrim = !Math::isSameDirection(firstSegment->getDirection1(),
1192 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1193 //reverseTrim = reverseTrim || !Math::isSameDirection(segment2.getDirection1(),
1194 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1196 Polyline* newPolyline = new Polyline(container);
1197 newPolyline->setClosed(polyline.isClosed());
1198 newPolyline->setSelected(polyline.isSelected());
1199 newPolyline->setLayer(polyline.getLayer());
1200 newPolyline->setPen(polyline.getPen());
1202 // normal trimming: start removing nodes at trim segment. ends stay the same
1203 if (reverseTrim==false) {
1204 // copy polyline, trim segments and drop between nodes:
1206 bool removing = false;
1207 bool nextIsStraight = false;
1208 Entity* lastEntity = polyline.lastEntity();
1209 for (Entity* e=polyline.firstEntity(); e!=NULL;
1210 e=polyline.nextEntity()) {
1212 if (e->isAtomic()) {
1213 AtomicEntity* ae = (AtomicEntity*)e;
1215 if (ae->rtti()==RS2::EntityArc) {
1216 DEBUG->print("Modification::polylineTrim: arc segment");
1217 bulge = ((Arc*)ae)->getBulge();
1219 DEBUG->print("Modification::polylineTrim: line segment");
1223 // last entity is closing entity and will be added below with endPolyline()
1224 if (e==lastEntity && polyline.isClosed()) {
1225 DEBUG->print("Modification::polylineTrim: "
1226 "dropping last vertex of closed polyline");
1230 // first vertex (startpoint)
1232 DEBUG->print("Modification::polylineTrim: first node: %f/%f",
1233 ae->getStartpoint().x, ae->getStartpoint().y);
1235 newPolyline->setNextBulge(bulge);
1236 newPolyline->addVertex(ae->getStartpoint());
1240 // trim and start removing nodes:
1241 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1242 DEBUG->print("Modification::polylineTrim: "
1243 "start removing at trim point %f/%f",
1244 sol.get(0).x, sol.get(0).y);
1245 newPolyline->setNextBulge(0.0);
1246 newPolyline->addVertex(sol.get(0));
1248 nextIsStraight = true;
1251 // stop removing nodes:
1252 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1253 DEBUG->print("Modification::polylineTrim: stop removing at: %f/%f",
1254 ae->getEndpoint().x, ae->getEndpoint().y);
1258 // normal node (not deleted):
1259 if (removing==false) {
1260 DEBUG->print("Modification::polylineTrim: normal vertex found: %f/%f",
1261 ae->getEndpoint().x, ae->getEndpoint().y);
1262 if (nextIsStraight) {
1263 newPolyline->setNextBulge(0.0);
1264 nextIsStraight = false;
1266 newPolyline->setNextBulge(bulge);
1268 newPolyline->addVertex(ae->getEndpoint());
1271 DEBUG->print("Modification::polylineTrim: "
1272 "Polyline contains non-atomic entities",
1278 // reverse trimming: remove nodes at the ends and keep those in between
1280 // copy polyline, trim segments and drop between nodes:
1281 //bool first = true;
1282 bool removing = true;
1283 bool nextIsStraight = false;
1284 Entity* lastEntity = polyline.lastEntity();
1285 for (Entity* e=polyline.firstEntity(); e!=NULL;
1286 e=polyline.nextEntity()) {
1288 if (e->isAtomic()) {
1289 AtomicEntity* ae = (AtomicEntity*)e;
1291 if (ae->rtti()==RS2::EntityArc) {
1292 DEBUG->print("Modification::polylineTrim: arc segment");
1293 bulge = ((Arc*)ae)->getBulge();
1295 DEBUG->print("Modification::polylineTrim: line segment");
1299 // last entity is closing entity and will be added below with endPolyline()
1300 if (e==lastEntity && polyline.isClosed()) {
1301 DEBUG->print("Modification::polylineTrim: "
1302 "dropping last vertex of closed polyline");
1306 // trim and stop removing nodes:
1307 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1308 DEBUG->print("Modification::polylineTrim: "
1309 "stop removing at trim point %f/%f",
1310 sol.get(0).x, sol.get(0).y);
1311 newPolyline->setNextBulge(0.0);
1312 // start of new polyline:
1313 newPolyline->addVertex(sol.get(0));
1315 nextIsStraight = true;
1318 // start removing nodes again:
1319 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1320 DEBUG->print("Modification::polylineTrim: start removing at: %f/%f",
1321 ae->getEndpoint().x, ae->getEndpoint().y);
1322 newPolyline->setNextBulge(0.0);
1323 // start of new polyline:
1324 newPolyline->addVertex(sol.get(0));
1328 // normal node (not deleted):
1329 if (removing==false) {
1330 DEBUG->print("Modification::polylineTrim: normal vertex found: %f/%f",
1331 ae->getEndpoint().x, ae->getEndpoint().y);
1332 if (nextIsStraight) {
1333 newPolyline->setNextBulge(0.0);
1334 nextIsStraight = false;
1336 newPolyline->setNextBulge(bulge);
1338 newPolyline->addVertex(ae->getEndpoint());
1341 DEBUG->print("Modification::polylineTrim: "
1342 "Polyline contains non-atomic entities",
1348 DEBUG->print("Modification::polylineTrim: ending polyline");
1349 newPolyline->setNextBulge(polyline.getClosingBulge());
1350 newPolyline->endPolyline();
1352 // add new polyline:
1353 DEBUG->print("Modification::polylineTrim: adding new polyline");
1354 container->addEntity(newPolyline);
1355 if (graphicView!=NULL) {
1356 graphicView->deleteEntity(&polyline);
1357 graphicView->drawEntity(newPolyline);
1360 DEBUG->print("Modification::polylineTrim: handling undo");
1361 if (document!=NULL && handleUndo) {
1362 document->startUndoCycle();
1364 polyline.setUndoState(true);
1365 document->addUndoable(&polyline);
1366 document->addUndoable(newPolyline);
1368 document->endUndoCycle();
1376 * Moves all selected entities with the given data for the move
1379 bool Modification::move(MoveData & data)
1381 if (container == NULL)
1383 DEBUG->print("Modification::move: no valid container", Debug::D_WARNING);
1387 // Q3PtrList<Entity> addList;
1388 // addList.setAutoDelete(false);
1389 QList<Entity *> addList;
1391 if (document != NULL && handleUndo)
1392 document->startUndoCycle();
1394 // Create new entites
1395 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1398 //for (uint i=0; i<container->count(); ++i) {
1399 //Entity* e = container->entityAt(i);
1400 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1402 if (e != NULL && e->isSelected())
1404 Entity * ec = e->clone();
1405 ec->move(data.offset * num);
1407 if (data.useCurrentLayer)
1408 ec->setLayerToActive();
1410 if (data.useCurrentAttributes)
1411 ec->setPenToActive();
1413 if (ec->rtti() == RS2::EntityInsert)
1414 ((Insert *)ec)->update();
1416 // since 2.0.4.0: keep selection
1417 ec->setSelected(true);
1423 deselectOriginals(data.number==0);
1424 addNewEntities(addList);
1426 if (document != NULL && handleUndo)
1427 document->endUndoCycle();
1429 if (graphicView != NULL)
1430 graphicView->redraw();
1436 * Rotates all selected entities with the given data for the rotation.
1438 bool Modification::rotate(RotateData & data)
1440 if (container == NULL)
1442 DEBUG->print("Modification::rotate: no valid container",
1447 // Q3PtrList<Entity> addList;
1448 // addList.setAutoDelete(false);
1449 QList<Entity *> addList;
1451 if (document!=NULL && handleUndo)
1452 document->startUndoCycle();
1454 // Create new entites
1455 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1457 for (Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1459 //for (uint i=0; i<container->count(); ++i) {
1460 //Entity* e = container->entityAt(i);
1462 if (e != NULL && e->isSelected())
1464 Entity * ec = e->clone();
1465 ec->setSelected(false);
1466 ec->rotate(data.center, data.angle*num);
1468 if (data.useCurrentLayer)
1469 ec->setLayerToActive();
1471 if (data.useCurrentAttributes)
1472 ec->setPenToActive();
1474 if (ec->rtti() == RS2::EntityInsert)
1475 ((Insert *)ec)->update();
1482 deselectOriginals(data.number == 0);
1483 addNewEntities(addList);
1485 if (document != NULL && handleUndo)
1486 document->endUndoCycle();
1488 if (graphicView != NULL)
1489 graphicView->redraw();
1495 * Moves all selected entities with the given data for the scale
1498 bool Modification::scale(ScaleData & data)
1500 if (container == NULL)
1502 DEBUG->print("Modification::scale: no valid container", Debug::D_WARNING);
1506 // Q3PtrList<Entity> addList;
1507 // addList.setAutoDelete(false);
1508 QList<Entity *> addList;
1510 if (document!=NULL && handleUndo)
1511 document->startUndoCycle();
1513 // Create new entites
1514 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1516 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1518 //for (uint i=0; i<container->count(); ++i) {
1519 //Entity* e = container->entityAt(i);
1520 if (e != NULL && e->isSelected())
1522 Entity * ec = e->clone();
1523 ec->setSelected(false);
1524 ec->scale(data.referencePoint, Math::pow(data.factor, num));
1526 if (data.useCurrentLayer)
1527 ec->setLayerToActive();
1529 if (data.useCurrentAttributes)
1530 ec->setPenToActive();
1532 if (ec->rtti()==RS2::EntityInsert)
1533 ((Insert*)ec)->update();
1540 deselectOriginals(data.number == 0);
1541 addNewEntities(addList);
1543 if (document != NULL && handleUndo)
1544 document->endUndoCycle();
1546 if (graphicView != NULL)
1547 graphicView->redraw();
1553 * Mirror all selected entities with the given data for the mirror
1556 bool Modification::mirror(MirrorData & data)
1558 if (container==NULL) {
1559 DEBUG->print("Modification::mirror: no valid container",
1564 // Q3PtrList<Entity> addList;
1565 // addList.setAutoDelete(false);
1566 QList<Entity *> addList;
1568 if (document!=NULL && handleUndo) {
1569 document->startUndoCycle();
1572 // Create new entites
1574 num<=(int)data.copy || (data.copy==false && num<=1);
1576 for (Entity* e=container->firstEntity();
1578 e=container->nextEntity()) {
1579 //for (uint i=0; i<container->count(); ++i) {
1580 //Entity* e = container->entityAt(i);
1582 if (e!=NULL && e->isSelected()) {
1583 Entity* ec = e->clone();
1584 ec->setSelected(false);
1586 ec->mirror(data.axisPoint1, data.axisPoint2);
1587 if (data.useCurrentLayer) {
1588 ec->setLayerToActive();
1590 if (data.useCurrentAttributes) {
1591 ec->setPenToActive();
1593 if (ec->rtti()==RS2::EntityInsert) {
1594 ((Insert*)ec)->update();
1601 deselectOriginals(data.copy==false);
1602 addNewEntities(addList);
1604 if (document!=NULL && handleUndo) {
1605 document->endUndoCycle();
1608 if (graphicView!=NULL) {
1609 graphicView->redraw();
1615 * Rotates entities around two centers with the given parameters.
1617 bool Modification::rotate2(Rotate2Data & data)
1619 if (container==NULL) {
1620 DEBUG->print("Modification::rotate2: no valid container",
1625 // Q3PtrList<Entity> addList;
1626 // addList.setAutoDelete(false);
1627 QList<Entity *> addList;
1629 if (document!=NULL && handleUndo) {
1630 document->startUndoCycle();
1633 // Create new entites
1635 num<=data.number || (data.number==0 && num<=1);
1638 for (Entity* e=container->firstEntity();
1640 e=container->nextEntity()) {
1641 //for (uint i=0; i<container->count(); ++i) {
1642 //Entity* e = container->entityAt(i);
1644 if (e!=NULL && e->isSelected()) {
1645 Entity* ec = e->clone();
1646 ec->setSelected(false);
1648 ec->rotate(data.center1, data.angle1*num);
1649 Vector center2 = data.center2;
1650 center2.rotate(data.center1, data.angle1*num);
1652 ec->rotate(center2, data.angle2*num);
1653 if (data.useCurrentLayer) {
1654 ec->setLayerToActive();
1656 if (data.useCurrentAttributes) {
1657 ec->setPenToActive();
1659 if (ec->rtti()==RS2::EntityInsert) {
1660 ((Insert*)ec)->update();
1667 deselectOriginals(data.number==0);
1668 addNewEntities(addList);
1670 if (document!=NULL && handleUndo) {
1671 document->endUndoCycle();
1674 if (graphicView!=NULL) {
1675 graphicView->redraw();
1681 * Moves and rotates entities with the given parameters.
1683 bool Modification::moveRotate(MoveRotateData & data)
1685 if (container==NULL) {
1686 DEBUG->print("Modification::moveRotate: no valid container",
1691 // Q3PtrList<Entity> addList;
1692 // addList.setAutoDelete(false);
1693 QList<Entity *> addList;
1695 if (document!=NULL && handleUndo) {
1696 document->startUndoCycle();
1699 // Create new entites
1701 num<=data.number || (data.number==0 && num<=1);
1703 for (Entity* e=container->firstEntity();
1705 e=container->nextEntity()) {
1706 //for (uint i=0; i<container->count(); ++i) {
1707 //Entity* e = container->entityAt(i);
1709 if (e!=NULL && e->isSelected()) {
1710 Entity* ec = e->clone();
1711 ec->setSelected(false);
1713 ec->move(data.offset*num);
1714 ec->rotate(data.referencePoint + data.offset*num,
1716 if (data.useCurrentLayer) {
1717 ec->setLayerToActive();
1719 if (data.useCurrentAttributes) {
1720 ec->setPenToActive();
1722 if (ec->rtti()==RS2::EntityInsert) {
1723 ((Insert*)ec)->update();
1730 deselectOriginals(data.number==0);
1731 addNewEntities(addList);
1733 if (document!=NULL && handleUndo) {
1734 document->endUndoCycle();
1736 if (graphicView!=NULL) {
1737 graphicView->redraw();
1744 * Deselects all selected entities and removes them if remove is true;
1746 * @param remove true: Remove entites.
1748 void Modification::deselectOriginals(bool remove)
1750 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1752 //for (uint i=0; i<container->count(); ++i) {
1753 //Entity* e = container->entityAt(i);
1757 bool selected = false;
1759 if (e->isAtomic()) {
1760 AtomicEntity* ae = (AtomicEntity*)e;
1761 if (ae->isStartpointSelected() ||
1762 ae->isEndpointSelected()) {
1769 if (e->isSelected())
1774 e->setSelected(false);
1778 //if (graphicView!=NULL) {
1779 // graphicView->deleteEntity(e);
1781 e->changeUndoState();
1783 if (document != NULL && handleUndo)
1784 document->addUndoable(e);
1788 //if (graphicView!=NULL) {
1789 // graphicView->drawEntity(e);
1798 * Adds the given entities to the container and draws the entities if
1799 * there's a graphic view available.
1801 * @param addList Entities to add.
1803 //void Modification::addNewEntities(Q3PtrList<Entity> & addList)
1804 void Modification::addNewEntities(QList<Entity *> & addList)
1806 // for(Entity * e=addList.first(); e!=NULL; e=addList.next())
1807 for(int i=0; i<addList.size(); i++)
1809 Entity * e = addList[i];
1813 container->addEntity(e);
1815 if (document != NULL && handleUndo)
1816 document->addUndoable(e);
1817 //if (graphicView!=NULL) {
1818 // graphicView->drawEntity(e);
1825 * Trims or extends the given trimEntity to the intersection point of the
1826 * trimEntity and the limitEntity.
1828 * @param trimCoord Coordinate which defines which endpoint of the
1829 * trim entity to trim.
1830 * @param trimEntity Entity which will be trimmed.
1831 * @param limitCoord Coordinate which defines the intersection to which the
1832 * trim entity will be trimmed.
1833 * @param limitEntity Entity to which the trim entity will be trimmed.
1834 * @param both true: Trim both entities. false: trim trimEntity only.
1836 bool Modification::trim(const Vector& trimCoord, AtomicEntity* trimEntity,
1837 const Vector& limitCoord, Entity* limitEntity, bool both)
1839 if (trimEntity==NULL || limitEntity==NULL)
1841 DEBUG->print(Debug::D_WARNING,
1842 "Modification::trim: At least one entity is NULL");
1846 if (both && !limitEntity->isAtomic())
1848 DEBUG->print(Debug::D_WARNING,
1849 "Modification::trim: limitEntity is not atomic");
1852 VectorSolutions sol;
1854 if (limitEntity->isAtomic())
1856 // intersection(s) of the two entities:
1857 sol = Information::getIntersection(trimEntity, limitEntity, false);
1858 } else if (limitEntity->isContainer()) {
1859 EntityContainer* ec = (EntityContainer*)limitEntity;
1864 for (Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1865 e=ec->nextEntity(RS2::ResolveAll)) {
1866 //for (int i=0; i<container->count(); ++i) {
1867 // Entity* e = container->entityAt(i);
1871 VectorSolutions s2 = Information::getIntersection(trimEntity,
1874 if (s2.hasValid()) {
1875 for (int k=0; k<s2.getNumber(); ++k) {
1876 if (i<128 && s2.get(k).valid) {
1877 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1878 sol.set(i++, s2.get(k));
1888 if (!sol.hasValid())
1891 AtomicEntity * trimmed1 = NULL;
1892 AtomicEntity * trimmed2 = NULL;
1894 // remove trim entity from view:
1895 if (trimEntity->rtti() == RS2::EntityCircle)
1897 // convert a circle into a trimmable arc
1898 Circle * c = (Circle *)trimEntity;
1899 double am = c->getCenter().angleTo(trimCoord);
1900 ArcData d(c->getCenter(), c->getRadius(),
1901 Math::correctAngle(am - M_PI / 2),
1902 Math::correctAngle(am + M_PI / 2), false);
1903 trimmed1 = new Arc(trimEntity->getParent(), d);
1907 trimmed1 = (AtomicEntity *)trimEntity->clone();
1908 trimmed1->setHighlighted(false);
1911 #warning "!!! Old rendering path needs upgrading !!!"
1914 graphicView->deleteEntity(trimEntity);
1917 // remove limit entity from view:
1920 trimmed2 = (AtomicEntity *)limitEntity->clone();
1921 trimmed2->setHighlighted(false);
1923 #warning "!!! Old rendering path needs upgrading !!!"
1926 graphicView->deleteEntity(limitEntity);
1932 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1933 //sol.getClosest(limitCoord, NULL, &ind);
1934 DEBUG->print("Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1935 DEBUG->print("Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1936 DEBUG->print("Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1937 DEBUG->print("Modification::trim: ind: %d", ind);
1938 Vector is2 = sol.get(ind==0 ? 1 : 0);
1939 //Vector is2 = sol.get(ind);
1940 DEBUG->print("Modification::trim: is2: %f/%f", is2.x, is2.y);
1942 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1943 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1946 case RS2::EndingStart:
1947 trimmed1->trimStartpoint(is);
1948 if (trimEntity->rtti()==RS2::EntityCircle) {
1949 trimmed1->trimEndpoint(is2);
1952 case RS2::EndingEnd:
1953 trimmed1->trimEndpoint(is);
1954 if (trimEntity->rtti()==RS2::EntityCircle) {
1955 trimmed1->trimStartpoint(is2);
1962 // trim limit entity:
1964 Vector is = sol.getClosest(limitCoord);
1966 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1969 case RS2::EndingStart:
1970 trimmed2->trimStartpoint(is);
1972 case RS2::EndingEnd:
1973 trimmed2->trimEndpoint(is);
1980 // add new trimmed trim entity:
1981 container->addEntity(trimmed1);
1982 if (graphicView!=NULL) {
1983 graphicView->drawEntity(trimmed1);
1986 // add new trimmed limit entity:
1988 container->addEntity(trimmed2);
1989 if (graphicView!=NULL) {
1990 graphicView->drawEntity(trimmed2);
1994 if (document!=NULL && handleUndo) {
1995 document->startUndoCycle();
1996 document->addUndoable(trimmed1);
1997 trimEntity->setUndoState(true);
1998 document->addUndoable(trimEntity);
2000 document->addUndoable(trimmed2);
2001 limitEntity->setUndoState(true);
2002 document->addUndoable(limitEntity);
2004 document->endUndoCycle();
2013 * Trims or extends the given trimEntity by the given amount.
2015 * @param trimCoord Coordinate which defines which endpoint of the
2016 * trim entity to trim.
2017 * @param trimEntity Entity which will be trimmed.
2018 * @param dist Amount to trim by.
2020 bool Modification::trimAmount(const Vector & trimCoord,
2021 AtomicEntity * trimEntity, double dist)
2025 DEBUG->print(Debug::D_WARNING, "Modification::trimAmount: Entity is NULL");
2029 AtomicEntity * trimmed = NULL;
2031 // remove trim entity:
2032 trimmed = (AtomicEntity*)trimEntity->clone();
2034 #warning "!!! Old rendering path needs upgrading !!!"
2037 graphicView->deleteEntity(trimEntity);
2041 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2042 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2043 trimCoord.distanceTo(trimmed->getEndpoint()))
2045 trimmed->trimStartpoint(is);
2049 trimmed->trimEndpoint(is);
2052 // add new trimmed trim entity:
2053 container->addEntity(trimmed);
2055 #warning "!!! Old rendering path needs upgrading !!!"
2058 graphicView->drawEntity(trimmed);
2061 if (document && handleUndo)
2063 document->startUndoCycle();
2064 document->addUndoable(trimmed);
2065 trimEntity->setUndoState(true);
2066 document->addUndoable(trimEntity);
2067 document->endUndoCycle();
2076 * Cuts the given entity at the given point.
2078 bool Modification::cut(const Vector& cutCoord,
2079 AtomicEntity* cutEntity) {
2081 if (cutEntity==NULL) {
2082 DEBUG->print(Debug::D_WARNING,
2083 "Modification::cut: Entity is NULL");
2087 if (!cutCoord.valid) {
2088 DEBUG->print(Debug::D_WARNING,
2089 "Modification::cut: Point invalid.");
2093 // cut point is at endpoint of entity:
2094 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2095 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2096 DEBUG->print(Debug::D_WARNING,
2097 "Modification::cut: Cutting point on endpoint");
2101 #warning "!!! Old rendering path needs upgrading !!!"
2103 // delete cut entity on the screen:
2105 graphicView->deleteEntity(cutEntity);
2108 AtomicEntity * cut1 = NULL;
2109 AtomicEntity * cut2 = NULL;
2111 // create new two halves:
2112 if (cutEntity->rtti() == RS2::EntityCircle)
2114 Circle * c = (Circle *)cutEntity;
2115 cut1 = new Arc(cutEntity->getParent(),
2116 ArcData(c->getCenter(),
2119 cut1->setPen(cutEntity->getPen());
2120 cut1->setLayer(cutEntity->getLayer());
2123 cut1->trimEndpoint(cutCoord);
2124 cut1->trimStartpoint(cutCoord);
2128 cut1 = (AtomicEntity*)cutEntity->clone();
2129 cut2 = (AtomicEntity*)cutEntity->clone();
2131 cut1->trimEndpoint(cutCoord);
2132 cut2->trimStartpoint(cutCoord);
2135 // add new cut entity:
2136 container->addEntity(cut1);
2138 container->addEntity(cut2);
2141 if (graphicView!=NULL) {
2142 graphicView->drawEntity(cut1);
2144 graphicView->drawEntity(cut2);
2148 if (document!=NULL && handleUndo) {
2149 document->startUndoCycle();
2150 document->addUndoable(cut1);
2152 document->addUndoable(cut2);
2154 cutEntity->setUndoState(true);
2155 document->addUndoable(cutEntity);
2156 document->endUndoCycle();
2165 bool Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2166 const Vector& offset)
2170 DEBUG->print(Debug::D_WARNING,
2171 "Modification::stretch: Offset invalid");
2175 // Q3PtrList<Entity> addList;
2176 // addList.setAutoDelete(false);
2177 QList<Entity *> addList;
2179 if (document!=NULL && handleUndo) {
2180 document->startUndoCycle();
2183 // Create new entites
2184 for (Entity* e=container->firstEntity();
2186 e=container->nextEntity()) {
2187 //for (int i=0; i<container->count(); ++i) {
2188 // Entity* e = container->entityAt(i);
2193 (e->isInWindow(firstCorner, secondCorner) ||
2194 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2196 Entity* ec = e->clone();
2197 ec->stretch(firstCorner, secondCorner, offset);
2199 e->setSelected(true);
2203 deselectOriginals(true);
2204 addNewEntities(addList);
2206 if (document!=NULL && handleUndo) {
2207 document->endUndoCycle();
2210 if (graphicView!=NULL) {
2211 graphicView->redraw();
2221 * @param coord1 Mouse coordinate to specify direction from intersection.
2222 * @param entity1 First entity of the corner.
2223 * @param coord2 Mouse coordinate to specify direction from intersection.
2224 * @param entity2 Second entity of the corner.
2225 * @param data Lengths and trim flag.
2227 bool Modification::bevel(const Vector& coord1, AtomicEntity* entity1,
2228 const Vector& coord2, AtomicEntity* entity2,
2231 DEBUG->print("Modification::bevel");
2233 if (entity1==NULL || entity2==NULL) {
2234 DEBUG->print(Debug::D_WARNING,
2235 "Modification::bevel: At least one entity is NULL");
2239 EntityContainer* baseContainer = container;
2240 bool isPolyline = false;
2241 bool isClosedPolyline = false;
2243 if (document!=NULL && handleUndo) {
2244 document->startUndoCycle();
2247 // find out whether we're bevelling within a polyline:
2248 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2249 DEBUG->print("Modification::bevel: trimming polyline segments");
2250 if (entity1->getParent()!=entity2->getParent()) {
2251 DEBUG->print(Debug::D_WARNING,
2252 "Modification::bevel: entities not in the same polyline");
2255 // clone polyline for undo
2256 if (document!=NULL && handleUndo) {
2257 EntityContainer* cl =
2258 (EntityContainer*)entity1->getParent()->clone();
2259 container->addEntity(cl);
2260 //cl->setUndoState(true);
2261 document->addUndoable(cl);
2263 document->addUndoable(entity1->getParent());
2264 entity1->getParent()->setUndoState(true);
2269 entity1 = (AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2270 entity2 = (AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2272 //baseContainer = entity1->getParent();
2274 isClosedPolyline = ((Polyline*)entity1)->isClosed();
2277 DEBUG->print("Modification::bevel: getting intersection");
2279 VectorSolutions sol =
2280 Information::getIntersection(entity1, entity2, false);
2282 if (sol.getNumber()==0) {
2286 AtomicEntity* trimmed1 = NULL;
2287 AtomicEntity* trimmed2 = NULL;
2289 //if (data.trim || isPolyline) {
2294 trimmed1 = (AtomicEntity*)entity1->clone();
2295 trimmed2 = (AtomicEntity*)entity2->clone();
2298 #warning "!!! Old rendering path needs upgrading !!!"
2300 // remove trim entity (on screen):
2301 if (data.trim || isPolyline)
2307 graphicView->deleteEntity(baseContainer);
2311 graphicView->deleteEntity(entity1);
2312 graphicView->deleteEntity(entity2);
2318 // trim entities to intersection
2319 DEBUG->print("Modification::bevel: trim entities to intersection 01");
2320 bool start1 = false;
2321 Vector is = sol.getClosest(coord2);
2322 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2324 case RS2::EndingStart:
2325 trimmed1->trimStartpoint(is);
2328 case RS2::EndingEnd:
2329 trimmed1->trimEndpoint(is);
2336 DEBUG->print("Modification::bevel: trim entities to intersection 02");
2337 bool start2 = false;
2338 is = sol.getClosest(coord1);
2339 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2341 case RS2::EndingStart:
2342 trimmed2->trimStartpoint(is);
2345 case RS2::EndingEnd:
2346 trimmed2->trimEndpoint(is);
2355 // find definitive bevel points
2356 DEBUG->print("Modification::bevel: find definitive bevel points");
2357 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2358 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2361 DEBUG->print("Modification::bevel: final trim");
2362 if (data.trim==true) {
2364 case RS2::EndingStart:
2365 trimmed1->trimStartpoint(bp1);
2367 case RS2::EndingEnd:
2368 trimmed1->trimEndpoint(bp1);
2375 case RS2::EndingStart:
2376 trimmed2->trimStartpoint(bp2);
2378 case RS2::EndingEnd:
2379 trimmed2->trimEndpoint(bp2);
2385 // add new trimmed entities:
2386 if (isPolyline==false) {
2387 container->addEntity(trimmed1);
2388 container->addEntity(trimmed2);
2390 if (graphicView!=NULL) {
2392 graphicView->drawEntity(trimmed1);
2393 graphicView->drawEntity(trimmed2);
2400 DEBUG->print("Modification::bevel: add bevel line");
2401 Line* bevel = new Line(baseContainer, LineData(bp1, bp2));
2403 if (isPolyline==false) {
2404 baseContainer->addEntity(bevel);
2406 int idx1 = baseContainer->findEntity(trimmed1);
2407 int idx2 = baseContainer->findEntity(trimmed2);
2409 bevel->setSelected(baseContainer->isSelected());
2410 bevel->setLayer(baseContainer->getLayer());
2411 bevel->setPen(baseContainer->getPen());
2413 bool insertAfter1 = false;
2414 if (!isClosedPolyline) {
2415 insertAfter1 = (idx1<idx2);
2418 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2419 (idx2==0 && idx1==(int)baseContainer->count()-1));
2422 // insert bevel at the right position:
2423 //if ((idx1<idx2 && idx1!=0) ||
2424 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2426 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2429 baseContainer->insertEntity(idx1+1, bevel);
2431 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2434 baseContainer->insertEntity(idx2+1, bevel);
2439 ((Polyline*)baseContainer)->updateEndpoints();
2442 if (graphicView!=NULL) {
2444 graphicView->drawEntity(baseContainer);
2446 graphicView->drawEntity(bevel);
2450 DEBUG->print("Modification::bevel: handling undo");
2452 if (document!=NULL && handleUndo) {
2453 //document->startUndoCycle();
2455 if (isPolyline==false && data.trim==true) {
2456 document->addUndoable(trimmed1);
2457 entity1->setUndoState(true);
2458 document->addUndoable(entity1);
2460 document->addUndoable(trimmed2);
2461 entity2->setUndoState(true);
2462 document->addUndoable(entity2);
2465 if (isPolyline==false) {
2466 document->addUndoable(bevel);
2469 document->endUndoCycle();
2472 if (data.trim==false) {
2473 DEBUG->print("Modification::bevel: delete trimmed elements");
2476 DEBUG->print("Modification::bevel: delete trimmed elements: ok");
2488 * @param coord Mouse coordinate to specify the rounding.
2489 * @param entity1 First entity of the corner.
2490 * @param entity2 Second entity of the corner.
2491 * @param data Radius and trim flag.
2493 bool Modification::round(const Vector& coord,
2494 const Vector& coord1,
2495 AtomicEntity* entity1,
2496 const Vector& coord2,
2497 AtomicEntity* entity2,
2500 if (entity1==NULL || entity2==NULL) {
2501 DEBUG->print(Debug::D_WARNING,
2502 "Modification::round: At least one entity is NULL");
2506 EntityContainer* baseContainer = container;
2507 bool isPolyline = false;
2508 bool isClosedPolyline = false;
2510 if (document!=NULL && handleUndo) {
2511 document->startUndoCycle();
2514 // find out whether we're rounding within a polyline:
2515 if (entity1->getParent()!=NULL &&
2516 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2518 if (entity1->getParent()!=entity2->getParent()) {
2519 DEBUG->print(Debug::D_WARNING,
2520 "Modification::round: entities not in "
2521 "the same polyline");
2522 if (document!=NULL && handleUndo) {
2523 document->endUndoCycle();
2528 // clone polyline for undo
2529 if (document!=NULL && handleUndo) {
2530 EntityContainer* cl =
2531 (EntityContainer*)entity1->getParent()->clone();
2532 container->addEntity(cl);
2533 document->addUndoable(cl);
2535 document->addUndoable(entity1->getParent());
2536 entity1->getParent()->setUndoState(true);
2541 entity1 = (AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2542 entity2 = (AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2545 isClosedPolyline = ((Polyline*)entity1)->isClosed();
2548 // create 2 tmp parallels
2549 Creation creation(NULL, NULL);
2550 Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2551 Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2553 VectorSolutions sol2 =
2554 Information::getIntersection(entity1, entity2, false);
2556 VectorSolutions sol =
2557 Information::getIntersection(par1, par2, false);
2559 if (sol.getNumber()==0) {
2560 if (document!=NULL && handleUndo) {
2561 document->endUndoCycle();
2566 // there might be two intersections: choose the closest:
2567 Vector is = sol.getClosest(coord);
2568 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2569 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2570 double ang1 = is.angleTo(p1);
2571 double ang2 = is.angleTo(p2);
2572 bool reversed = (Math::getAngleDifference(ang1, ang2)>M_PI);
2574 Arc* arc = new Arc(baseContainer,
2581 AtomicEntity* trimmed1 = NULL;
2582 AtomicEntity* trimmed2 = NULL;
2584 if (data.trim || isPolyline) {
2589 trimmed1 = (AtomicEntity*)entity1->clone();
2590 trimmed2 = (AtomicEntity*)entity2->clone();
2593 #warning "!!! Old rendering path needs upgrading !!!"
2595 // remove trim entity:
2596 if (graphicView!=NULL)
2600 graphicView->deleteEntity(baseContainer);
2604 graphicView->deleteEntity(entity1);
2605 graphicView->deleteEntity(entity2);
2610 // trim entities to intersection
2611 Vector is2 = sol2.getClosest(coord2);
2612 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2614 case RS2::EndingStart:
2615 trimmed1->trimStartpoint(p1);
2617 case RS2::EndingEnd:
2618 trimmed1->trimEndpoint(p1);
2624 is2 = sol2.getClosest(coord1);
2625 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2627 case RS2::EndingStart:
2628 trimmed2->trimStartpoint(p2);
2630 case RS2::EndingEnd:
2631 trimmed2->trimEndpoint(p2);
2637 // add new trimmed entities:
2638 if (isPolyline==false) {
2639 container->addEntity(trimmed1);
2640 container->addEntity(trimmed2);
2642 if (graphicView!=NULL) {
2644 graphicView->drawEntity(trimmed1);
2645 graphicView->drawEntity(trimmed2);
2651 if (isPolyline==false) {
2652 baseContainer->addEntity(arc);
2654 // find out which base entity is before the rounding:
2655 int idx1 = baseContainer->findEntity(trimmed1);
2656 int idx2 = baseContainer->findEntity(trimmed2);
2658 arc->setSelected(baseContainer->isSelected());
2659 arc->setLayer(baseContainer->getLayer());
2660 arc->setPen(baseContainer->getPen());
2662 DEBUG->print("Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2663 DEBUG->print("Modification::round: idx1!=0: %d", (int)(idx1!=0));
2664 DEBUG->print("Modification::round: idx2==0: %d", (int)(idx2==0));
2665 DEBUG->print("Modification::round: idx1==(int)baseContainer->count()-1: %d",
2666 (int)(idx1==(int)baseContainer->count()-1));
2668 bool insertAfter1 = false;
2669 if (!isClosedPolyline) {
2670 insertAfter1 = (idx1<idx2);
2673 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2674 (idx2==0 && idx1==(int)baseContainer->count()-1));
2677 // insert rounding at the right position:
2678 //if ((idx1<idx2 && idx1!=0) ||
2679 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2682 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2685 baseContainer->insertEntity(idx1+1, arc);
2687 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2690 baseContainer->insertEntity(idx2+1, arc);
2695 ((Polyline*)baseContainer)->updateEndpoints();
2698 if (graphicView!=NULL) {
2700 graphicView->drawEntity(baseContainer);
2702 graphicView->drawEntity(arc);
2706 if (document!=NULL && handleUndo) {
2707 if (isPolyline==false && data.trim==true) {
2708 document->addUndoable(trimmed1);
2709 entity1->setUndoState(true);
2710 document->addUndoable(entity1);
2712 document->addUndoable(trimmed2);
2713 entity2->setUndoState(true);
2714 document->addUndoable(entity2);
2717 if (isPolyline==false) {
2718 document->addUndoable(arc);
2721 document->endUndoCycle();
2731 * Removes the selected entity containers and adds the entities in them as
2732 * new single entities.
2734 bool Modification::explode()
2736 if (container == NULL)
2738 DEBUG->print("Modification::explode: no valid container for addinge entities",
2743 // Q3PtrList<Entity> addList;
2744 // addList.setAutoDelete(false);
2745 QList<Entity *> addList;
2747 if (document!=NULL && handleUndo) {
2748 document->startUndoCycle();
2751 for (Entity* e=container->firstEntity();
2753 e=container->nextEntity()) {
2754 //for (uint i=0; i<container->count(); ++i) {
2755 //Entity* e = container->entityAt(i);
2757 if (e!=NULL && e->isSelected()) {
2758 if (e->isContainer()) {
2760 // add entities from container:
2761 EntityContainer* ec = (EntityContainer*)e;
2762 //ec->setSelected(false);
2764 // iterate and explode container:
2765 //for (uint i2=0; i2<ec->count(); ++i2) {
2766 // Entity* e2 = ec->entityAt(i2);
2767 RS2::ResolveLevel rl;
2771 switch (ec->rtti()) {
2772 case RS2::EntityText:
2773 case RS2::EntityHatch:
2774 case RS2::EntityPolyline:
2775 rl = RS2::ResolveAll;
2776 resolveLayer = true;
2780 case RS2::EntityInsert:
2782 resolveLayer = false;
2783 rl = RS2::ResolveNone;
2786 case RS2::EntityDimAligned:
2787 case RS2::EntityDimLinear:
2788 case RS2::EntityDimRadial:
2789 case RS2::EntityDimDiametric:
2790 case RS2::EntityDimAngular:
2791 case RS2::EntityDimLeader:
2792 rl = RS2::ResolveNone;
2793 resolveLayer = true;
2798 rl = RS2::ResolveAll;
2799 resolveLayer = true;
2804 for (Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2805 e2 = ec->nextEntity(rl)) {
2808 Entity* clone = e2->clone();
2809 clone->setSelected(false);
2810 clone->reparent(container);
2813 clone->setLayer(ec->getLayer());
2815 clone->setLayer(e2->getLayer());
2818 clone->setPen(ec->getPen(resolvePen));
2820 addList.append(clone);
2826 e->setSelected(false);
2831 deselectOriginals(true);
2832 addNewEntities(addList);
2834 if (document!=NULL && handleUndo) {
2835 document->endUndoCycle();
2838 if (graphicView!=NULL) {
2839 graphicView->redraw();
2845 bool Modification::explodeTextIntoLetters()
2847 if (container == NULL)
2849 DEBUG->print("Modification::explodeTextIntoLetters: no valid container"
2850 " for addinge entities", Debug::D_WARNING);
2854 // Q3PtrList<Entity> addList;
2855 // addList.setAutoDelete(false);
2856 QList<Entity *> addList;
2858 if (document!=NULL && handleUndo) {
2859 document->startUndoCycle();
2862 for (Entity* e=container->firstEntity();
2864 e=container->nextEntity()) {
2865 if (e!=NULL && e->isSelected()) {
2866 if (e->rtti()==RS2::EntityText) {
2867 // add letters of text:
2868 Text* text = (Text*)e;
2869 explodeTextIntoLetters(text, addList);
2871 e->setSelected(false);
2876 deselectOriginals(true);
2877 addNewEntities(addList);
2879 if (document!=NULL && handleUndo) {
2880 document->endUndoCycle();
2883 if (graphicView!=NULL) {
2884 graphicView->redraw();
2890 //bool Modification::explodeTextIntoLetters(Text* text, Q3PtrList<Entity>& addList)
2891 bool Modification::explodeTextIntoLetters(Text * text, QList<Entity *> & addList)
2896 // iterate though lines:
2897 for(Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2903 if (e2->rtti() == RS2::EntityContainer)
2905 EntityContainer * line = (EntityContainer *)e2;
2907 // iterate though letters:
2908 for(Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2913 // super / sub texts:
2914 if (e3->rtti() == RS2::EntityText)
2915 explodeTextIntoLetters((Text *)e3, addList);
2917 else if (e3->rtti() == RS2::EntityInsert)
2919 Insert * letter = (Insert *)e3;
2921 Text * tl = new Text(container, TextData(letter->getInsertionPoint(),
2922 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2923 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2924 letter->getAngle(), RS2::Update));
2926 tl->setLayer(text->getLayer());
2927 tl->setPen(text->getPen());
2940 * Moves all reference points of selected entities with the given data.
2942 bool Modification::moveRef(MoveRefData& data)
2944 if (container == NULL)
2946 DEBUG->print("Modification::moveRef: no valid container", Debug::D_WARNING);
2950 // Q3PtrList<Entity> addList;
2951 // addList.setAutoDelete(false);
2952 QList<Entity *> addList;
2954 if (document != NULL && handleUndo)
2955 document->startUndoCycle();
2957 // Create new entites
2958 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2960 if (e != NULL && e->isSelected())
2962 Entity * ec = e->clone();
2963 ec->moveRef(data.ref, data.offset);
2964 // since 2.0.4.0: keep it selected
2965 ec->setSelected(true);
2970 deselectOriginals(true);
2971 addNewEntities(addList);
2973 if (document != NULL && handleUndo)
2974 document->endUndoCycle();
2976 if (graphicView != NULL)
2977 graphicView->redraw();