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 #warning "!!! Need to rename graphic to drawing !!!"
46 graphic = container.GetDrawing();
47 document = container.getDocument();
51 * Deletes all selected entities.
53 void Modification::remove()
55 if (container == NULL)
57 DEBUG->print("Modification::remove: no valid container", Debug::D_WARNING);
62 document->startUndoCycle();
65 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
67 if (e && e->isSelected())
69 e->setSelected(false);
73 document->addUndoable(e);
78 document->endUndoCycle();
80 graphicView->redraw();
84 * Changes the attributes of all selected
86 bool Modification::changeAttributes(AttributesData & data)
90 DEBUG->print("Modification::changeAttributes: no valid container", Debug::D_WARNING);
94 QList<Entity *> addList;
97 document->startUndoCycle();
99 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
101 //for (uint i=0; i<container->count(); ++i) {
102 //Entity* e = container->entityAt(i);
103 if (e && e->isSelected())
105 Entity * ec = e->clone();
106 ec->setSelected(false);
108 Pen pen = ec->getPen(false);
110 if (data.changeLayer == true)
111 ec->setLayer(data.layer);
113 if (data.changeColor == true)
114 pen.setColor(data.pen.getColor());
116 if (data.changeLineType == true)
117 pen.setLineType(data.pen.getLineType());
119 if (data.changeWidth == true)
120 pen.setWidth(data.pen.getWidth());
124 //if (data.useCurrentLayer) {
125 // ec->setLayerToActive();
127 //if (data.useCurrentAttributes) {
128 // ec->setPenToActive();
130 //if (ec->rtti()==RS2::EntityInsert) {
131 // ((Insert*)ec)->update();
138 deselectOriginals(true);
139 addNewEntities(addList);
142 document->endUndoCycle();
145 graphicView->redraw();
152 * Copies all selected entities from the given container to the clipboard.
153 * Layers and blocks that are needed are also copied if the container is
154 * or is part of an Drawing.
156 * @param container The entity container.
157 * @param ref Reference point. The entities will be moved by -ref.
158 * @param cut true: cut instead of copying, false: copy
160 void Modification::copy(const Vector& ref, const bool cut) {
162 if (container==NULL) {
163 DEBUG->print("Modification::copy: no valid container",
170 CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
172 CLIPBOARD->getGraphic()->setUnit(RS2::None);
175 // start undo cycle for the container if we're cutting
176 if (cut && document!=NULL) {
177 document->startUndoCycle();
180 // copy entities / layers / blocks
181 for (Entity* e=container->firstEntity(); e!=NULL;
182 e=container->nextEntity()) {
183 //for (uint i=0; i<container->count(); ++i) {
184 //Entity* e = container->entityAt(i);
186 if (e!=NULL && e->isSelected()) {
187 copyEntity(e, ref, cut);
191 if (cut && document!=NULL) {
192 document->endUndoCycle();
199 * Copies the given entity from the given container to the clipboard.
200 * Layers and blocks that are needed are also copied if the container is
201 * or is part of an Drawing.
203 * @param e The entity.
204 * @param ref Reference point. The entities will be moved by -ref.
205 * @param cut true: cut instead of copying, false: copy
207 void Modification::copyEntity(Entity * e, const Vector & ref, const bool cut)
209 if (e && e->isSelected())
211 // delete entity in graphic view:
214 #warning "!!! Old rendering path needs upgrading !!!"
217 graphicView->deleteEntity(e);
220 e->setSelected(false);
224 #warning "!!! Old rendering path needs upgrading !!!"
227 graphicView->deleteEntity(e);
230 e->setSelected(false);
232 #warning "!!! Old rendering path needs upgrading !!!"
235 graphicView->drawEntity(e);
239 // add entity to clipboard:
240 Entity * c = e->clone();
242 CLIPBOARD->addEntity(c);
247 // set layer to the layer clone:
248 Layer * l = e->getLayer();
251 c->setLayer(l->getName());
253 // make sure all sub entities point to layers of the clipboard
254 if (c->isContainer())
256 EntityContainer * ec = (EntityContainer *)c;
258 for(Entity * e2=ec->firstEntity(RS2::ResolveAll); e2!=NULL;
259 e2=ec->nextEntity(RS2::ResolveAll))
261 //Entity* e2 = ec->entityAt(i);
262 Layer * l2 = e2->getLayer();
265 e2->setLayer(l2->getName());
271 e->changeUndoState();
274 document->addUndoable(e);
282 * Copies all layers of the given entity to the clipboard.
284 void Modification::copyLayers(Entity* e) {
290 // add layer(s) of the entity if it's not an insert
291 // (inserts are on layer '0'):
292 if (e->rtti()!=RS2::EntityInsert) {
293 Layer* l = e->getLayer();
295 if (!CLIPBOARD->hasLayer(l->getName())) {
296 CLIPBOARD->addLayer(l->clone());
301 // special handling of inserts:
303 // insert: add layer(s) of subentities:
304 Block* b = ((Insert*)e)->getBlockForInsert();
306 for (Entity* e2=b->firstEntity(); e2!=NULL;
307 e2=b->nextEntity()) {
308 //for (uint i=0; i<b->count(); ++i) {
309 //Entity* e2 = b->entityAt(i);
319 * Copies all blocks of the given entity to the clipboard.
321 void Modification::copyBlocks(Entity* e) {
327 // add block of the entity if it's an insert
328 if (e->rtti()==RS2::EntityInsert) {
329 Block* b = ((Insert*)e)->getBlockForInsert();
331 // add block of an insert:
332 if (!CLIPBOARD->hasBlock(b->getName())) {
333 CLIPBOARD->addBlock((Block*)b->clone());
336 for (Entity* e2=b->firstEntity(); e2!=NULL;
337 e2=b->nextEntity()) {
338 //for (uint i=0; i<b->count(); ++i) {
339 //Entity* e2 = b->entityAt(i);
349 * Pastes all entities from the clipboard into the container.
350 * Layers and blocks that are needed are also copied if the container is
351 * or is part of an Drawing.
353 * @param data Paste data.
354 * @param source The source from where to paste. NULL means the source
357 void Modification::paste(const PasteData& data, Drawing* source) {
360 DEBUG->print(Debug::D_WARNING,
361 "Modification::paste: Graphic is NULL");
368 source = CLIPBOARD->getGraphic();
370 // graphics from the clipboard need to be scaled. from the part lib not:
371 RS2::Unit sourceUnit = source->getUnit();
372 RS2::Unit targetUnit = graphic->getUnit();
373 factor = Units::convert(1.0, sourceUnit, targetUnit);
376 if (document!=NULL) {
377 document->startUndoCycle();
383 Layer* layer = graphic->getActiveLayer();
384 for(uint i=0; i<source->countLayers(); ++i) {
385 Layer* l = source->layerAt(i);
387 if (graphic->findLayer(l->getName())==NULL) {
388 graphic->addLayer(l->clone());
392 graphic->activateLayer(layer);
397 for(uint i=0; i<source->countBlocks(); ++i) {
398 Block* b = source->blockAt(i);
400 if (graphic->findBlock(b->getName())==NULL) {
401 Block* bc = (Block*)b->clone();
402 bc->reparent(container);
403 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
404 // scale block but don't scale inserts in block
405 // (they already scale with their block)
406 for(uint i2=0; i2<bc->count(); ++i2) {
407 Entity* e = bc->entityAt(i2);
408 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
409 e->scale(bc->getBasePoint(),
410 Vector(factor, factor));
412 Vector ip = ((Insert*)e)->getInsertionPoint();
413 ip.scale(bc->getBasePoint(),
414 Vector(factor, factor));
415 ((Insert*)e)->setInsertionPoint(ip);
420 graphic->addBlock(bc);
426 // add entities to this host (graphic or a new block)
427 EntityContainer* host = container;
432 if (data.asInsert==true) {
433 BlockList* blkList = graphic->getBlockList();
435 blockName = blkList->newName(data.blockName);
440 Vector(0.0,0.0), false));
441 graphic->addBlock(blk);
449 //for (uint i=0; i<((EntityContainer*)source)->count(); ++i) {
450 //Entity* e = source->entityAt(i);
451 for (Entity* e=((EntityContainer*)source)->firstEntity();
453 e=((EntityContainer*)source)->nextEntity()) {
457 QString layerName = "0";
458 Layer* layer = e->getLayer();
460 layerName = layer->getName();
462 Entity* e2 = e->clone();
464 if (data.asInsert==false) {
465 e2->move(data.insertionPoint);
467 // don't adjust insert factor - block was already adjusted to unit
468 if (e2->rtti()==RS2::EntityInsert) {
469 Vector ip = ((Insert*)e2)->getInsertionPoint();
470 ip.scale(data.insertionPoint, Vector(factor, factor));
471 ((Insert*)e2)->setInsertionPoint(ip);
474 e2->scale(data.insertionPoint, Vector(factor, factor));
477 e2->setLayer(layerName);
479 // make sure all sub entities point to layers of the container
480 if (e2->isContainer()) {
481 EntityContainer* ec = (EntityContainer*)e2;
483 for (Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
484 e3 = ec->nextEntity(RS2::ResolveAll)) {
486 //Entity* e3 = ec->entityAt(i);
487 Layer* l2 = e3->getLayer();
489 e3->setLayer(l2->getName());
494 if (document!=NULL && data.asInsert==false) {
495 document->addUndoable(e2);
500 if (data.asInsert==true) {
502 new Insert(container,
506 Vector(data.factor, data.factor),
508 1,1,Vector(0.0,0.0)));
509 container->addEntity(ins);
510 ins->setLayerToActive();
511 ins->setPenToActive();
513 if (document!=NULL) {
514 document->addUndoable(ins);
518 if (document!=NULL) {
519 document->endUndoCycle();
525 * Splits a polyline into two leaving out a gap.
527 * @param polyline The original polyline
528 * @param e1 1st entity on which the first cutting point is.
529 * @param v1 1st cutting point.
530 * @param e2 2nd entity on which the first cutting point is.
531 * @param v2 2nd cutting point.
532 * @param polyline1 Pointer to a polyline pointer which will hold the
533 * 1st resulting new polyline. Pass NULL if you don't
534 * need those pointers.
535 * @param polyline2 Pointer to a polyline pointer which will hold the
536 * 2nd resulting new polyline. Pass NULL if you don't
537 * need those pointers.
539 * @todo Support arcs in polylines, check for wrong parameters
543 bool Modification::splitPolyline(Polyline& polyline,
544 Entity& e1, Vector v1,
545 Entity& e2, Vector v2,
546 Polyline** polyline1,
547 Polyline** polyline2) const {
549 if (container==NULL) {
550 DEBUG->print("Modification::splitPolyline: no valid container",
555 Entity* firstEntity = polyline.firstEntity();
556 Vector firstPoint(false);
557 if (firstEntity->rtti()==RS2::EntityLine) {
558 firstPoint = ((Line*)firstEntity)->getStartpoint();
561 new Polyline(container,
562 PolylineData(firstPoint, Vector(0.0,0.0), 0));
563 Polyline* pl2 = new Polyline(container);
564 Polyline* pl = pl1; // Current polyline
568 if (polyline1!=NULL) {
571 if (polyline2!=NULL) {
575 for (Entity* e = polyline.firstEntity();
577 e = polyline.nextEntity()) {
579 if (e->rtti()==RS2::EntityLine) {
582 } else if (e->rtti()==RS2::EntityArc) {
590 if (line!=NULL /*|| arc!=NULL*/) {
592 if (e==&e1 && e==&e2) {
593 // Trim within a single entity:
594 Vector sp = line->getStartpoint();
595 double dist1 = (v1-sp).magnitude();
596 double dist2 = (v2-sp).magnitude();
597 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
599 pl->setStartpoint(dist1<dist2 ? v2 : v1);
600 pl->addVertex(line->getEndpoint(), 0.0);
601 } else if (e==&e1 || e==&e2) {
603 Vector v = (e==&e1 ? v1 : v2);
605 // Trim endpoint of entity to first vector
606 pl->addVertex(v, 0.0);
609 // Trim startpoint of entity to second vector
611 pl->setStartpoint(v);
612 pl->addVertex(line->getEndpoint(), 0.0);
615 // Add entities to polylines
616 if (line!=NULL && pl!=NULL) {
617 pl->addVertex(line->getEndpoint(), 0.0);
623 container->addEntity(pl1);
624 container->addEntity(pl2);
625 //container->removeEntity(&polyline);
626 polyline.changeUndoState();
634 * Adds a node to the given polyline. The new node is placed between
635 * the start and end point of the given segment.
637 * @param node The position of the new node.
639 * @return Pointer to the new polyline or NULL.
642 Polyline* Modification::addPolylineNode(Polyline& polyline,
643 const AtomicEntity& segment,
644 const Vector& node) {
645 DEBUG->print("Modification::addPolylineNode");
647 if (container==NULL) {
648 DEBUG->print("Modification::addPolylineNode: no valid container",
653 if (segment.getParent()!=&polyline) {
654 DEBUG->print("Modification::addPolylineNode: "
655 "segment not part of the polyline",
660 Polyline* newPolyline = new Polyline(container);
661 newPolyline->setClosed(polyline.isClosed());
662 newPolyline->setSelected(polyline.isSelected());
663 newPolyline->setLayer(polyline.getLayer());
664 newPolyline->setPen(polyline.getPen());
666 // copy polyline and add new node:
668 Entity* lastEntity = polyline.lastEntity();
669 for (Entity* e=polyline.firstEntity(); e!=NULL;
670 e=polyline.nextEntity()) {
673 AtomicEntity* ae = (AtomicEntity*)e;
675 if (ae->rtti()==RS2::EntityArc) {
676 DEBUG->print("Modification::addPolylineNode: arc segment");
677 bulge = ((Arc*)ae)->getBulge();
679 DEBUG->print("Modification::addPolylineNode: line segment");
684 DEBUG->print("Modification::addPolylineNode: first segment: %f/%f",
685 ae->getStartpoint().x, ae->getStartpoint().y);
687 newPolyline->setNextBulge(bulge);
688 newPolyline->addVertex(ae->getStartpoint());
694 DEBUG->print("Modification::addPolylineNode: split segment found");
696 DEBUG->print("Modification::addPolylineNode: node: %f/%f",
699 newPolyline->setNextBulge(0.0);
700 newPolyline->addVertex(node);
702 DEBUG->print("Modification::addPolylineNode: after node: %f/%f",
703 ae->getEndpoint().x, ae->getEndpoint().y);
705 if (ae!=lastEntity || polyline.isClosed()==false) {
706 newPolyline->setNextBulge(0.0);
707 newPolyline->addVertex(ae->getEndpoint());
710 DEBUG->print("Modification::addPolylineNode: normal vertex found: %f/%f",
711 ae->getEndpoint().x, ae->getEndpoint().y);
713 if (ae!=lastEntity || polyline.isClosed()==false) {
714 newPolyline->setNextBulge(bulge);
715 newPolyline->addVertex(ae->getEndpoint());
719 DEBUG->print("Modification::addPolylineNode: "
720 "Polyline contains non-atomic entities",
725 newPolyline->setNextBulge(polyline.getClosingBulge());
726 newPolyline->endPolyline();
729 container->addEntity(newPolyline);
730 if (graphicView!=NULL) {
731 graphicView->deleteEntity(&polyline);
732 graphicView->drawEntity(newPolyline);
735 if (document!=NULL && handleUndo) {
736 document->startUndoCycle();
738 polyline.setUndoState(true);
739 document->addUndoable(&polyline);
740 document->addUndoable(newPolyline);
742 document->endUndoCycle();
752 * Deletes a node from a polyline.
754 * @param node The node to delete.
756 * @return Pointer to the new polyline or NULL.
759 Polyline* Modification::deletePolylineNode(Polyline& polyline,
760 const Vector& node) {
762 DEBUG->print("Modification::deletePolylineNode");
764 if (container==NULL) {
765 DEBUG->print("Modification::addPolylineNode: no valid container",
770 if (node.valid==false) {
771 DEBUG->print("Modification::deletePolylineNode: "
777 // check if the polyline is no longer there after deleting the node:
778 if (polyline.count()==1) {
779 Entity* e = polyline.firstEntity();
780 if (e!=NULL && e->isAtomic()) {
781 AtomicEntity* ae = (AtomicEntity*)e;
782 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
783 node.distanceTo(ae->getEndpoint())<1.0e-6) {
785 if (graphicView!=NULL) {
786 graphicView->deleteEntity(&polyline);
789 if (document!=NULL && handleUndo) {
790 document->startUndoCycle();
791 polyline.setUndoState(true);
792 document->addUndoable(&polyline);
793 document->endUndoCycle();
800 Polyline* newPolyline = new Polyline(container);
801 newPolyline->setClosed(polyline.isClosed());
802 newPolyline->setSelected(polyline.isSelected());
803 newPolyline->setLayer(polyline.getLayer());
804 newPolyline->setPen(polyline.getPen());
806 // copy polyline and drop deleted node:
808 bool lastDropped = false;
809 Entity* lastEntity = polyline.lastEntity();
810 for (Entity* e=polyline.firstEntity(); e!=NULL;
811 e=polyline.nextEntity()) {
814 AtomicEntity* ae = (AtomicEntity*)e;
816 if (ae->rtti()==RS2::EntityArc) {
817 DEBUG->print("Modification::deletePolylineNode: arc segment");
818 bulge = ((Arc*)ae)->getBulge();
820 DEBUG->print("Modification::deletePolylineNode: line segment");
824 // last entity is closing entity and will be added below with endPolyline()
825 if (e==lastEntity && polyline.isClosed()) {
829 // first vertex (startpoint)
830 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
831 DEBUG->print("Modification::deletePolylineNode: first node: %f/%f",
832 ae->getStartpoint().x, ae->getStartpoint().y);
834 newPolyline->setNextBulge(bulge);
835 newPolyline->addVertex(ae->getStartpoint());
839 // normal node (not deleted):
840 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
841 DEBUG->print("Modification::deletePolylineNode: normal vertex found: %f/%f",
842 ae->getEndpoint().x, ae->getEndpoint().y);
846 newPolyline->setNextBulge(bulge);
847 newPolyline->addVertex(ae->getEndpoint());
851 // drop deleted node:
853 DEBUG->print("Modification::deletePolylineNode: deleting vertex: %f/%f",
854 ae->getEndpoint().x, ae->getEndpoint().y);
858 DEBUG->print("Modification::deletePolylineNode: "
859 "Polyline contains non-atomic entities",
864 DEBUG->print("Modification::deletePolylineNode: ending polyline");
865 newPolyline->setNextBulge(polyline.getClosingBulge());
866 newPolyline->endPolyline();
868 //if (newPolyline->count()==1) {
872 DEBUG->print("Modification::deletePolylineNode: adding new polyline");
873 container->addEntity(newPolyline);
874 if (graphicView!=NULL) {
875 graphicView->deleteEntity(&polyline);
876 graphicView->drawEntity(newPolyline);
879 DEBUG->print("Modification::deletePolylineNode: handling undo");
880 if (document!=NULL && handleUndo) {
881 document->startUndoCycle();
883 polyline.setUndoState(true);
884 document->addUndoable(&polyline);
885 document->addUndoable(newPolyline);
887 document->endUndoCycle();
897 * Deletes all nodes between the two given nodes (exclusive).
899 * @param node1 First limiting node.
900 * @param node2 Second limiting node.
902 * @return Pointer to the new polyline or NULL.
905 Polyline* Modification::deletePolylineNodesBetween(Polyline& polyline,
906 AtomicEntity& segment, const Vector& node1, const Vector& node2) {
908 DEBUG->print("Modification::deletePolylineNodesBetween");
910 if (container==NULL) {
911 DEBUG->print("Modification::addPolylineNodesBetween: no valid container",
916 if (node1.valid==false || node2.valid==false) {
917 DEBUG->print("Modification::deletePolylineNodesBetween: "
923 if (node1.distanceTo(node2)<1.0e-6) {
924 DEBUG->print("Modification::deletePolylineNodesBetween: "
925 "nodes are identical",
930 // check if there's nothing to delete:
931 for (Entity* e=polyline.firstEntity(); e!=NULL;
932 e=polyline.nextEntity()) {
935 AtomicEntity* ae = (AtomicEntity*)e;
937 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
938 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
939 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
940 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
942 DEBUG->print("Modification::deletePolylineNodesBetween: "
951 // check if the start point is involved:
952 bool startpointInvolved = false;
953 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
954 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
955 startpointInvolved = true;
959 // check which part of the polyline has to be deleted:
960 bool deleteStart = false;
961 if (polyline.isClosed()) {
963 double length1 = 0.0;
964 double length2 = 0.0;
965 Entity* e=polyline.firstEntity();
967 if (startpointInvolved) {
969 AtomicEntity* ae = (AtomicEntity*)e;
970 length1+=ae->getLength();
972 e = polyline.nextEntity();
974 for (; e!=NULL; e=polyline.nextEntity()) {
977 AtomicEntity* ae = (AtomicEntity*)e;
979 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
980 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
986 length2+=ae->getLength();
988 length1+=ae->getLength();
992 if (length1<length2) {
999 Polyline* newPolyline = new Polyline(container);
1000 newPolyline->setClosed(polyline.isClosed());
1001 newPolyline->setSelected(polyline.isSelected());
1002 newPolyline->setLayer(polyline.getLayer());
1003 newPolyline->setPen(polyline.getPen());
1005 if (startpointInvolved && deleteStart && polyline.isClosed()) {
1006 newPolyline->setNextBulge(0.0);
1007 newPolyline->addVertex(polyline.getStartpoint());
1010 // copy polyline and drop deleted nodes:
1012 bool removing = deleteStart;
1014 bool nextIsStraight = false;
1015 Entity* lastEntity = polyline.lastEntity();
1018 for (Entity* e=polyline.firstEntity(); e!=NULL;
1019 e=polyline.nextEntity()) {
1021 DEBUG->print("Modification::deletePolylineNodesBetween: entity: %d", i++);
1022 DEBUG->print("Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1024 if (e->isAtomic()) {
1025 AtomicEntity* ae = (AtomicEntity*)e;
1026 if (ae->rtti()==RS2::EntityArc) {
1027 DEBUG->print("Modification::deletePolylineNodesBetween: arc segment");
1028 bulge = ((Arc*)ae)->getBulge();
1030 DEBUG->print("Modification::deletePolylineNodesBetween: line segment");
1034 // last entity is closing entity and will be added below with endPolyline()
1035 if (e==lastEntity && polyline.isClosed()) {
1036 DEBUG->print("Modification::deletePolylineNodesBetween: "
1037 "dropping last vertex of closed polyline");
1041 // first vertex (startpoint)
1044 DEBUG->print("Modification::deletePolylineNodesBetween: first node: %f/%f",
1045 ae->getStartpoint().x, ae->getStartpoint().y);
1046 newPolyline->setNextBulge(bulge);
1047 newPolyline->addVertex(ae->getStartpoint());
1052 // stop removing nodes:
1053 if (removing==true &&
1054 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1055 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1056 DEBUG->print("Modification::deletePolylineNodesBetween: "
1057 "stop removing at: %f/%f",
1058 ae->getEndpoint().x, ae->getEndpoint().y);
1062 nextIsStraight = true;
1066 // normal node (not deleted):
1067 if (removing==false && (done==false || deleteStart==false)) {
1068 DEBUG->print("Modification::deletePolylineNodesBetween: "
1069 "normal vertex found: %f/%f",
1070 ae->getEndpoint().x, ae->getEndpoint().y);
1071 if (nextIsStraight) {
1073 nextIsStraight = false;
1075 newPolyline->setNextBulge(bulge);
1076 newPolyline->addVertex(ae->getEndpoint());
1079 // drop deleted node:
1081 DEBUG->print("Modification::deletePolylineNodesBetween: "
1082 "deleting vertex: %f/%f",
1083 ae->getEndpoint().x, ae->getEndpoint().y);
1086 // start to remove nodes from now on:
1087 if (done==false && removing==false &&
1088 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1089 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1090 DEBUG->print("Modification::deletePolylineNodesBetween: "
1091 "start removing at: %f/%f",
1092 ae->getEndpoint().x, ae->getEndpoint().y);
1100 DEBUG->print("Modification::deletePolylineNodesBetween: "
1101 "Polyline contains non-atomic entities",
1106 DEBUG->print("Modification::deletePolylineNodesBetween: ending polyline");
1107 newPolyline->setNextBulge(polyline.getClosingBulge());
1108 newPolyline->endPolyline();
1110 // add new polyline:
1111 DEBUG->print("Modification::deletePolylineNodesBetween: adding new polyline");
1112 container->addEntity(newPolyline);
1113 if (graphicView!=NULL) {
1114 graphicView->deleteEntity(&polyline);
1115 graphicView->drawEntity(newPolyline);
1118 DEBUG->print("Modification::deletePolylineNodesBetween: handling undo");
1119 if (document!=NULL && handleUndo) {
1120 document->startUndoCycle();
1122 polyline.setUndoState(true);
1123 document->addUndoable(&polyline);
1124 document->addUndoable(newPolyline);
1126 document->endUndoCycle();
1136 * Trims two segments of a polyline all nodes between the two trim segments
1139 * @param polyline The polyline entity.
1140 * @param segment1 First segment to trim.
1141 * @param segment2 Second segment to trim.
1143 * @return Pointer to the new polyline or NULL.
1146 Polyline* Modification::polylineTrim(Polyline& polyline,
1147 AtomicEntity& segment1,
1148 AtomicEntity& segment2) {
1150 DEBUG->print("Modification::polylineTrim");
1152 if (container==NULL) {
1153 DEBUG->print("Modification::addPolylineNodesBetween: no valid container",
1158 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1159 DEBUG->print("Modification::polylineTrim: "
1160 "segments not in polyline",
1165 if (&segment1==&segment2) {
1166 DEBUG->print("Modification::polylineTrim: "
1167 "segments are identical",
1172 VectorSolutions sol;
1173 sol = Information::getIntersection(&segment1, &segment2, false);
1175 if (sol.getNumber()==0) {
1176 DEBUG->print("Modification::polylineTrim: "
1177 "segments cannot be trimmed",
1182 // check which segment comes first in the polyline:
1183 AtomicEntity* firstSegment;
1184 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1185 firstSegment = &segment2;
1187 firstSegment = &segment1;
1190 // find out if we need to trim towards the open part of the polyline
1192 reverseTrim = !Math::isSameDirection(firstSegment->getDirection1(),
1193 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1194 //reverseTrim = reverseTrim || !Math::isSameDirection(segment2.getDirection1(),
1195 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1197 Polyline* newPolyline = new Polyline(container);
1198 newPolyline->setClosed(polyline.isClosed());
1199 newPolyline->setSelected(polyline.isSelected());
1200 newPolyline->setLayer(polyline.getLayer());
1201 newPolyline->setPen(polyline.getPen());
1203 // normal trimming: start removing nodes at trim segment. ends stay the same
1204 if (reverseTrim==false) {
1205 // copy polyline, trim segments and drop between nodes:
1207 bool removing = false;
1208 bool nextIsStraight = false;
1209 Entity* lastEntity = polyline.lastEntity();
1210 for (Entity* e=polyline.firstEntity(); e!=NULL;
1211 e=polyline.nextEntity()) {
1213 if (e->isAtomic()) {
1214 AtomicEntity* ae = (AtomicEntity*)e;
1216 if (ae->rtti()==RS2::EntityArc) {
1217 DEBUG->print("Modification::polylineTrim: arc segment");
1218 bulge = ((Arc*)ae)->getBulge();
1220 DEBUG->print("Modification::polylineTrim: line segment");
1224 // last entity is closing entity and will be added below with endPolyline()
1225 if (e==lastEntity && polyline.isClosed()) {
1226 DEBUG->print("Modification::polylineTrim: "
1227 "dropping last vertex of closed polyline");
1231 // first vertex (startpoint)
1233 DEBUG->print("Modification::polylineTrim: first node: %f/%f",
1234 ae->getStartpoint().x, ae->getStartpoint().y);
1236 newPolyline->setNextBulge(bulge);
1237 newPolyline->addVertex(ae->getStartpoint());
1241 // trim and start removing nodes:
1242 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1243 DEBUG->print("Modification::polylineTrim: "
1244 "start removing at trim point %f/%f",
1245 sol.get(0).x, sol.get(0).y);
1246 newPolyline->setNextBulge(0.0);
1247 newPolyline->addVertex(sol.get(0));
1249 nextIsStraight = true;
1252 // stop removing nodes:
1253 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1254 DEBUG->print("Modification::polylineTrim: stop removing at: %f/%f",
1255 ae->getEndpoint().x, ae->getEndpoint().y);
1259 // normal node (not deleted):
1260 if (removing==false) {
1261 DEBUG->print("Modification::polylineTrim: normal vertex found: %f/%f",
1262 ae->getEndpoint().x, ae->getEndpoint().y);
1263 if (nextIsStraight) {
1264 newPolyline->setNextBulge(0.0);
1265 nextIsStraight = false;
1267 newPolyline->setNextBulge(bulge);
1269 newPolyline->addVertex(ae->getEndpoint());
1272 DEBUG->print("Modification::polylineTrim: "
1273 "Polyline contains non-atomic entities",
1279 // reverse trimming: remove nodes at the ends and keep those in between
1281 // copy polyline, trim segments and drop between nodes:
1282 //bool first = true;
1283 bool removing = true;
1284 bool nextIsStraight = false;
1285 Entity* lastEntity = polyline.lastEntity();
1286 for (Entity* e=polyline.firstEntity(); e!=NULL;
1287 e=polyline.nextEntity()) {
1289 if (e->isAtomic()) {
1290 AtomicEntity* ae = (AtomicEntity*)e;
1292 if (ae->rtti()==RS2::EntityArc) {
1293 DEBUG->print("Modification::polylineTrim: arc segment");
1294 bulge = ((Arc*)ae)->getBulge();
1296 DEBUG->print("Modification::polylineTrim: line segment");
1300 // last entity is closing entity and will be added below with endPolyline()
1301 if (e==lastEntity && polyline.isClosed()) {
1302 DEBUG->print("Modification::polylineTrim: "
1303 "dropping last vertex of closed polyline");
1307 // trim and stop removing nodes:
1308 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1309 DEBUG->print("Modification::polylineTrim: "
1310 "stop removing at trim point %f/%f",
1311 sol.get(0).x, sol.get(0).y);
1312 newPolyline->setNextBulge(0.0);
1313 // start of new polyline:
1314 newPolyline->addVertex(sol.get(0));
1316 nextIsStraight = true;
1319 // start removing nodes again:
1320 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1321 DEBUG->print("Modification::polylineTrim: start removing at: %f/%f",
1322 ae->getEndpoint().x, ae->getEndpoint().y);
1323 newPolyline->setNextBulge(0.0);
1324 // start of new polyline:
1325 newPolyline->addVertex(sol.get(0));
1329 // normal node (not deleted):
1330 if (removing==false) {
1331 DEBUG->print("Modification::polylineTrim: normal vertex found: %f/%f",
1332 ae->getEndpoint().x, ae->getEndpoint().y);
1333 if (nextIsStraight) {
1334 newPolyline->setNextBulge(0.0);
1335 nextIsStraight = false;
1337 newPolyline->setNextBulge(bulge);
1339 newPolyline->addVertex(ae->getEndpoint());
1342 DEBUG->print("Modification::polylineTrim: "
1343 "Polyline contains non-atomic entities",
1349 DEBUG->print("Modification::polylineTrim: ending polyline");
1350 newPolyline->setNextBulge(polyline.getClosingBulge());
1351 newPolyline->endPolyline();
1353 // add new polyline:
1354 DEBUG->print("Modification::polylineTrim: adding new polyline");
1355 container->addEntity(newPolyline);
1356 if (graphicView!=NULL) {
1357 graphicView->deleteEntity(&polyline);
1358 graphicView->drawEntity(newPolyline);
1361 DEBUG->print("Modification::polylineTrim: handling undo");
1362 if (document!=NULL && handleUndo) {
1363 document->startUndoCycle();
1365 polyline.setUndoState(true);
1366 document->addUndoable(&polyline);
1367 document->addUndoable(newPolyline);
1369 document->endUndoCycle();
1377 * Moves all selected entities with the given data for the move
1380 bool Modification::move(MoveData & data)
1382 if (container == NULL)
1384 DEBUG->print("Modification::move: no valid container", Debug::D_WARNING);
1388 // Q3PtrList<Entity> addList;
1389 // addList.setAutoDelete(false);
1390 QList<Entity *> addList;
1392 if (document != NULL && handleUndo)
1393 document->startUndoCycle();
1395 // Create new entites
1396 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1399 //for (uint i=0; i<container->count(); ++i) {
1400 //Entity* e = container->entityAt(i);
1401 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1403 if (e != NULL && e->isSelected())
1405 Entity * ec = e->clone();
1406 ec->move(data.offset * num);
1408 if (data.useCurrentLayer)
1409 ec->setLayerToActive();
1411 if (data.useCurrentAttributes)
1412 ec->setPenToActive();
1414 if (ec->rtti() == RS2::EntityInsert)
1415 ((Insert *)ec)->update();
1417 // since 2.0.4.0: keep selection
1418 ec->setSelected(true);
1424 deselectOriginals(data.number==0);
1425 addNewEntities(addList);
1427 if (document != NULL && handleUndo)
1428 document->endUndoCycle();
1430 if (graphicView != NULL)
1431 graphicView->redraw();
1437 * Rotates all selected entities with the given data for the rotation.
1439 bool Modification::rotate(RotateData & data)
1441 if (container == NULL)
1443 DEBUG->print("Modification::rotate: no valid container",
1448 // Q3PtrList<Entity> addList;
1449 // addList.setAutoDelete(false);
1450 QList<Entity *> addList;
1452 if (document!=NULL && handleUndo)
1453 document->startUndoCycle();
1455 // Create new entites
1456 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1458 for (Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1460 //for (uint i=0; i<container->count(); ++i) {
1461 //Entity* e = container->entityAt(i);
1463 if (e != NULL && e->isSelected())
1465 Entity * ec = e->clone();
1466 ec->setSelected(false);
1467 ec->rotate(data.center, data.angle*num);
1469 if (data.useCurrentLayer)
1470 ec->setLayerToActive();
1472 if (data.useCurrentAttributes)
1473 ec->setPenToActive();
1475 if (ec->rtti() == RS2::EntityInsert)
1476 ((Insert *)ec)->update();
1483 deselectOriginals(data.number == 0);
1484 addNewEntities(addList);
1486 if (document != NULL && handleUndo)
1487 document->endUndoCycle();
1489 if (graphicView != NULL)
1490 graphicView->redraw();
1496 * Moves all selected entities with the given data for the scale
1499 bool Modification::scale(ScaleData & data)
1501 if (container == NULL)
1503 DEBUG->print("Modification::scale: no valid container", Debug::D_WARNING);
1507 // Q3PtrList<Entity> addList;
1508 // addList.setAutoDelete(false);
1509 QList<Entity *> addList;
1511 if (document!=NULL && handleUndo)
1512 document->startUndoCycle();
1514 // Create new entites
1515 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1517 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1519 //for (uint i=0; i<container->count(); ++i) {
1520 //Entity* e = container->entityAt(i);
1521 if (e != NULL && e->isSelected())
1523 Entity * ec = e->clone();
1524 ec->setSelected(false);
1525 ec->scale(data.referencePoint, Math::pow(data.factor, num));
1527 if (data.useCurrentLayer)
1528 ec->setLayerToActive();
1530 if (data.useCurrentAttributes)
1531 ec->setPenToActive();
1533 if (ec->rtti()==RS2::EntityInsert)
1534 ((Insert*)ec)->update();
1541 deselectOriginals(data.number == 0);
1542 addNewEntities(addList);
1544 if (document != NULL && handleUndo)
1545 document->endUndoCycle();
1547 if (graphicView != NULL)
1548 graphicView->redraw();
1554 * Mirror all selected entities with the given data for the mirror
1557 bool Modification::mirror(MirrorData & data)
1559 if (container==NULL) {
1560 DEBUG->print("Modification::mirror: no valid container",
1565 // Q3PtrList<Entity> addList;
1566 // addList.setAutoDelete(false);
1567 QList<Entity *> addList;
1569 if (document!=NULL && handleUndo) {
1570 document->startUndoCycle();
1573 // Create new entites
1575 num<=(int)data.copy || (data.copy==false && num<=1);
1577 for (Entity* e=container->firstEntity();
1579 e=container->nextEntity()) {
1580 //for (uint i=0; i<container->count(); ++i) {
1581 //Entity* e = container->entityAt(i);
1583 if (e!=NULL && e->isSelected()) {
1584 Entity* ec = e->clone();
1585 ec->setSelected(false);
1587 ec->mirror(data.axisPoint1, data.axisPoint2);
1588 if (data.useCurrentLayer) {
1589 ec->setLayerToActive();
1591 if (data.useCurrentAttributes) {
1592 ec->setPenToActive();
1594 if (ec->rtti()==RS2::EntityInsert) {
1595 ((Insert*)ec)->update();
1602 deselectOriginals(data.copy==false);
1603 addNewEntities(addList);
1605 if (document!=NULL && handleUndo) {
1606 document->endUndoCycle();
1609 if (graphicView!=NULL) {
1610 graphicView->redraw();
1616 * Rotates entities around two centers with the given parameters.
1618 bool Modification::rotate2(Rotate2Data & data)
1620 if (container==NULL) {
1621 DEBUG->print("Modification::rotate2: no valid container",
1626 // Q3PtrList<Entity> addList;
1627 // addList.setAutoDelete(false);
1628 QList<Entity *> addList;
1630 if (document!=NULL && handleUndo) {
1631 document->startUndoCycle();
1634 // Create new entites
1636 num<=data.number || (data.number==0 && num<=1);
1639 for (Entity* e=container->firstEntity();
1641 e=container->nextEntity()) {
1642 //for (uint i=0; i<container->count(); ++i) {
1643 //Entity* e = container->entityAt(i);
1645 if (e!=NULL && e->isSelected()) {
1646 Entity* ec = e->clone();
1647 ec->setSelected(false);
1649 ec->rotate(data.center1, data.angle1*num);
1650 Vector center2 = data.center2;
1651 center2.rotate(data.center1, data.angle1*num);
1653 ec->rotate(center2, data.angle2*num);
1654 if (data.useCurrentLayer) {
1655 ec->setLayerToActive();
1657 if (data.useCurrentAttributes) {
1658 ec->setPenToActive();
1660 if (ec->rtti()==RS2::EntityInsert) {
1661 ((Insert*)ec)->update();
1668 deselectOriginals(data.number==0);
1669 addNewEntities(addList);
1671 if (document!=NULL && handleUndo) {
1672 document->endUndoCycle();
1675 if (graphicView!=NULL) {
1676 graphicView->redraw();
1682 * Moves and rotates entities with the given parameters.
1684 bool Modification::moveRotate(MoveRotateData & data)
1686 if (container==NULL) {
1687 DEBUG->print("Modification::moveRotate: no valid container",
1692 // Q3PtrList<Entity> addList;
1693 // addList.setAutoDelete(false);
1694 QList<Entity *> addList;
1696 if (document!=NULL && handleUndo) {
1697 document->startUndoCycle();
1700 // Create new entites
1702 num<=data.number || (data.number==0 && num<=1);
1704 for (Entity* e=container->firstEntity();
1706 e=container->nextEntity()) {
1707 //for (uint i=0; i<container->count(); ++i) {
1708 //Entity* e = container->entityAt(i);
1710 if (e!=NULL && e->isSelected()) {
1711 Entity* ec = e->clone();
1712 ec->setSelected(false);
1714 ec->move(data.offset*num);
1715 ec->rotate(data.referencePoint + data.offset*num,
1717 if (data.useCurrentLayer) {
1718 ec->setLayerToActive();
1720 if (data.useCurrentAttributes) {
1721 ec->setPenToActive();
1723 if (ec->rtti()==RS2::EntityInsert) {
1724 ((Insert*)ec)->update();
1731 deselectOriginals(data.number==0);
1732 addNewEntities(addList);
1734 if (document!=NULL && handleUndo) {
1735 document->endUndoCycle();
1737 if (graphicView!=NULL) {
1738 graphicView->redraw();
1745 * Deselects all selected entities and removes them if remove is true;
1747 * @param remove true: Remove entites.
1749 void Modification::deselectOriginals(bool remove)
1751 for(Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1753 //for (uint i=0; i<container->count(); ++i) {
1754 //Entity* e = container->entityAt(i);
1758 bool selected = false;
1760 if (e->isAtomic()) {
1761 AtomicEntity* ae = (AtomicEntity*)e;
1762 if (ae->isStartpointSelected() ||
1763 ae->isEndpointSelected()) {
1770 if (e->isSelected())
1775 e->setSelected(false);
1779 //if (graphicView!=NULL) {
1780 // graphicView->deleteEntity(e);
1782 e->changeUndoState();
1784 if (document != NULL && handleUndo)
1785 document->addUndoable(e);
1789 //if (graphicView!=NULL) {
1790 // graphicView->drawEntity(e);
1799 * Adds the given entities to the container and draws the entities if
1800 * there's a graphic view available.
1802 * @param addList Entities to add.
1804 //void Modification::addNewEntities(Q3PtrList<Entity> & addList)
1805 void Modification::addNewEntities(QList<Entity *> & addList)
1807 // for(Entity * e=addList.first(); e!=NULL; e=addList.next())
1808 for(int i=0; i<addList.size(); i++)
1810 Entity * e = addList[i];
1814 container->addEntity(e);
1816 if (document != NULL && handleUndo)
1817 document->addUndoable(e);
1818 //if (graphicView!=NULL) {
1819 // graphicView->drawEntity(e);
1826 * Trims or extends the given trimEntity to the intersection point of the
1827 * trimEntity and the limitEntity.
1829 * @param trimCoord Coordinate which defines which endpoint of the
1830 * trim entity to trim.
1831 * @param trimEntity Entity which will be trimmed.
1832 * @param limitCoord Coordinate which defines the intersection to which the
1833 * trim entity will be trimmed.
1834 * @param limitEntity Entity to which the trim entity will be trimmed.
1835 * @param both true: Trim both entities. false: trim trimEntity only.
1837 bool Modification::trim(const Vector& trimCoord, AtomicEntity* trimEntity,
1838 const Vector& limitCoord, Entity* limitEntity, bool both)
1840 if (trimEntity==NULL || limitEntity==NULL)
1842 DEBUG->print(Debug::D_WARNING,
1843 "Modification::trim: At least one entity is NULL");
1847 if (both && !limitEntity->isAtomic())
1849 DEBUG->print(Debug::D_WARNING,
1850 "Modification::trim: limitEntity is not atomic");
1853 VectorSolutions sol;
1855 if (limitEntity->isAtomic())
1857 // intersection(s) of the two entities:
1858 sol = Information::getIntersection(trimEntity, limitEntity, false);
1859 } else if (limitEntity->isContainer()) {
1860 EntityContainer* ec = (EntityContainer*)limitEntity;
1865 for (Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1866 e=ec->nextEntity(RS2::ResolveAll)) {
1867 //for (int i=0; i<container->count(); ++i) {
1868 // Entity* e = container->entityAt(i);
1872 VectorSolutions s2 = Information::getIntersection(trimEntity,
1875 if (s2.hasValid()) {
1876 for (int k=0; k<s2.getNumber(); ++k) {
1877 if (i<128 && s2.get(k).valid) {
1878 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1879 sol.set(i++, s2.get(k));
1889 if (!sol.hasValid())
1892 AtomicEntity * trimmed1 = NULL;
1893 AtomicEntity * trimmed2 = NULL;
1895 // remove trim entity from view:
1896 if (trimEntity->rtti() == RS2::EntityCircle)
1898 // convert a circle into a trimmable arc
1899 Circle * c = (Circle *)trimEntity;
1900 double am = c->getCenter().angleTo(trimCoord);
1901 ArcData d(c->getCenter(), c->getRadius(),
1902 Math::correctAngle(am - M_PI / 2),
1903 Math::correctAngle(am + M_PI / 2), false);
1904 trimmed1 = new Arc(trimEntity->getParent(), d);
1908 trimmed1 = (AtomicEntity *)trimEntity->clone();
1909 trimmed1->setHighlighted(false);
1912 #warning "!!! Old rendering path needs upgrading !!!"
1915 graphicView->deleteEntity(trimEntity);
1918 // remove limit entity from view:
1921 trimmed2 = (AtomicEntity *)limitEntity->clone();
1922 trimmed2->setHighlighted(false);
1924 #warning "!!! Old rendering path needs upgrading !!!"
1927 graphicView->deleteEntity(limitEntity);
1933 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1934 //sol.getClosest(limitCoord, NULL, &ind);
1935 DEBUG->print("Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1936 DEBUG->print("Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1937 DEBUG->print("Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1938 DEBUG->print("Modification::trim: ind: %d", ind);
1939 Vector is2 = sol.get(ind==0 ? 1 : 0);
1940 //Vector is2 = sol.get(ind);
1941 DEBUG->print("Modification::trim: is2: %f/%f", is2.x, is2.y);
1943 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1944 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1947 case RS2::EndingStart:
1948 trimmed1->trimStartpoint(is);
1949 if (trimEntity->rtti()==RS2::EntityCircle) {
1950 trimmed1->trimEndpoint(is2);
1953 case RS2::EndingEnd:
1954 trimmed1->trimEndpoint(is);
1955 if (trimEntity->rtti()==RS2::EntityCircle) {
1956 trimmed1->trimStartpoint(is2);
1963 // trim limit entity:
1965 Vector is = sol.getClosest(limitCoord);
1967 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1970 case RS2::EndingStart:
1971 trimmed2->trimStartpoint(is);
1973 case RS2::EndingEnd:
1974 trimmed2->trimEndpoint(is);
1981 // add new trimmed trim entity:
1982 container->addEntity(trimmed1);
1983 if (graphicView!=NULL) {
1984 graphicView->drawEntity(trimmed1);
1987 // add new trimmed limit entity:
1989 container->addEntity(trimmed2);
1990 if (graphicView!=NULL) {
1991 graphicView->drawEntity(trimmed2);
1995 if (document!=NULL && handleUndo) {
1996 document->startUndoCycle();
1997 document->addUndoable(trimmed1);
1998 trimEntity->setUndoState(true);
1999 document->addUndoable(trimEntity);
2001 document->addUndoable(trimmed2);
2002 limitEntity->setUndoState(true);
2003 document->addUndoable(limitEntity);
2005 document->endUndoCycle();
2014 * Trims or extends the given trimEntity by the given amount.
2016 * @param trimCoord Coordinate which defines which endpoint of the
2017 * trim entity to trim.
2018 * @param trimEntity Entity which will be trimmed.
2019 * @param dist Amount to trim by.
2021 bool Modification::trimAmount(const Vector & trimCoord,
2022 AtomicEntity * trimEntity, double dist)
2026 DEBUG->print(Debug::D_WARNING, "Modification::trimAmount: Entity is NULL");
2030 AtomicEntity * trimmed = NULL;
2032 // remove trim entity:
2033 trimmed = (AtomicEntity*)trimEntity->clone();
2035 #warning "!!! Old rendering path needs upgrading !!!"
2038 graphicView->deleteEntity(trimEntity);
2042 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2043 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2044 trimCoord.distanceTo(trimmed->getEndpoint()))
2046 trimmed->trimStartpoint(is);
2050 trimmed->trimEndpoint(is);
2053 // add new trimmed trim entity:
2054 container->addEntity(trimmed);
2056 #warning "!!! Old rendering path needs upgrading !!!"
2059 graphicView->drawEntity(trimmed);
2062 if (document && handleUndo)
2064 document->startUndoCycle();
2065 document->addUndoable(trimmed);
2066 trimEntity->setUndoState(true);
2067 document->addUndoable(trimEntity);
2068 document->endUndoCycle();
2077 * Cuts the given entity at the given point.
2079 bool Modification::cut(const Vector& cutCoord,
2080 AtomicEntity* cutEntity) {
2082 if (cutEntity==NULL) {
2083 DEBUG->print(Debug::D_WARNING,
2084 "Modification::cut: Entity is NULL");
2088 if (!cutCoord.valid) {
2089 DEBUG->print(Debug::D_WARNING,
2090 "Modification::cut: Point invalid.");
2094 // cut point is at endpoint of entity:
2095 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2096 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2097 DEBUG->print(Debug::D_WARNING,
2098 "Modification::cut: Cutting point on endpoint");
2102 #warning "!!! Old rendering path needs upgrading !!!"
2104 // delete cut entity on the screen:
2106 graphicView->deleteEntity(cutEntity);
2109 AtomicEntity * cut1 = NULL;
2110 AtomicEntity * cut2 = NULL;
2112 // create new two halves:
2113 if (cutEntity->rtti() == RS2::EntityCircle)
2115 Circle * c = (Circle *)cutEntity;
2116 cut1 = new Arc(cutEntity->getParent(),
2117 ArcData(c->getCenter(),
2120 cut1->setPen(cutEntity->getPen());
2121 cut1->setLayer(cutEntity->getLayer());
2124 cut1->trimEndpoint(cutCoord);
2125 cut1->trimStartpoint(cutCoord);
2129 cut1 = (AtomicEntity*)cutEntity->clone();
2130 cut2 = (AtomicEntity*)cutEntity->clone();
2132 cut1->trimEndpoint(cutCoord);
2133 cut2->trimStartpoint(cutCoord);
2136 // add new cut entity:
2137 container->addEntity(cut1);
2139 container->addEntity(cut2);
2142 if (graphicView!=NULL) {
2143 graphicView->drawEntity(cut1);
2145 graphicView->drawEntity(cut2);
2149 if (document!=NULL && handleUndo) {
2150 document->startUndoCycle();
2151 document->addUndoable(cut1);
2153 document->addUndoable(cut2);
2155 cutEntity->setUndoState(true);
2156 document->addUndoable(cutEntity);
2157 document->endUndoCycle();
2166 bool Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2167 const Vector& offset)
2171 DEBUG->print(Debug::D_WARNING,
2172 "Modification::stretch: Offset invalid");
2176 // Q3PtrList<Entity> addList;
2177 // addList.setAutoDelete(false);
2178 QList<Entity *> addList;
2180 if (document!=NULL && handleUndo) {
2181 document->startUndoCycle();
2184 // Create new entites
2185 for (Entity* e=container->firstEntity();
2187 e=container->nextEntity()) {
2188 //for (int i=0; i<container->count(); ++i) {
2189 // Entity* e = container->entityAt(i);
2194 (e->isInWindow(firstCorner, secondCorner) ||
2195 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2197 Entity* ec = e->clone();
2198 ec->stretch(firstCorner, secondCorner, offset);
2200 e->setSelected(true);
2204 deselectOriginals(true);
2205 addNewEntities(addList);
2207 if (document!=NULL && handleUndo) {
2208 document->endUndoCycle();
2211 if (graphicView!=NULL) {
2212 graphicView->redraw();
2222 * @param coord1 Mouse coordinate to specify direction from intersection.
2223 * @param entity1 First entity of the corner.
2224 * @param coord2 Mouse coordinate to specify direction from intersection.
2225 * @param entity2 Second entity of the corner.
2226 * @param data Lengths and trim flag.
2228 bool Modification::bevel(const Vector& coord1, AtomicEntity* entity1,
2229 const Vector& coord2, AtomicEntity* entity2,
2232 DEBUG->print("Modification::bevel");
2234 if (entity1==NULL || entity2==NULL) {
2235 DEBUG->print(Debug::D_WARNING,
2236 "Modification::bevel: At least one entity is NULL");
2240 EntityContainer* baseContainer = container;
2241 bool isPolyline = false;
2242 bool isClosedPolyline = false;
2244 if (document!=NULL && handleUndo) {
2245 document->startUndoCycle();
2248 // find out whether we're bevelling within a polyline:
2249 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2250 DEBUG->print("Modification::bevel: trimming polyline segments");
2251 if (entity1->getParent()!=entity2->getParent()) {
2252 DEBUG->print(Debug::D_WARNING,
2253 "Modification::bevel: entities not in the same polyline");
2256 // clone polyline for undo
2257 if (document!=NULL && handleUndo) {
2258 EntityContainer* cl =
2259 (EntityContainer*)entity1->getParent()->clone();
2260 container->addEntity(cl);
2261 //cl->setUndoState(true);
2262 document->addUndoable(cl);
2264 document->addUndoable(entity1->getParent());
2265 entity1->getParent()->setUndoState(true);
2270 entity1 = (AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2271 entity2 = (AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2273 //baseContainer = entity1->getParent();
2275 isClosedPolyline = ((Polyline*)entity1)->isClosed();
2278 DEBUG->print("Modification::bevel: getting intersection");
2280 VectorSolutions sol =
2281 Information::getIntersection(entity1, entity2, false);
2283 if (sol.getNumber()==0) {
2287 AtomicEntity* trimmed1 = NULL;
2288 AtomicEntity* trimmed2 = NULL;
2290 //if (data.trim || isPolyline) {
2295 trimmed1 = (AtomicEntity*)entity1->clone();
2296 trimmed2 = (AtomicEntity*)entity2->clone();
2299 #warning "!!! Old rendering path needs upgrading !!!"
2301 // remove trim entity (on screen):
2302 if (data.trim || isPolyline)
2308 graphicView->deleteEntity(baseContainer);
2312 graphicView->deleteEntity(entity1);
2313 graphicView->deleteEntity(entity2);
2319 // trim entities to intersection
2320 DEBUG->print("Modification::bevel: trim entities to intersection 01");
2321 bool start1 = false;
2322 Vector is = sol.getClosest(coord2);
2323 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2325 case RS2::EndingStart:
2326 trimmed1->trimStartpoint(is);
2329 case RS2::EndingEnd:
2330 trimmed1->trimEndpoint(is);
2337 DEBUG->print("Modification::bevel: trim entities to intersection 02");
2338 bool start2 = false;
2339 is = sol.getClosest(coord1);
2340 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2342 case RS2::EndingStart:
2343 trimmed2->trimStartpoint(is);
2346 case RS2::EndingEnd:
2347 trimmed2->trimEndpoint(is);
2356 // find definitive bevel points
2357 DEBUG->print("Modification::bevel: find definitive bevel points");
2358 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2359 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2362 DEBUG->print("Modification::bevel: final trim");
2363 if (data.trim==true) {
2365 case RS2::EndingStart:
2366 trimmed1->trimStartpoint(bp1);
2368 case RS2::EndingEnd:
2369 trimmed1->trimEndpoint(bp1);
2376 case RS2::EndingStart:
2377 trimmed2->trimStartpoint(bp2);
2379 case RS2::EndingEnd:
2380 trimmed2->trimEndpoint(bp2);
2386 // add new trimmed entities:
2387 if (isPolyline==false) {
2388 container->addEntity(trimmed1);
2389 container->addEntity(trimmed2);
2391 if (graphicView!=NULL) {
2393 graphicView->drawEntity(trimmed1);
2394 graphicView->drawEntity(trimmed2);
2401 DEBUG->print("Modification::bevel: add bevel line");
2402 Line* bevel = new Line(baseContainer, LineData(bp1, bp2));
2404 if (isPolyline==false) {
2405 baseContainer->addEntity(bevel);
2407 int idx1 = baseContainer->findEntity(trimmed1);
2408 int idx2 = baseContainer->findEntity(trimmed2);
2410 bevel->setSelected(baseContainer->isSelected());
2411 bevel->setLayer(baseContainer->getLayer());
2412 bevel->setPen(baseContainer->getPen());
2414 bool insertAfter1 = false;
2415 if (!isClosedPolyline) {
2416 insertAfter1 = (idx1<idx2);
2419 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2420 (idx2==0 && idx1==(int)baseContainer->count()-1));
2423 // insert bevel at the right position:
2424 //if ((idx1<idx2 && idx1!=0) ||
2425 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2427 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2430 baseContainer->insertEntity(idx1+1, bevel);
2432 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2435 baseContainer->insertEntity(idx2+1, bevel);
2440 ((Polyline*)baseContainer)->updateEndpoints();
2443 if (graphicView!=NULL) {
2445 graphicView->drawEntity(baseContainer);
2447 graphicView->drawEntity(bevel);
2451 DEBUG->print("Modification::bevel: handling undo");
2453 if (document!=NULL && handleUndo) {
2454 //document->startUndoCycle();
2456 if (isPolyline==false && data.trim==true) {
2457 document->addUndoable(trimmed1);
2458 entity1->setUndoState(true);
2459 document->addUndoable(entity1);
2461 document->addUndoable(trimmed2);
2462 entity2->setUndoState(true);
2463 document->addUndoable(entity2);
2466 if (isPolyline==false) {
2467 document->addUndoable(bevel);
2470 document->endUndoCycle();
2473 if (data.trim==false) {
2474 DEBUG->print("Modification::bevel: delete trimmed elements");
2477 DEBUG->print("Modification::bevel: delete trimmed elements: ok");
2489 * @param coord Mouse coordinate to specify the rounding.
2490 * @param entity1 First entity of the corner.
2491 * @param entity2 Second entity of the corner.
2492 * @param data Radius and trim flag.
2494 bool Modification::round(const Vector& coord,
2495 const Vector& coord1,
2496 AtomicEntity* entity1,
2497 const Vector& coord2,
2498 AtomicEntity* entity2,
2501 if (entity1==NULL || entity2==NULL) {
2502 DEBUG->print(Debug::D_WARNING,
2503 "Modification::round: At least one entity is NULL");
2507 EntityContainer* baseContainer = container;
2508 bool isPolyline = false;
2509 bool isClosedPolyline = false;
2511 if (document!=NULL && handleUndo) {
2512 document->startUndoCycle();
2515 // find out whether we're rounding within a polyline:
2516 if (entity1->getParent()!=NULL &&
2517 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2519 if (entity1->getParent()!=entity2->getParent()) {
2520 DEBUG->print(Debug::D_WARNING,
2521 "Modification::round: entities not in "
2522 "the same polyline");
2523 if (document!=NULL && handleUndo) {
2524 document->endUndoCycle();
2529 // clone polyline for undo
2530 if (document!=NULL && handleUndo) {
2531 EntityContainer* cl =
2532 (EntityContainer*)entity1->getParent()->clone();
2533 container->addEntity(cl);
2534 document->addUndoable(cl);
2536 document->addUndoable(entity1->getParent());
2537 entity1->getParent()->setUndoState(true);
2542 entity1 = (AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2543 entity2 = (AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2546 isClosedPolyline = ((Polyline*)entity1)->isClosed();
2549 // create 2 tmp parallels
2550 Creation creation(NULL, NULL);
2551 Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2552 Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2554 VectorSolutions sol2 =
2555 Information::getIntersection(entity1, entity2, false);
2557 VectorSolutions sol =
2558 Information::getIntersection(par1, par2, false);
2560 if (sol.getNumber()==0) {
2561 if (document!=NULL && handleUndo) {
2562 document->endUndoCycle();
2567 // there might be two intersections: choose the closest:
2568 Vector is = sol.getClosest(coord);
2569 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2570 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2571 double ang1 = is.angleTo(p1);
2572 double ang2 = is.angleTo(p2);
2573 bool reversed = (Math::getAngleDifference(ang1, ang2)>M_PI);
2575 Arc* arc = new Arc(baseContainer,
2582 AtomicEntity* trimmed1 = NULL;
2583 AtomicEntity* trimmed2 = NULL;
2585 if (data.trim || isPolyline) {
2590 trimmed1 = (AtomicEntity*)entity1->clone();
2591 trimmed2 = (AtomicEntity*)entity2->clone();
2594 #warning "!!! Old rendering path needs upgrading !!!"
2596 // remove trim entity:
2597 if (graphicView!=NULL)
2601 graphicView->deleteEntity(baseContainer);
2605 graphicView->deleteEntity(entity1);
2606 graphicView->deleteEntity(entity2);
2611 // trim entities to intersection
2612 Vector is2 = sol2.getClosest(coord2);
2613 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2615 case RS2::EndingStart:
2616 trimmed1->trimStartpoint(p1);
2618 case RS2::EndingEnd:
2619 trimmed1->trimEndpoint(p1);
2625 is2 = sol2.getClosest(coord1);
2626 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2628 case RS2::EndingStart:
2629 trimmed2->trimStartpoint(p2);
2631 case RS2::EndingEnd:
2632 trimmed2->trimEndpoint(p2);
2638 // add new trimmed entities:
2639 if (isPolyline==false) {
2640 container->addEntity(trimmed1);
2641 container->addEntity(trimmed2);
2643 if (graphicView!=NULL) {
2645 graphicView->drawEntity(trimmed1);
2646 graphicView->drawEntity(trimmed2);
2652 if (isPolyline==false) {
2653 baseContainer->addEntity(arc);
2655 // find out which base entity is before the rounding:
2656 int idx1 = baseContainer->findEntity(trimmed1);
2657 int idx2 = baseContainer->findEntity(trimmed2);
2659 arc->setSelected(baseContainer->isSelected());
2660 arc->setLayer(baseContainer->getLayer());
2661 arc->setPen(baseContainer->getPen());
2663 DEBUG->print("Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2664 DEBUG->print("Modification::round: idx1!=0: %d", (int)(idx1!=0));
2665 DEBUG->print("Modification::round: idx2==0: %d", (int)(idx2==0));
2666 DEBUG->print("Modification::round: idx1==(int)baseContainer->count()-1: %d",
2667 (int)(idx1==(int)baseContainer->count()-1));
2669 bool insertAfter1 = false;
2670 if (!isClosedPolyline) {
2671 insertAfter1 = (idx1<idx2);
2674 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2675 (idx2==0 && idx1==(int)baseContainer->count()-1));
2678 // insert rounding at the right position:
2679 //if ((idx1<idx2 && idx1!=0) ||
2680 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2683 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2686 baseContainer->insertEntity(idx1+1, arc);
2688 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2691 baseContainer->insertEntity(idx2+1, arc);
2696 ((Polyline*)baseContainer)->updateEndpoints();
2699 if (graphicView!=NULL) {
2701 graphicView->drawEntity(baseContainer);
2703 graphicView->drawEntity(arc);
2707 if (document!=NULL && handleUndo) {
2708 if (isPolyline==false && data.trim==true) {
2709 document->addUndoable(trimmed1);
2710 entity1->setUndoState(true);
2711 document->addUndoable(entity1);
2713 document->addUndoable(trimmed2);
2714 entity2->setUndoState(true);
2715 document->addUndoable(entity2);
2718 if (isPolyline==false) {
2719 document->addUndoable(arc);
2722 document->endUndoCycle();
2732 * Removes the selected entity containers and adds the entities in them as
2733 * new single entities.
2735 bool Modification::explode()
2737 if (container == NULL)
2739 DEBUG->print("Modification::explode: no valid container for addinge entities",
2744 // Q3PtrList<Entity> addList;
2745 // addList.setAutoDelete(false);
2746 QList<Entity *> addList;
2748 if (document!=NULL && handleUndo) {
2749 document->startUndoCycle();
2752 for (Entity* e=container->firstEntity();
2754 e=container->nextEntity()) {
2755 //for (uint i=0; i<container->count(); ++i) {
2756 //Entity* e = container->entityAt(i);
2758 if (e!=NULL && e->isSelected()) {
2759 if (e->isContainer()) {
2761 // add entities from container:
2762 EntityContainer* ec = (EntityContainer*)e;
2763 //ec->setSelected(false);
2765 // iterate and explode container:
2766 //for (uint i2=0; i2<ec->count(); ++i2) {
2767 // Entity* e2 = ec->entityAt(i2);
2768 RS2::ResolveLevel rl;
2772 switch (ec->rtti()) {
2773 case RS2::EntityText:
2774 case RS2::EntityHatch:
2775 case RS2::EntityPolyline:
2776 rl = RS2::ResolveAll;
2777 resolveLayer = true;
2781 case RS2::EntityInsert:
2783 resolveLayer = false;
2784 rl = RS2::ResolveNone;
2787 case RS2::EntityDimAligned:
2788 case RS2::EntityDimLinear:
2789 case RS2::EntityDimRadial:
2790 case RS2::EntityDimDiametric:
2791 case RS2::EntityDimAngular:
2792 case RS2::EntityDimLeader:
2793 rl = RS2::ResolveNone;
2794 resolveLayer = true;
2799 rl = RS2::ResolveAll;
2800 resolveLayer = true;
2805 for (Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2806 e2 = ec->nextEntity(rl)) {
2809 Entity* clone = e2->clone();
2810 clone->setSelected(false);
2811 clone->reparent(container);
2814 clone->setLayer(ec->getLayer());
2816 clone->setLayer(e2->getLayer());
2819 clone->setPen(ec->getPen(resolvePen));
2821 addList.append(clone);
2827 e->setSelected(false);
2832 deselectOriginals(true);
2833 addNewEntities(addList);
2835 if (document!=NULL && handleUndo) {
2836 document->endUndoCycle();
2839 if (graphicView!=NULL) {
2840 graphicView->redraw();
2846 bool Modification::explodeTextIntoLetters()
2848 if (container == NULL)
2850 DEBUG->print("Modification::explodeTextIntoLetters: no valid container"
2851 " for addinge entities", Debug::D_WARNING);
2855 // Q3PtrList<Entity> addList;
2856 // addList.setAutoDelete(false);
2857 QList<Entity *> addList;
2859 if (document!=NULL && handleUndo) {
2860 document->startUndoCycle();
2863 for (Entity* e=container->firstEntity();
2865 e=container->nextEntity()) {
2866 if (e!=NULL && e->isSelected()) {
2867 if (e->rtti()==RS2::EntityText) {
2868 // add letters of text:
2869 Text* text = (Text*)e;
2870 explodeTextIntoLetters(text, addList);
2872 e->setSelected(false);
2877 deselectOriginals(true);
2878 addNewEntities(addList);
2880 if (document!=NULL && handleUndo) {
2881 document->endUndoCycle();
2884 if (graphicView!=NULL) {
2885 graphicView->redraw();
2891 //bool Modification::explodeTextIntoLetters(Text* text, Q3PtrList<Entity>& addList)
2892 bool Modification::explodeTextIntoLetters(Text * text, QList<Entity *> & addList)
2897 // iterate though lines:
2898 for(Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2904 if (e2->rtti() == RS2::EntityContainer)
2906 EntityContainer * line = (EntityContainer *)e2;
2908 // iterate though letters:
2909 for(Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2914 // super / sub texts:
2915 if (e3->rtti() == RS2::EntityText)
2916 explodeTextIntoLetters((Text *)e3, addList);
2918 else if (e3->rtti() == RS2::EntityInsert)
2920 Insert * letter = (Insert *)e3;
2922 Text * tl = new Text(container, TextData(letter->getInsertionPoint(),
2923 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2924 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2925 letter->getAngle(), RS2::Update));
2927 tl->setLayer(text->getLayer());
2928 tl->setPen(text->getPen());
2941 * Moves all reference points of selected entities with the given data.
2943 bool Modification::moveRef(MoveRefData& data)
2945 if (container == NULL)
2947 DEBUG->print("Modification::moveRef: no valid container", Debug::D_WARNING);
2951 // Q3PtrList<Entity> addList;
2952 // addList.setAutoDelete(false);
2953 QList<Entity *> addList;
2955 if (document != NULL && handleUndo)
2956 document->startUndoCycle();
2958 // Create new entites
2959 for(Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2961 if (e != NULL && e->isSelected())
2963 Entity * ec = e->clone();
2964 ec->moveRef(data.ref, data.offset);
2965 // since 2.0.4.0: keep it selected
2966 ec->setSelected(true);
2971 deselectOriginals(true);
2972 addNewEntities(addList);
2974 if (document != NULL && handleUndo)
2975 document->endUndoCycle();
2977 if (graphicView != NULL)
2978 graphicView->redraw();