2 #include "rs_modification.h"
4 #include "rs_clipboard.h"
5 #include "rs_creation.h"
7 #include "rs_graphic.h"
8 #include "rs_information.h"
10 #include "rs_polyline.h"
15 * Default constructor.
17 * @param container The container to which we will add
18 * entities. Usually that's an RS_Graphic entity but
19 * it can also be a polyline, text, ...
20 * @param graphicView Pointer to graphic view or NULL if you don't want the
21 * any views to be updated.
22 * @param handleUndo true: Handle undo functionalitiy.
24 RS_Modification::RS_Modification(RS_EntityContainer & container,
25 RS_GraphicView * graphicView, bool handleUndo)
27 this->container = &container;
28 this->graphicView = graphicView;
29 this->handleUndo = handleUndo;
30 graphic = container.getGraphic();
31 document = container.getDocument();
35 * Deletes all selected entities.
37 void RS_Modification::remove()
39 if (container == NULL)
41 RS_DEBUG->print("RS_Modification::remove: no valid container", RS_Debug::D_WARNING);
46 document->startUndoCycle();
49 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
51 if (e != NULL && e->isSelected())
53 e->setSelected(false);
57 document->addUndoable(e);
62 document->endUndoCycle();
64 graphicView->redraw();
68 * Changes the attributes of all selected
70 bool RS_Modification::changeAttributes(RS_AttributesData & data)
72 if (container == NULL)
74 RS_DEBUG->print("RS_Modification::changeAttributes: no valid container", RS_Debug::D_WARNING);
78 // Q3PtrList<RS_Entity> addList;
79 // addList.setAutoDelete(false);
80 QList<RS_Entity *> addList;
83 document->startUndoCycle();
85 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
87 //for (uint i=0; i<container->count(); ++i) {
88 //RS_Entity* e = container->entityAt(i);
89 if (e != NULL && e->isSelected())
91 RS_Entity * ec = e->clone();
92 ec->setSelected(false);
94 RS_Pen pen = ec->getPen(false);
96 if (data.changeLayer == true)
97 ec->setLayer(data.layer);
99 if (data.changeColor == true)
100 pen.setColor(data.pen.getColor());
102 if (data.changeLineType == true)
103 pen.setLineType(data.pen.getLineType());
105 if (data.changeWidth == true)
106 pen.setWidth(data.pen.getWidth());
110 //if (data.useCurrentLayer) {
111 // ec->setLayerToActive();
113 //if (data.useCurrentAttributes) {
114 // ec->setPenToActive();
116 //if (ec->rtti()==RS2::EntityInsert) {
117 // ((RS_Insert*)ec)->update();
124 deselectOriginals(true);
125 addNewEntities(addList);
127 if (document != NULL)
128 document->endUndoCycle();
130 if (graphicView != NULL)
131 graphicView->redraw();
138 * Copies all selected entities from the given container to the clipboard.
139 * Layers and blocks that are needed are also copied if the container is
140 * or is part of an RS_Graphic.
142 * @param container The entity container.
143 * @param ref Reference point. The entities will be moved by -ref.
144 * @param cut true: cut instead of copying, false: copy
146 void RS_Modification::copy(const Vector& ref, const bool cut) {
148 if (container==NULL) {
149 RS_DEBUG->print("RS_Modification::copy: no valid container",
150 RS_Debug::D_WARNING);
154 RS_CLIPBOARD->clear();
156 RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
158 RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
161 // start undo cycle for the container if we're cutting
162 if (cut && document!=NULL) {
163 document->startUndoCycle();
166 // copy entities / layers / blocks
167 for (RS_Entity* e=container->firstEntity(); e!=NULL;
168 e=container->nextEntity()) {
169 //for (uint i=0; i<container->count(); ++i) {
170 //RS_Entity* e = container->entityAt(i);
172 if (e!=NULL && e->isSelected()) {
173 copyEntity(e, ref, cut);
177 if (cut && document!=NULL) {
178 document->endUndoCycle();
185 * Copies the given entity from the given container to the clipboard.
186 * Layers and blocks that are needed are also copied if the container is
187 * or is part of an RS_Graphic.
189 * @param e The entity.
190 * @param ref Reference point. The entities will be moved by -ref.
191 * @param cut true: cut instead of copying, false: copy
193 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
196 if (e!=NULL && e->isSelected()) {
197 // delete entity in graphic view:
199 if (graphicView!=NULL) {
200 graphicView->deleteEntity(e);
202 e->setSelected(false);
204 if (graphicView!=NULL) {
205 graphicView->deleteEntity(e);
207 e->setSelected(false);
208 if (graphicView!=NULL) {
209 graphicView->drawEntity(e);
213 // add entity to clipboard:
214 RS_Entity* c = e->clone();
216 RS_CLIPBOARD->addEntity(c);
221 // set layer to the layer clone:
222 RS_Layer* l = e->getLayer();
224 c->setLayer(l->getName());
227 // make sure all sub entities point to layers of the clipboard
228 if (c->isContainer()) {
229 RS_EntityContainer* ec = (RS_EntityContainer*)c;
231 for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
232 e2 = ec->nextEntity(RS2::ResolveAll)) {
234 //RS_Entity* e2 = ec->entityAt(i);
235 RS_Layer* l2 = e2->getLayer();
238 e2->setLayer(l2->getName());
244 e->changeUndoState();
245 if (document!=NULL) {
246 document->addUndoable(e);
256 * Copies all layers of the given entity to the clipboard.
258 void RS_Modification::copyLayers(RS_Entity* e) {
264 // add layer(s) of the entity if it's not an insert
265 // (inserts are on layer '0'):
266 if (e->rtti()!=RS2::EntityInsert) {
267 RS_Layer* l = e->getLayer();
269 if (!RS_CLIPBOARD->hasLayer(l->getName())) {
270 RS_CLIPBOARD->addLayer(l->clone());
275 // special handling of inserts:
277 // insert: add layer(s) of subentities:
278 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
280 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
281 e2=b->nextEntity()) {
282 //for (uint i=0; i<b->count(); ++i) {
283 //RS_Entity* e2 = b->entityAt(i);
293 * Copies all blocks of the given entity to the clipboard.
295 void RS_Modification::copyBlocks(RS_Entity* e) {
301 // add block of the entity if it's an insert
302 if (e->rtti()==RS2::EntityInsert) {
303 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
305 // add block of an insert:
306 if (!RS_CLIPBOARD->hasBlock(b->getName())) {
307 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
310 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
311 e2=b->nextEntity()) {
312 //for (uint i=0; i<b->count(); ++i) {
313 //RS_Entity* e2 = b->entityAt(i);
323 * Pastes all entities from the clipboard into the container.
324 * Layers and blocks that are needed are also copied if the container is
325 * or is part of an RS_Graphic.
327 * @param data Paste data.
328 * @param source The source from where to paste. NULL means the source
331 void RS_Modification::paste(const RS_PasteData& data, RS_Graphic* source) {
334 RS_DEBUG->print(RS_Debug::D_WARNING,
335 "RS_Modification::paste: Graphic is NULL");
342 source = RS_CLIPBOARD->getGraphic();
344 // graphics from the clipboard need to be scaled. from the part lib not:
345 RS2::Unit sourceUnit = source->getUnit();
346 RS2::Unit targetUnit = graphic->getUnit();
347 factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
350 if (document!=NULL) {
351 document->startUndoCycle();
357 RS_Layer* layer = graphic->getActiveLayer();
358 for(uint i=0; i<source->countLayers(); ++i) {
359 RS_Layer* l = source->layerAt(i);
361 if (graphic->findLayer(l->getName())==NULL) {
362 graphic->addLayer(l->clone());
366 graphic->activateLayer(layer);
371 for(uint i=0; i<source->countBlocks(); ++i) {
372 RS_Block* b = source->blockAt(i);
374 if (graphic->findBlock(b->getName())==NULL) {
375 RS_Block* bc = (RS_Block*)b->clone();
376 bc->reparent(container);
377 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
378 // scale block but don't scale inserts in block
379 // (they already scale with their block)
380 for(uint i2=0; i2<bc->count(); ++i2) {
381 RS_Entity* e = bc->entityAt(i2);
382 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
383 e->scale(bc->getBasePoint(),
384 Vector(factor, factor));
386 Vector ip = ((RS_Insert*)e)->getInsertionPoint();
387 ip.scale(bc->getBasePoint(),
388 Vector(factor, factor));
389 ((RS_Insert*)e)->setInsertionPoint(ip);
394 graphic->addBlock(bc);
400 // add entities to this host (graphic or a new block)
401 RS_EntityContainer* host = container;
406 if (data.asInsert==true) {
407 RS_BlockList* blkList = graphic->getBlockList();
409 blockName = blkList->newName(data.blockName);
412 new RS_Block(graphic,
413 RS_BlockData(blockName,
414 Vector(0.0,0.0), false));
415 graphic->addBlock(blk);
423 //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
424 //RS_Entity* e = source->entityAt(i);
425 for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
427 e=((RS_EntityContainer*)source)->nextEntity()) {
431 QString layerName = "0";
432 RS_Layer* layer = e->getLayer();
434 layerName = layer->getName();
436 RS_Entity* e2 = e->clone();
438 if (data.asInsert==false) {
439 e2->move(data.insertionPoint);
441 // don't adjust insert factor - block was already adjusted to unit
442 if (e2->rtti()==RS2::EntityInsert) {
443 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
444 ip.scale(data.insertionPoint, Vector(factor, factor));
445 ((RS_Insert*)e2)->setInsertionPoint(ip);
448 e2->scale(data.insertionPoint, Vector(factor, factor));
451 e2->setLayer(layerName);
453 // make sure all sub entities point to layers of the container
454 if (e2->isContainer()) {
455 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
457 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
458 e3 = ec->nextEntity(RS2::ResolveAll)) {
460 //RS_Entity* e3 = ec->entityAt(i);
461 RS_Layer* l2 = e3->getLayer();
463 e3->setLayer(l2->getName());
468 if (document!=NULL && data.asInsert==false) {
469 document->addUndoable(e2);
474 if (data.asInsert==true) {
476 new RS_Insert(container,
480 Vector(data.factor, data.factor),
482 1,1,Vector(0.0,0.0)));
483 container->addEntity(ins);
484 ins->setLayerToActive();
485 ins->setPenToActive();
487 if (document!=NULL) {
488 document->addUndoable(ins);
492 if (document!=NULL) {
493 document->endUndoCycle();
499 * Splits a polyline into two leaving out a gap.
501 * @param polyline The original polyline
502 * @param e1 1st entity on which the first cutting point is.
503 * @param v1 1st cutting point.
504 * @param e2 2nd entity on which the first cutting point is.
505 * @param v2 2nd cutting point.
506 * @param polyline1 Pointer to a polyline pointer which will hold the
507 * 1st resulting new polyline. Pass NULL if you don't
508 * need those pointers.
509 * @param polyline2 Pointer to a polyline pointer which will hold the
510 * 2nd resulting new polyline. Pass NULL if you don't
511 * need those pointers.
513 * @todo Support arcs in polylines, check for wrong parameters
517 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
518 RS_Entity& e1, Vector v1,
519 RS_Entity& e2, Vector v2,
520 RS_Polyline** polyline1,
521 RS_Polyline** polyline2) const {
523 if (container==NULL) {
524 RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
525 RS_Debug::D_WARNING);
529 RS_Entity* firstEntity = polyline.firstEntity();
530 Vector firstPoint(false);
531 if (firstEntity->rtti()==RS2::EntityLine) {
532 firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
535 new RS_Polyline(container,
536 RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
537 RS_Polyline* pl2 = new RS_Polyline(container);
538 RS_Polyline* pl = pl1; // Current polyline
539 RS_Line* line = NULL;
542 if (polyline1!=NULL) {
545 if (polyline2!=NULL) {
549 for (RS_Entity* e = polyline.firstEntity();
551 e = polyline.nextEntity()) {
553 if (e->rtti()==RS2::EntityLine) {
556 } else if (e->rtti()==RS2::EntityArc) {
564 if (line!=NULL /*|| arc!=NULL*/) {
566 if (e==&e1 && e==&e2) {
567 // Trim within a single entity:
568 Vector sp = line->getStartpoint();
569 double dist1 = (v1-sp).magnitude();
570 double dist2 = (v2-sp).magnitude();
571 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
573 pl->setStartpoint(dist1<dist2 ? v2 : v1);
574 pl->addVertex(line->getEndpoint(), 0.0);
575 } else if (e==&e1 || e==&e2) {
577 Vector v = (e==&e1 ? v1 : v2);
579 // Trim endpoint of entity to first vector
580 pl->addVertex(v, 0.0);
583 // Trim startpoint of entity to second vector
585 pl->setStartpoint(v);
586 pl->addVertex(line->getEndpoint(), 0.0);
589 // Add entities to polylines
590 if (line!=NULL && pl!=NULL) {
591 pl->addVertex(line->getEndpoint(), 0.0);
597 container->addEntity(pl1);
598 container->addEntity(pl2);
599 //container->removeEntity(&polyline);
600 polyline.changeUndoState();
608 * Adds a node to the given polyline. The new node is placed between
609 * the start and end point of the given segment.
611 * @param node The position of the new node.
613 * @return Pointer to the new polyline or NULL.
616 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
617 const RS_AtomicEntity& segment,
618 const Vector& node) {
619 RS_DEBUG->print("RS_Modification::addPolylineNode");
621 if (container==NULL) {
622 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
623 RS_Debug::D_WARNING);
627 if (segment.getParent()!=&polyline) {
628 RS_DEBUG->print("RS_Modification::addPolylineNode: "
629 "segment not part of the polyline",
630 RS_Debug::D_WARNING);
634 RS_Polyline* newPolyline = new RS_Polyline(container);
635 newPolyline->setClosed(polyline.isClosed());
636 newPolyline->setSelected(polyline.isSelected());
637 newPolyline->setLayer(polyline.getLayer());
638 newPolyline->setPen(polyline.getPen());
640 // copy polyline and add new node:
642 RS_Entity* lastEntity = polyline.lastEntity();
643 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
644 e=polyline.nextEntity()) {
647 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
649 if (ae->rtti()==RS2::EntityArc) {
650 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
651 bulge = ((RS_Arc*)ae)->getBulge();
653 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
658 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
659 ae->getStartpoint().x, ae->getStartpoint().y);
661 newPolyline->setNextBulge(bulge);
662 newPolyline->addVertex(ae->getStartpoint());
668 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
670 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
673 newPolyline->setNextBulge(0.0);
674 newPolyline->addVertex(node);
676 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
677 ae->getEndpoint().x, ae->getEndpoint().y);
679 if (ae!=lastEntity || polyline.isClosed()==false) {
680 newPolyline->setNextBulge(0.0);
681 newPolyline->addVertex(ae->getEndpoint());
684 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
685 ae->getEndpoint().x, ae->getEndpoint().y);
687 if (ae!=lastEntity || polyline.isClosed()==false) {
688 newPolyline->setNextBulge(bulge);
689 newPolyline->addVertex(ae->getEndpoint());
693 RS_DEBUG->print("RS_Modification::addPolylineNode: "
694 "Polyline contains non-atomic entities",
695 RS_Debug::D_WARNING);
699 newPolyline->setNextBulge(polyline.getClosingBulge());
700 newPolyline->endPolyline();
703 container->addEntity(newPolyline);
704 if (graphicView!=NULL) {
705 graphicView->deleteEntity(&polyline);
706 graphicView->drawEntity(newPolyline);
709 if (document!=NULL && handleUndo) {
710 document->startUndoCycle();
712 polyline.setUndoState(true);
713 document->addUndoable(&polyline);
714 document->addUndoable(newPolyline);
716 document->endUndoCycle();
726 * Deletes a node from a polyline.
728 * @param node The node to delete.
730 * @return Pointer to the new polyline or NULL.
733 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
734 const Vector& node) {
736 RS_DEBUG->print("RS_Modification::deletePolylineNode");
738 if (container==NULL) {
739 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
740 RS_Debug::D_WARNING);
744 if (node.valid==false) {
745 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
747 RS_Debug::D_WARNING);
751 // check if the polyline is no longer there after deleting the node:
752 if (polyline.count()==1) {
753 RS_Entity* e = polyline.firstEntity();
754 if (e!=NULL && e->isAtomic()) {
755 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
756 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
757 node.distanceTo(ae->getEndpoint())<1.0e-6) {
759 if (graphicView!=NULL) {
760 graphicView->deleteEntity(&polyline);
763 if (document!=NULL && handleUndo) {
764 document->startUndoCycle();
765 polyline.setUndoState(true);
766 document->addUndoable(&polyline);
767 document->endUndoCycle();
774 RS_Polyline* newPolyline = new RS_Polyline(container);
775 newPolyline->setClosed(polyline.isClosed());
776 newPolyline->setSelected(polyline.isSelected());
777 newPolyline->setLayer(polyline.getLayer());
778 newPolyline->setPen(polyline.getPen());
780 // copy polyline and drop deleted node:
782 bool lastDropped = false;
783 RS_Entity* lastEntity = polyline.lastEntity();
784 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
785 e=polyline.nextEntity()) {
788 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
790 if (ae->rtti()==RS2::EntityArc) {
791 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
792 bulge = ((RS_Arc*)ae)->getBulge();
794 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
798 // last entity is closing entity and will be added below with endPolyline()
799 if (e==lastEntity && polyline.isClosed()) {
803 // first vertex (startpoint)
804 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
805 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
806 ae->getStartpoint().x, ae->getStartpoint().y);
808 newPolyline->setNextBulge(bulge);
809 newPolyline->addVertex(ae->getStartpoint());
813 // normal node (not deleted):
814 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
815 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
816 ae->getEndpoint().x, ae->getEndpoint().y);
820 newPolyline->setNextBulge(bulge);
821 newPolyline->addVertex(ae->getEndpoint());
825 // drop deleted node:
827 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
828 ae->getEndpoint().x, ae->getEndpoint().y);
832 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
833 "Polyline contains non-atomic entities",
834 RS_Debug::D_WARNING);
838 RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
839 newPolyline->setNextBulge(polyline.getClosingBulge());
840 newPolyline->endPolyline();
842 //if (newPolyline->count()==1) {
846 RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
847 container->addEntity(newPolyline);
848 if (graphicView!=NULL) {
849 graphicView->deleteEntity(&polyline);
850 graphicView->drawEntity(newPolyline);
853 RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
854 if (document!=NULL && handleUndo) {
855 document->startUndoCycle();
857 polyline.setUndoState(true);
858 document->addUndoable(&polyline);
859 document->addUndoable(newPolyline);
861 document->endUndoCycle();
871 * Deletes all nodes between the two given nodes (exclusive).
873 * @param node1 First limiting node.
874 * @param node2 Second limiting node.
876 * @return Pointer to the new polyline or NULL.
879 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
880 RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
882 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
884 if (container==NULL) {
885 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
886 RS_Debug::D_WARNING);
890 if (node1.valid==false || node2.valid==false) {
891 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
893 RS_Debug::D_WARNING);
897 if (node1.distanceTo(node2)<1.0e-6) {
898 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
899 "nodes are identical",
900 RS_Debug::D_WARNING);
904 // check if there's nothing to delete:
905 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
906 e=polyline.nextEntity()) {
909 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
911 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
912 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
913 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
914 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
916 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
918 RS_Debug::D_WARNING);
925 // check if the start point is involved:
926 bool startpointInvolved = false;
927 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
928 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
929 startpointInvolved = true;
933 // check which part of the polyline has to be deleted:
934 bool deleteStart = false;
935 if (polyline.isClosed()) {
937 double length1 = 0.0;
938 double length2 = 0.0;
939 RS_Entity* e=polyline.firstEntity();
941 if (startpointInvolved) {
943 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
944 length1+=ae->getLength();
946 e = polyline.nextEntity();
948 for (; e!=NULL; e=polyline.nextEntity()) {
951 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
953 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
954 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
960 length2+=ae->getLength();
962 length1+=ae->getLength();
966 if (length1<length2) {
973 RS_Polyline* newPolyline = new RS_Polyline(container);
974 newPolyline->setClosed(polyline.isClosed());
975 newPolyline->setSelected(polyline.isSelected());
976 newPolyline->setLayer(polyline.getLayer());
977 newPolyline->setPen(polyline.getPen());
979 if (startpointInvolved && deleteStart && polyline.isClosed()) {
980 newPolyline->setNextBulge(0.0);
981 newPolyline->addVertex(polyline.getStartpoint());
984 // copy polyline and drop deleted nodes:
986 bool removing = deleteStart;
988 bool nextIsStraight = false;
989 RS_Entity* lastEntity = polyline.lastEntity();
992 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
993 e=polyline.nextEntity()) {
995 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
996 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
999 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1000 if (ae->rtti()==RS2::EntityArc) {
1001 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1002 bulge = ((RS_Arc*)ae)->getBulge();
1004 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1008 // last entity is closing entity and will be added below with endPolyline()
1009 if (e==lastEntity && polyline.isClosed()) {
1010 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1011 "dropping last vertex of closed polyline");
1015 // first vertex (startpoint)
1018 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1019 ae->getStartpoint().x, ae->getStartpoint().y);
1020 newPolyline->setNextBulge(bulge);
1021 newPolyline->addVertex(ae->getStartpoint());
1026 // stop removing nodes:
1027 if (removing==true &&
1028 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1029 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1030 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1031 "stop removing at: %f/%f",
1032 ae->getEndpoint().x, ae->getEndpoint().y);
1036 nextIsStraight = true;
1040 // normal node (not deleted):
1041 if (removing==false && (done==false || deleteStart==false)) {
1042 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1043 "normal vertex found: %f/%f",
1044 ae->getEndpoint().x, ae->getEndpoint().y);
1045 if (nextIsStraight) {
1047 nextIsStraight = false;
1049 newPolyline->setNextBulge(bulge);
1050 newPolyline->addVertex(ae->getEndpoint());
1053 // drop deleted node:
1055 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1056 "deleting vertex: %f/%f",
1057 ae->getEndpoint().x, ae->getEndpoint().y);
1060 // start to remove nodes from now on:
1061 if (done==false && removing==false &&
1062 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1063 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1064 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1065 "start removing at: %f/%f",
1066 ae->getEndpoint().x, ae->getEndpoint().y);
1074 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1075 "Polyline contains non-atomic entities",
1076 RS_Debug::D_WARNING);
1080 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1081 newPolyline->setNextBulge(polyline.getClosingBulge());
1082 newPolyline->endPolyline();
1084 // add new polyline:
1085 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1086 container->addEntity(newPolyline);
1087 if (graphicView!=NULL) {
1088 graphicView->deleteEntity(&polyline);
1089 graphicView->drawEntity(newPolyline);
1092 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1093 if (document!=NULL && handleUndo) {
1094 document->startUndoCycle();
1096 polyline.setUndoState(true);
1097 document->addUndoable(&polyline);
1098 document->addUndoable(newPolyline);
1100 document->endUndoCycle();
1110 * Trims two segments of a polyline all nodes between the two trim segments
1113 * @param polyline The polyline entity.
1114 * @param segment1 First segment to trim.
1115 * @param segment2 Second segment to trim.
1117 * @return Pointer to the new polyline or NULL.
1120 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1121 RS_AtomicEntity& segment1,
1122 RS_AtomicEntity& segment2) {
1124 RS_DEBUG->print("RS_Modification::polylineTrim");
1126 if (container==NULL) {
1127 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1128 RS_Debug::D_WARNING);
1132 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1133 RS_DEBUG->print("RS_Modification::polylineTrim: "
1134 "segments not in polyline",
1135 RS_Debug::D_WARNING);
1139 if (&segment1==&segment2) {
1140 RS_DEBUG->print("RS_Modification::polylineTrim: "
1141 "segments are identical",
1142 RS_Debug::D_WARNING);
1146 VectorSolutions sol;
1147 sol = RS_Information::getIntersection(&segment1, &segment2, false);
1149 if (sol.getNumber()==0) {
1150 RS_DEBUG->print("RS_Modification::polylineTrim: "
1151 "segments cannot be trimmed",
1152 RS_Debug::D_WARNING);
1156 // check which segment comes first in the polyline:
1157 RS_AtomicEntity* firstSegment;
1158 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1159 firstSegment = &segment2;
1161 firstSegment = &segment1;
1164 // find out if we need to trim towards the open part of the polyline
1166 reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1167 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1168 //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1169 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1171 RS_Polyline* newPolyline = new RS_Polyline(container);
1172 newPolyline->setClosed(polyline.isClosed());
1173 newPolyline->setSelected(polyline.isSelected());
1174 newPolyline->setLayer(polyline.getLayer());
1175 newPolyline->setPen(polyline.getPen());
1177 // normal trimming: start removing nodes at trim segment. ends stay the same
1178 if (reverseTrim==false) {
1179 // copy polyline, trim segments and drop between nodes:
1181 bool removing = false;
1182 bool nextIsStraight = false;
1183 RS_Entity* lastEntity = polyline.lastEntity();
1184 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1185 e=polyline.nextEntity()) {
1187 if (e->isAtomic()) {
1188 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1190 if (ae->rtti()==RS2::EntityArc) {
1191 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1192 bulge = ((RS_Arc*)ae)->getBulge();
1194 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1198 // last entity is closing entity and will be added below with endPolyline()
1199 if (e==lastEntity && polyline.isClosed()) {
1200 RS_DEBUG->print("RS_Modification::polylineTrim: "
1201 "dropping last vertex of closed polyline");
1205 // first vertex (startpoint)
1207 RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1208 ae->getStartpoint().x, ae->getStartpoint().y);
1210 newPolyline->setNextBulge(bulge);
1211 newPolyline->addVertex(ae->getStartpoint());
1215 // trim and start removing nodes:
1216 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1217 RS_DEBUG->print("RS_Modification::polylineTrim: "
1218 "start removing at trim point %f/%f",
1219 sol.get(0).x, sol.get(0).y);
1220 newPolyline->setNextBulge(0.0);
1221 newPolyline->addVertex(sol.get(0));
1223 nextIsStraight = true;
1226 // stop removing nodes:
1227 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1228 RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1229 ae->getEndpoint().x, ae->getEndpoint().y);
1233 // normal node (not deleted):
1234 if (removing==false) {
1235 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1236 ae->getEndpoint().x, ae->getEndpoint().y);
1237 if (nextIsStraight) {
1238 newPolyline->setNextBulge(0.0);
1239 nextIsStraight = false;
1241 newPolyline->setNextBulge(bulge);
1243 newPolyline->addVertex(ae->getEndpoint());
1246 RS_DEBUG->print("RS_Modification::polylineTrim: "
1247 "Polyline contains non-atomic entities",
1248 RS_Debug::D_WARNING);
1253 // reverse trimming: remove nodes at the ends and keep those in between
1255 // copy polyline, trim segments and drop between nodes:
1256 //bool first = true;
1257 bool removing = true;
1258 bool nextIsStraight = false;
1259 RS_Entity* lastEntity = polyline.lastEntity();
1260 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1261 e=polyline.nextEntity()) {
1263 if (e->isAtomic()) {
1264 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1266 if (ae->rtti()==RS2::EntityArc) {
1267 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1268 bulge = ((RS_Arc*)ae)->getBulge();
1270 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1274 // last entity is closing entity and will be added below with endPolyline()
1275 if (e==lastEntity && polyline.isClosed()) {
1276 RS_DEBUG->print("RS_Modification::polylineTrim: "
1277 "dropping last vertex of closed polyline");
1281 // trim and stop removing nodes:
1282 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1283 RS_DEBUG->print("RS_Modification::polylineTrim: "
1284 "stop removing at trim point %f/%f",
1285 sol.get(0).x, sol.get(0).y);
1286 newPolyline->setNextBulge(0.0);
1287 // start of new polyline:
1288 newPolyline->addVertex(sol.get(0));
1290 nextIsStraight = true;
1293 // start removing nodes again:
1294 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1295 RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1296 ae->getEndpoint().x, ae->getEndpoint().y);
1297 newPolyline->setNextBulge(0.0);
1298 // start of new polyline:
1299 newPolyline->addVertex(sol.get(0));
1303 // normal node (not deleted):
1304 if (removing==false) {
1305 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1306 ae->getEndpoint().x, ae->getEndpoint().y);
1307 if (nextIsStraight) {
1308 newPolyline->setNextBulge(0.0);
1309 nextIsStraight = false;
1311 newPolyline->setNextBulge(bulge);
1313 newPolyline->addVertex(ae->getEndpoint());
1316 RS_DEBUG->print("RS_Modification::polylineTrim: "
1317 "Polyline contains non-atomic entities",
1318 RS_Debug::D_WARNING);
1323 RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1324 newPolyline->setNextBulge(polyline.getClosingBulge());
1325 newPolyline->endPolyline();
1327 // add new polyline:
1328 RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1329 container->addEntity(newPolyline);
1330 if (graphicView!=NULL) {
1331 graphicView->deleteEntity(&polyline);
1332 graphicView->drawEntity(newPolyline);
1335 RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1336 if (document!=NULL && handleUndo) {
1337 document->startUndoCycle();
1339 polyline.setUndoState(true);
1340 document->addUndoable(&polyline);
1341 document->addUndoable(newPolyline);
1343 document->endUndoCycle();
1351 * Moves all selected entities with the given data for the move
1354 bool RS_Modification::move(RS_MoveData & data)
1356 if (container == NULL)
1358 RS_DEBUG->print("RS_Modification::move: no valid container", RS_Debug::D_WARNING);
1362 // Q3PtrList<RS_Entity> addList;
1363 // addList.setAutoDelete(false);
1364 QList<RS_Entity *> addList;
1366 if (document != NULL && handleUndo)
1367 document->startUndoCycle();
1369 // Create new entites
1370 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1373 //for (uint i=0; i<container->count(); ++i) {
1374 //RS_Entity* e = container->entityAt(i);
1375 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1377 if (e != NULL && e->isSelected())
1379 RS_Entity * ec = e->clone();
1380 ec->move(data.offset * num);
1382 if (data.useCurrentLayer)
1383 ec->setLayerToActive();
1385 if (data.useCurrentAttributes)
1386 ec->setPenToActive();
1388 if (ec->rtti() == RS2::EntityInsert)
1389 ((RS_Insert *)ec)->update();
1391 // since 2.0.4.0: keep selection
1392 ec->setSelected(true);
1398 deselectOriginals(data.number==0);
1399 addNewEntities(addList);
1401 if (document != NULL && handleUndo)
1402 document->endUndoCycle();
1404 if (graphicView != NULL)
1405 graphicView->redraw();
1411 * Rotates all selected entities with the given data for the rotation.
1413 bool RS_Modification::rotate(RS_RotateData & data)
1415 if (container == NULL)
1417 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1418 RS_Debug::D_WARNING);
1422 // Q3PtrList<RS_Entity> addList;
1423 // addList.setAutoDelete(false);
1424 QList<RS_Entity *> addList;
1426 if (document!=NULL && handleUndo)
1427 document->startUndoCycle();
1429 // Create new entites
1430 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1432 for (RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1434 //for (uint i=0; i<container->count(); ++i) {
1435 //RS_Entity* e = container->entityAt(i);
1437 if (e != NULL && e->isSelected())
1439 RS_Entity * ec = e->clone();
1440 ec->setSelected(false);
1441 ec->rotate(data.center, data.angle*num);
1443 if (data.useCurrentLayer)
1444 ec->setLayerToActive();
1446 if (data.useCurrentAttributes)
1447 ec->setPenToActive();
1449 if (ec->rtti() == RS2::EntityInsert)
1450 ((RS_Insert *)ec)->update();
1457 deselectOriginals(data.number == 0);
1458 addNewEntities(addList);
1460 if (document != NULL && handleUndo)
1461 document->endUndoCycle();
1463 if (graphicView != NULL)
1464 graphicView->redraw();
1470 * Moves all selected entities with the given data for the scale
1473 bool RS_Modification::scale(RS_ScaleData & data)
1475 if (container == NULL)
1477 RS_DEBUG->print("RS_Modification::scale: no valid container", RS_Debug::D_WARNING);
1481 // Q3PtrList<RS_Entity> addList;
1482 // addList.setAutoDelete(false);
1483 QList<RS_Entity *> addList;
1485 if (document!=NULL && handleUndo)
1486 document->startUndoCycle();
1488 // Create new entites
1489 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1491 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1493 //for (uint i=0; i<container->count(); ++i) {
1494 //RS_Entity* e = container->entityAt(i);
1495 if (e != NULL && e->isSelected())
1497 RS_Entity * ec = e->clone();
1498 ec->setSelected(false);
1499 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1501 if (data.useCurrentLayer)
1502 ec->setLayerToActive();
1504 if (data.useCurrentAttributes)
1505 ec->setPenToActive();
1507 if (ec->rtti()==RS2::EntityInsert)
1508 ((RS_Insert*)ec)->update();
1515 deselectOriginals(data.number == 0);
1516 addNewEntities(addList);
1518 if (document != NULL && handleUndo)
1519 document->endUndoCycle();
1521 if (graphicView != NULL)
1522 graphicView->redraw();
1528 * Mirror all selected entities with the given data for the mirror
1531 bool RS_Modification::mirror(RS_MirrorData & data)
1533 if (container==NULL) {
1534 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1535 RS_Debug::D_WARNING);
1539 // Q3PtrList<RS_Entity> addList;
1540 // addList.setAutoDelete(false);
1541 QList<RS_Entity *> addList;
1543 if (document!=NULL && handleUndo) {
1544 document->startUndoCycle();
1547 // Create new entites
1549 num<=(int)data.copy || (data.copy==false && num<=1);
1551 for (RS_Entity* e=container->firstEntity();
1553 e=container->nextEntity()) {
1554 //for (uint i=0; i<container->count(); ++i) {
1555 //RS_Entity* e = container->entityAt(i);
1557 if (e!=NULL && e->isSelected()) {
1558 RS_Entity* ec = e->clone();
1559 ec->setSelected(false);
1561 ec->mirror(data.axisPoint1, data.axisPoint2);
1562 if (data.useCurrentLayer) {
1563 ec->setLayerToActive();
1565 if (data.useCurrentAttributes) {
1566 ec->setPenToActive();
1568 if (ec->rtti()==RS2::EntityInsert) {
1569 ((RS_Insert*)ec)->update();
1576 deselectOriginals(data.copy==false);
1577 addNewEntities(addList);
1579 if (document!=NULL && handleUndo) {
1580 document->endUndoCycle();
1583 if (graphicView!=NULL) {
1584 graphicView->redraw();
1590 * Rotates entities around two centers with the given parameters.
1592 bool RS_Modification::rotate2(RS_Rotate2Data & data)
1594 if (container==NULL) {
1595 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1596 RS_Debug::D_WARNING);
1600 // Q3PtrList<RS_Entity> addList;
1601 // addList.setAutoDelete(false);
1602 QList<RS_Entity *> addList;
1604 if (document!=NULL && handleUndo) {
1605 document->startUndoCycle();
1608 // Create new entites
1610 num<=data.number || (data.number==0 && num<=1);
1613 for (RS_Entity* e=container->firstEntity();
1615 e=container->nextEntity()) {
1616 //for (uint i=0; i<container->count(); ++i) {
1617 //RS_Entity* e = container->entityAt(i);
1619 if (e!=NULL && e->isSelected()) {
1620 RS_Entity* ec = e->clone();
1621 ec->setSelected(false);
1623 ec->rotate(data.center1, data.angle1*num);
1624 Vector center2 = data.center2;
1625 center2.rotate(data.center1, data.angle1*num);
1627 ec->rotate(center2, data.angle2*num);
1628 if (data.useCurrentLayer) {
1629 ec->setLayerToActive();
1631 if (data.useCurrentAttributes) {
1632 ec->setPenToActive();
1634 if (ec->rtti()==RS2::EntityInsert) {
1635 ((RS_Insert*)ec)->update();
1642 deselectOriginals(data.number==0);
1643 addNewEntities(addList);
1645 if (document!=NULL && handleUndo) {
1646 document->endUndoCycle();
1649 if (graphicView!=NULL) {
1650 graphicView->redraw();
1656 * Moves and rotates entities with the given parameters.
1658 bool RS_Modification::moveRotate(RS_MoveRotateData & data)
1660 if (container==NULL) {
1661 RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1662 RS_Debug::D_WARNING);
1666 // Q3PtrList<RS_Entity> addList;
1667 // addList.setAutoDelete(false);
1668 QList<RS_Entity *> addList;
1670 if (document!=NULL && handleUndo) {
1671 document->startUndoCycle();
1674 // Create new entites
1676 num<=data.number || (data.number==0 && num<=1);
1678 for (RS_Entity* e=container->firstEntity();
1680 e=container->nextEntity()) {
1681 //for (uint i=0; i<container->count(); ++i) {
1682 //RS_Entity* e = container->entityAt(i);
1684 if (e!=NULL && e->isSelected()) {
1685 RS_Entity* ec = e->clone();
1686 ec->setSelected(false);
1688 ec->move(data.offset*num);
1689 ec->rotate(data.referencePoint + data.offset*num,
1691 if (data.useCurrentLayer) {
1692 ec->setLayerToActive();
1694 if (data.useCurrentAttributes) {
1695 ec->setPenToActive();
1697 if (ec->rtti()==RS2::EntityInsert) {
1698 ((RS_Insert*)ec)->update();
1705 deselectOriginals(data.number==0);
1706 addNewEntities(addList);
1708 if (document!=NULL && handleUndo) {
1709 document->endUndoCycle();
1711 if (graphicView!=NULL) {
1712 graphicView->redraw();
1719 * Deselects all selected entities and removes them if remove is true;
1721 * @param remove true: Remove entites.
1723 void RS_Modification::deselectOriginals(bool remove)
1725 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1727 //for (uint i=0; i<container->count(); ++i) {
1728 //RS_Entity* e = container->entityAt(i);
1732 bool selected = false;
1734 if (e->isAtomic()) {
1735 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1736 if (ae->isStartpointSelected() ||
1737 ae->isEndpointSelected()) {
1744 if (e->isSelected())
1749 e->setSelected(false);
1753 //if (graphicView!=NULL) {
1754 // graphicView->deleteEntity(e);
1756 e->changeUndoState();
1758 if (document != NULL && handleUndo)
1759 document->addUndoable(e);
1763 //if (graphicView!=NULL) {
1764 // graphicView->drawEntity(e);
1773 * Adds the given entities to the container and draws the entities if
1774 * there's a graphic view available.
1776 * @param addList Entities to add.
1778 //void RS_Modification::addNewEntities(Q3PtrList<RS_Entity> & addList)
1779 void RS_Modification::addNewEntities(QList<RS_Entity *> & addList)
1781 // for(RS_Entity * e=addList.first(); e!=NULL; e=addList.next())
1782 for(int i=0; i<addList.size(); i++)
1784 RS_Entity * e = addList[i];
1788 container->addEntity(e);
1790 if (document != NULL && handleUndo)
1791 document->addUndoable(e);
1792 //if (graphicView!=NULL) {
1793 // graphicView->drawEntity(e);
1800 * Trims or extends the given trimEntity to the intersection point of the
1801 * trimEntity and the limitEntity.
1803 * @param trimCoord Coordinate which defines which endpoint of the
1804 * trim entity to trim.
1805 * @param trimEntity Entity which will be trimmed.
1806 * @param limitCoord Coordinate which defines the intersection to which the
1807 * trim entity will be trimmed.
1808 * @param limitEntity Entity to which the trim entity will be trimmed.
1809 * @param both true: Trim both entities. false: trim trimEntity only.
1811 bool RS_Modification::trim(const Vector& trimCoord, RS_AtomicEntity* trimEntity,
1812 const Vector& limitCoord, RS_Entity* limitEntity, bool both)
1814 if (trimEntity==NULL || limitEntity==NULL)
1816 RS_DEBUG->print(RS_Debug::D_WARNING,
1817 "RS_Modification::trim: At least one entity is NULL");
1821 if (both && !limitEntity->isAtomic())
1823 RS_DEBUG->print(RS_Debug::D_WARNING,
1824 "RS_Modification::trim: limitEntity is not atomic");
1827 VectorSolutions sol;
1829 if (limitEntity->isAtomic())
1831 // intersection(s) of the two entities:
1832 sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1833 } else if (limitEntity->isContainer()) {
1834 RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1839 for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1840 e=ec->nextEntity(RS2::ResolveAll)) {
1841 //for (int i=0; i<container->count(); ++i) {
1842 // RS_Entity* e = container->entityAt(i);
1846 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1849 if (s2.hasValid()) {
1850 for (int k=0; k<s2.getNumber(); ++k) {
1851 if (i<128 && s2.get(k).valid) {
1852 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1853 sol.set(i++, s2.get(k));
1863 if (sol.hasValid()==false) {
1867 RS_AtomicEntity* trimmed1 = NULL;
1868 RS_AtomicEntity* trimmed2 = NULL;
1870 // remove trim entity from view:
1871 if (trimEntity->rtti()==RS2::EntityCircle) {
1872 // convert a circle into a trimmable arc
1873 RS_Circle* c = (RS_Circle*)trimEntity;
1874 double am = c->getCenter().angleTo(trimCoord);
1875 RS_ArcData d(c->getCenter(),
1877 RS_Math::correctAngle(am-M_PI/2),
1878 RS_Math::correctAngle(am+M_PI/2), false);
1879 trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1881 trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1882 trimmed1->setHighlighted(false);
1884 if (graphicView!=NULL) {
1885 graphicView->deleteEntity(trimEntity);
1888 // remove limit entity from view:
1890 trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1891 trimmed2->setHighlighted(false);
1892 if (graphicView!=NULL) {
1893 graphicView->deleteEntity(limitEntity);
1899 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1900 //sol.getClosest(limitCoord, NULL, &ind);
1901 RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1902 RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1903 RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1904 RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1905 Vector is2 = sol.get(ind==0 ? 1 : 0);
1906 //Vector is2 = sol.get(ind);
1907 RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1909 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1910 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1913 case RS2::EndingStart:
1914 trimmed1->trimStartpoint(is);
1915 if (trimEntity->rtti()==RS2::EntityCircle) {
1916 trimmed1->trimEndpoint(is2);
1919 case RS2::EndingEnd:
1920 trimmed1->trimEndpoint(is);
1921 if (trimEntity->rtti()==RS2::EntityCircle) {
1922 trimmed1->trimStartpoint(is2);
1929 // trim limit entity:
1931 Vector is = sol.getClosest(limitCoord);
1933 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1936 case RS2::EndingStart:
1937 trimmed2->trimStartpoint(is);
1939 case RS2::EndingEnd:
1940 trimmed2->trimEndpoint(is);
1947 // add new trimmed trim entity:
1948 container->addEntity(trimmed1);
1949 if (graphicView!=NULL) {
1950 graphicView->drawEntity(trimmed1);
1953 // add new trimmed limit entity:
1955 container->addEntity(trimmed2);
1956 if (graphicView!=NULL) {
1957 graphicView->drawEntity(trimmed2);
1961 if (document!=NULL && handleUndo) {
1962 document->startUndoCycle();
1963 document->addUndoable(trimmed1);
1964 trimEntity->setUndoState(true);
1965 document->addUndoable(trimEntity);
1967 document->addUndoable(trimmed2);
1968 limitEntity->setUndoState(true);
1969 document->addUndoable(limitEntity);
1971 document->endUndoCycle();
1980 * Trims or extends the given trimEntity by the given amount.
1982 * @param trimCoord Coordinate which defines which endpoint of the
1983 * trim entity to trim.
1984 * @param trimEntity Entity which will be trimmed.
1985 * @param dist Amount to trim by.
1987 bool RS_Modification::trimAmount(const Vector& trimCoord,
1988 RS_AtomicEntity* trimEntity,
1991 if (trimEntity==NULL) {
1992 RS_DEBUG->print(RS_Debug::D_WARNING,
1993 "RS_Modification::trimAmount: Entity is NULL");
1997 RS_AtomicEntity* trimmed = NULL;
1999 // remove trim entity:
2000 trimmed = (RS_AtomicEntity*)trimEntity->clone();
2001 if (graphicView!=NULL) {
2002 graphicView->deleteEntity(trimEntity);
2006 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2007 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2008 trimCoord.distanceTo(trimmed->getEndpoint())) {
2009 trimmed->trimStartpoint(is);
2011 trimmed->trimEndpoint(is);
2014 // add new trimmed trim entity:
2015 container->addEntity(trimmed);
2017 if (graphicView!=NULL) {
2018 graphicView->drawEntity(trimmed);
2021 if (document!=NULL && handleUndo) {
2022 document->startUndoCycle();
2023 document->addUndoable(trimmed);
2024 trimEntity->setUndoState(true);
2025 document->addUndoable(trimEntity);
2026 document->endUndoCycle();
2035 * Cuts the given entity at the given point.
2037 bool RS_Modification::cut(const Vector& cutCoord,
2038 RS_AtomicEntity* cutEntity) {
2040 if (cutEntity==NULL) {
2041 RS_DEBUG->print(RS_Debug::D_WARNING,
2042 "RS_Modification::cut: Entity is NULL");
2046 if (!cutCoord.valid) {
2047 RS_DEBUG->print(RS_Debug::D_WARNING,
2048 "RS_Modification::cut: Point invalid.");
2052 // cut point is at endpoint of entity:
2053 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2054 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2055 RS_DEBUG->print(RS_Debug::D_WARNING,
2056 "RS_Modification::cut: Cutting point on endpoint");
2060 // delete cut entity on the screen:
2061 if (graphicView!=NULL) {
2062 graphicView->deleteEntity(cutEntity);
2065 RS_AtomicEntity* cut1 = NULL;
2066 RS_AtomicEntity* cut2 = NULL;
2068 // create new two halves:
2069 if (cutEntity->rtti()==RS2::EntityCircle) {
2070 RS_Circle* c = (RS_Circle*)cutEntity;
2071 cut1 = new RS_Arc(cutEntity->getParent(),
2072 RS_ArcData(c->getCenter(),
2075 cut1->setPen(cutEntity->getPen());
2076 cut1->setLayer(cutEntity->getLayer());
2079 cut1->trimEndpoint(cutCoord);
2080 cut1->trimStartpoint(cutCoord);
2082 cut1 = (RS_AtomicEntity*)cutEntity->clone();
2083 cut2 = (RS_AtomicEntity*)cutEntity->clone();
2085 cut1->trimEndpoint(cutCoord);
2086 cut2->trimStartpoint(cutCoord);
2089 // add new cut entity:
2090 container->addEntity(cut1);
2092 container->addEntity(cut2);
2095 if (graphicView!=NULL) {
2096 graphicView->drawEntity(cut1);
2098 graphicView->drawEntity(cut2);
2102 if (document!=NULL && handleUndo) {
2103 document->startUndoCycle();
2104 document->addUndoable(cut1);
2106 document->addUndoable(cut2);
2108 cutEntity->setUndoState(true);
2109 document->addUndoable(cutEntity);
2110 document->endUndoCycle();
2119 bool RS_Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2120 const Vector& offset)
2124 RS_DEBUG->print(RS_Debug::D_WARNING,
2125 "RS_Modification::stretch: Offset invalid");
2129 // Q3PtrList<RS_Entity> addList;
2130 // addList.setAutoDelete(false);
2131 QList<RS_Entity *> addList;
2133 if (document!=NULL && handleUndo) {
2134 document->startUndoCycle();
2137 // Create new entites
2138 for (RS_Entity* e=container->firstEntity();
2140 e=container->nextEntity()) {
2141 //for (int i=0; i<container->count(); ++i) {
2142 // RS_Entity* e = container->entityAt(i);
2147 (e->isInWindow(firstCorner, secondCorner) ||
2148 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2150 RS_Entity* ec = e->clone();
2151 ec->stretch(firstCorner, secondCorner, offset);
2153 e->setSelected(true);
2157 deselectOriginals(true);
2158 addNewEntities(addList);
2160 if (document!=NULL && handleUndo) {
2161 document->endUndoCycle();
2164 if (graphicView!=NULL) {
2165 graphicView->redraw();
2175 * @param coord1 Mouse coordinate to specify direction from intersection.
2176 * @param entity1 First entity of the corner.
2177 * @param coord2 Mouse coordinate to specify direction from intersection.
2178 * @param entity2 Second entity of the corner.
2179 * @param data Lengths and trim flag.
2181 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2182 const Vector& coord2, RS_AtomicEntity* entity2,
2183 RS_BevelData& data) {
2185 RS_DEBUG->print("RS_Modification::bevel");
2187 if (entity1==NULL || entity2==NULL) {
2188 RS_DEBUG->print(RS_Debug::D_WARNING,
2189 "RS_Modification::bevel: At least one entity is NULL");
2193 RS_EntityContainer* baseContainer = container;
2194 bool isPolyline = false;
2195 bool isClosedPolyline = false;
2197 if (document!=NULL && handleUndo) {
2198 document->startUndoCycle();
2201 // find out whether we're bevelling within a polyline:
2202 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2203 RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2204 if (entity1->getParent()!=entity2->getParent()) {
2205 RS_DEBUG->print(RS_Debug::D_WARNING,
2206 "RS_Modification::bevel: entities not in the same polyline");
2209 // clone polyline for undo
2210 if (document!=NULL && handleUndo) {
2211 RS_EntityContainer* cl =
2212 (RS_EntityContainer*)entity1->getParent()->clone();
2213 container->addEntity(cl);
2214 //cl->setUndoState(true);
2215 document->addUndoable(cl);
2217 document->addUndoable(entity1->getParent());
2218 entity1->getParent()->setUndoState(true);
2223 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2224 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2226 //baseContainer = entity1->getParent();
2228 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2231 RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2233 VectorSolutions sol =
2234 RS_Information::getIntersection(entity1, entity2, false);
2236 if (sol.getNumber()==0) {
2240 RS_AtomicEntity* trimmed1 = NULL;
2241 RS_AtomicEntity* trimmed2 = NULL;
2243 //if (data.trim || isPolyline) {
2248 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2249 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2252 // remove trim entity (on screen):
2253 if (data.trim==true || isPolyline) {
2254 if (graphicView!=NULL) {
2256 graphicView->deleteEntity(baseContainer);
2258 graphicView->deleteEntity(entity1);
2259 graphicView->deleteEntity(entity2);
2264 // trim entities to intersection
2265 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2266 bool start1 = false;
2267 Vector is = sol.getClosest(coord2);
2268 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2270 case RS2::EndingStart:
2271 trimmed1->trimStartpoint(is);
2274 case RS2::EndingEnd:
2275 trimmed1->trimEndpoint(is);
2282 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2283 bool start2 = false;
2284 is = sol.getClosest(coord1);
2285 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2287 case RS2::EndingStart:
2288 trimmed2->trimStartpoint(is);
2291 case RS2::EndingEnd:
2292 trimmed2->trimEndpoint(is);
2301 // find definitive bevel points
2302 RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2303 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2304 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2307 RS_DEBUG->print("RS_Modification::bevel: final trim");
2308 if (data.trim==true) {
2310 case RS2::EndingStart:
2311 trimmed1->trimStartpoint(bp1);
2313 case RS2::EndingEnd:
2314 trimmed1->trimEndpoint(bp1);
2321 case RS2::EndingStart:
2322 trimmed2->trimStartpoint(bp2);
2324 case RS2::EndingEnd:
2325 trimmed2->trimEndpoint(bp2);
2331 // add new trimmed entities:
2332 if (isPolyline==false) {
2333 container->addEntity(trimmed1);
2334 container->addEntity(trimmed2);
2336 if (graphicView!=NULL) {
2338 graphicView->drawEntity(trimmed1);
2339 graphicView->drawEntity(trimmed2);
2346 RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2347 RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2349 if (isPolyline==false) {
2350 baseContainer->addEntity(bevel);
2352 int idx1 = baseContainer->findEntity(trimmed1);
2353 int idx2 = baseContainer->findEntity(trimmed2);
2355 bevel->setSelected(baseContainer->isSelected());
2356 bevel->setLayer(baseContainer->getLayer());
2357 bevel->setPen(baseContainer->getPen());
2359 bool insertAfter1 = false;
2360 if (!isClosedPolyline) {
2361 insertAfter1 = (idx1<idx2);
2364 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2365 (idx2==0 && idx1==(int)baseContainer->count()-1));
2368 // insert bevel at the right position:
2369 //if ((idx1<idx2 && idx1!=0) ||
2370 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2372 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2375 baseContainer->insertEntity(idx1+1, bevel);
2377 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2380 baseContainer->insertEntity(idx2+1, bevel);
2385 ((RS_Polyline*)baseContainer)->updateEndpoints();
2388 if (graphicView!=NULL) {
2390 graphicView->drawEntity(baseContainer);
2392 graphicView->drawEntity(bevel);
2396 RS_DEBUG->print("RS_Modification::bevel: handling undo");
2398 if (document!=NULL && handleUndo) {
2399 //document->startUndoCycle();
2401 if (isPolyline==false && data.trim==true) {
2402 document->addUndoable(trimmed1);
2403 entity1->setUndoState(true);
2404 document->addUndoable(entity1);
2406 document->addUndoable(trimmed2);
2407 entity2->setUndoState(true);
2408 document->addUndoable(entity2);
2411 if (isPolyline==false) {
2412 document->addUndoable(bevel);
2415 document->endUndoCycle();
2418 if (data.trim==false) {
2419 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2422 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2434 * @param coord Mouse coordinate to specify the rounding.
2435 * @param entity1 First entity of the corner.
2436 * @param entity2 Second entity of the corner.
2437 * @param data Radius and trim flag.
2439 bool RS_Modification::round(const Vector& coord,
2440 const Vector& coord1,
2441 RS_AtomicEntity* entity1,
2442 const Vector& coord2,
2443 RS_AtomicEntity* entity2,
2444 RS_RoundData& data) {
2446 if (entity1==NULL || entity2==NULL) {
2447 RS_DEBUG->print(RS_Debug::D_WARNING,
2448 "RS_Modification::round: At least one entity is NULL");
2452 RS_EntityContainer* baseContainer = container;
2453 bool isPolyline = false;
2454 bool isClosedPolyline = false;
2456 if (document!=NULL && handleUndo) {
2457 document->startUndoCycle();
2460 // find out whether we're rounding within a polyline:
2461 if (entity1->getParent()!=NULL &&
2462 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2464 if (entity1->getParent()!=entity2->getParent()) {
2465 RS_DEBUG->print(RS_Debug::D_WARNING,
2466 "RS_Modification::round: entities not in "
2467 "the same polyline");
2468 if (document!=NULL && handleUndo) {
2469 document->endUndoCycle();
2474 // clone polyline for undo
2475 if (document!=NULL && handleUndo) {
2476 RS_EntityContainer* cl =
2477 (RS_EntityContainer*)entity1->getParent()->clone();
2478 container->addEntity(cl);
2479 document->addUndoable(cl);
2481 document->addUndoable(entity1->getParent());
2482 entity1->getParent()->setUndoState(true);
2487 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2488 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2491 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2494 // create 2 tmp parallels
2495 RS_Creation creation(NULL, NULL);
2496 RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2497 RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2499 VectorSolutions sol2 =
2500 RS_Information::getIntersection(entity1, entity2, false);
2502 VectorSolutions sol =
2503 RS_Information::getIntersection(par1, par2, false);
2505 if (sol.getNumber()==0) {
2506 if (document!=NULL && handleUndo) {
2507 document->endUndoCycle();
2512 // there might be two intersections: choose the closest:
2513 Vector is = sol.getClosest(coord);
2514 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2515 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2516 double ang1 = is.angleTo(p1);
2517 double ang2 = is.angleTo(p2);
2518 bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2520 RS_Arc* arc = new RS_Arc(baseContainer,
2527 RS_AtomicEntity* trimmed1 = NULL;
2528 RS_AtomicEntity* trimmed2 = NULL;
2530 if (data.trim || isPolyline) {
2535 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2536 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2539 // remove trim entity:
2540 if (graphicView!=NULL) {
2542 graphicView->deleteEntity(baseContainer);
2544 graphicView->deleteEntity(entity1);
2545 graphicView->deleteEntity(entity2);
2549 // trim entities to intersection
2550 Vector is2 = sol2.getClosest(coord2);
2551 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2553 case RS2::EndingStart:
2554 trimmed1->trimStartpoint(p1);
2556 case RS2::EndingEnd:
2557 trimmed1->trimEndpoint(p1);
2563 is2 = sol2.getClosest(coord1);
2564 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2566 case RS2::EndingStart:
2567 trimmed2->trimStartpoint(p2);
2569 case RS2::EndingEnd:
2570 trimmed2->trimEndpoint(p2);
2576 // add new trimmed entities:
2577 if (isPolyline==false) {
2578 container->addEntity(trimmed1);
2579 container->addEntity(trimmed2);
2581 if (graphicView!=NULL) {
2583 graphicView->drawEntity(trimmed1);
2584 graphicView->drawEntity(trimmed2);
2590 if (isPolyline==false) {
2591 baseContainer->addEntity(arc);
2593 // find out which base entity is before the rounding:
2594 int idx1 = baseContainer->findEntity(trimmed1);
2595 int idx2 = baseContainer->findEntity(trimmed2);
2597 arc->setSelected(baseContainer->isSelected());
2598 arc->setLayer(baseContainer->getLayer());
2599 arc->setPen(baseContainer->getPen());
2601 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2602 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2603 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2604 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2605 (int)(idx1==(int)baseContainer->count()-1));
2607 bool insertAfter1 = false;
2608 if (!isClosedPolyline) {
2609 insertAfter1 = (idx1<idx2);
2612 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2613 (idx2==0 && idx1==(int)baseContainer->count()-1));
2616 // insert rounding at the right position:
2617 //if ((idx1<idx2 && idx1!=0) ||
2618 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2621 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2624 baseContainer->insertEntity(idx1+1, arc);
2626 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2629 baseContainer->insertEntity(idx2+1, arc);
2634 ((RS_Polyline*)baseContainer)->updateEndpoints();
2637 if (graphicView!=NULL) {
2639 graphicView->drawEntity(baseContainer);
2641 graphicView->drawEntity(arc);
2645 if (document!=NULL && handleUndo) {
2646 if (isPolyline==false && data.trim==true) {
2647 document->addUndoable(trimmed1);
2648 entity1->setUndoState(true);
2649 document->addUndoable(entity1);
2651 document->addUndoable(trimmed2);
2652 entity2->setUndoState(true);
2653 document->addUndoable(entity2);
2656 if (isPolyline==false) {
2657 document->addUndoable(arc);
2660 document->endUndoCycle();
2670 * Removes the selected entity containers and adds the entities in them as
2671 * new single entities.
2673 bool RS_Modification::explode()
2675 if (container == NULL)
2677 RS_DEBUG->print("RS_Modification::explode: no valid container for addinge entities",
2678 RS_Debug::D_WARNING);
2682 // Q3PtrList<RS_Entity> addList;
2683 // addList.setAutoDelete(false);
2684 QList<RS_Entity *> addList;
2686 if (document!=NULL && handleUndo) {
2687 document->startUndoCycle();
2690 for (RS_Entity* e=container->firstEntity();
2692 e=container->nextEntity()) {
2693 //for (uint i=0; i<container->count(); ++i) {
2694 //RS_Entity* e = container->entityAt(i);
2696 if (e!=NULL && e->isSelected()) {
2697 if (e->isContainer()) {
2699 // add entities from container:
2700 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2701 //ec->setSelected(false);
2703 // iterate and explode container:
2704 //for (uint i2=0; i2<ec->count(); ++i2) {
2705 // RS_Entity* e2 = ec->entityAt(i2);
2706 RS2::ResolveLevel rl;
2710 switch (ec->rtti()) {
2711 case RS2::EntityText:
2712 case RS2::EntityHatch:
2713 case RS2::EntityPolyline:
2714 rl = RS2::ResolveAll;
2715 resolveLayer = true;
2719 case RS2::EntityInsert:
2721 resolveLayer = false;
2722 rl = RS2::ResolveNone;
2725 case RS2::EntityDimAligned:
2726 case RS2::EntityDimLinear:
2727 case RS2::EntityDimRadial:
2728 case RS2::EntityDimDiametric:
2729 case RS2::EntityDimAngular:
2730 case RS2::EntityDimLeader:
2731 rl = RS2::ResolveNone;
2732 resolveLayer = true;
2737 rl = RS2::ResolveAll;
2738 resolveLayer = true;
2743 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2744 e2 = ec->nextEntity(rl)) {
2747 RS_Entity* clone = e2->clone();
2748 clone->setSelected(false);
2749 clone->reparent(container);
2752 clone->setLayer(ec->getLayer());
2754 clone->setLayer(e2->getLayer());
2757 clone->setPen(ec->getPen(resolvePen));
2759 addList.append(clone);
2765 e->setSelected(false);
2770 deselectOriginals(true);
2771 addNewEntities(addList);
2773 if (document!=NULL && handleUndo) {
2774 document->endUndoCycle();
2777 if (graphicView!=NULL) {
2778 graphicView->redraw();
2784 bool RS_Modification::explodeTextIntoLetters()
2786 if (container == NULL)
2788 RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2789 " for addinge entities", RS_Debug::D_WARNING);
2793 // Q3PtrList<RS_Entity> addList;
2794 // addList.setAutoDelete(false);
2795 QList<RS_Entity *> addList;
2797 if (document!=NULL && handleUndo) {
2798 document->startUndoCycle();
2801 for (RS_Entity* e=container->firstEntity();
2803 e=container->nextEntity()) {
2804 if (e!=NULL && e->isSelected()) {
2805 if (e->rtti()==RS2::EntityText) {
2806 // add letters of text:
2807 RS_Text* text = (RS_Text*)e;
2808 explodeTextIntoLetters(text, addList);
2810 e->setSelected(false);
2815 deselectOriginals(true);
2816 addNewEntities(addList);
2818 if (document!=NULL && handleUndo) {
2819 document->endUndoCycle();
2822 if (graphicView!=NULL) {
2823 graphicView->redraw();
2829 //bool RS_Modification::explodeTextIntoLetters(RS_Text* text, Q3PtrList<RS_Entity>& addList)
2830 bool RS_Modification::explodeTextIntoLetters(RS_Text * text, QList<RS_Entity *> & addList)
2835 // iterate though lines:
2836 for(RS_Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2842 if (e2->rtti() == RS2::EntityContainer)
2844 RS_EntityContainer * line = (RS_EntityContainer *)e2;
2846 // iterate though letters:
2847 for(RS_Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2852 // super / sub texts:
2853 if (e3->rtti() == RS2::EntityText)
2854 explodeTextIntoLetters((RS_Text *)e3, addList);
2856 else if (e3->rtti() == RS2::EntityInsert)
2858 RS_Insert * letter = (RS_Insert *)e3;
2860 RS_Text * tl = new RS_Text(container, RS_TextData(letter->getInsertionPoint(),
2861 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2862 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2863 letter->getAngle(), RS2::Update));
2865 tl->setLayer(text->getLayer());
2866 tl->setPen(text->getPen());
2879 * Moves all reference points of selected entities with the given data.
2881 bool RS_Modification::moveRef(RS_MoveRefData& data)
2883 if (container == NULL)
2885 RS_DEBUG->print("RS_Modification::moveRef: no valid container", RS_Debug::D_WARNING);
2889 // Q3PtrList<RS_Entity> addList;
2890 // addList.setAutoDelete(false);
2891 QList<RS_Entity *> addList;
2893 if (document != NULL && handleUndo)
2894 document->startUndoCycle();
2896 // Create new entites
2897 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2899 if (e != NULL && e->isSelected())
2901 RS_Entity * ec = e->clone();
2902 ec->moveRef(data.ref, data.offset);
2903 // since 2.0.4.0: keep it selected
2904 ec->setSelected(true);
2909 deselectOriginals(true);
2910 addNewEntities(addList);
2912 if (document != NULL && handleUndo)
2913 document->endUndoCycle();
2915 if (graphicView != NULL)
2916 graphicView->redraw();