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 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 06/01/2010 Added this text. :-)
15 #include "rs_modification.h"
17 #include "rs_clipboard.h"
18 #include "rs_creation.h"
19 #include "rs_entity.h"
21 #include "rs_information.h"
22 #include "rs_insert.h"
23 #include "rs_polyline.h"
28 * Default constructor.
30 * @param container The container to which we will add
31 * entities. Usually that's an Drawing entity but
32 * it can also be a polyline, text, ...
33 * @param graphicView Pointer to graphic view or NULL if you don't want the
34 * any views to be updated.
35 * @param handleUndo true: Handle undo functionalitiy.
37 RS_Modification::RS_Modification(RS_EntityContainer & container,
38 RS_GraphicView * graphicView, bool handleUndo)
40 this->container = &container;
41 this->graphicView = graphicView;
42 this->handleUndo = handleUndo;
43 graphic = container.getGraphic();
44 document = container.getDocument();
48 * Deletes all selected entities.
50 void RS_Modification::remove()
52 if (container == NULL)
54 RS_DEBUG->print("RS_Modification::remove: no valid container", RS_Debug::D_WARNING);
59 document->startUndoCycle();
62 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
64 if (e != NULL && e->isSelected())
66 e->setSelected(false);
70 document->addUndoable(e);
75 document->endUndoCycle();
77 graphicView->redraw();
81 * Changes the attributes of all selected
83 bool RS_Modification::changeAttributes(RS_AttributesData & data)
85 if (container == NULL)
87 RS_DEBUG->print("RS_Modification::changeAttributes: no valid container", RS_Debug::D_WARNING);
91 // Q3PtrList<RS_Entity> addList;
92 // addList.setAutoDelete(false);
93 QList<RS_Entity *> addList;
96 document->startUndoCycle();
98 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
100 //for (uint i=0; i<container->count(); ++i) {
101 //RS_Entity* e = container->entityAt(i);
102 if (e != NULL && e->isSelected())
104 RS_Entity * ec = e->clone();
105 ec->setSelected(false);
107 RS_Pen pen = ec->getPen(false);
109 if (data.changeLayer == true)
110 ec->setLayer(data.layer);
112 if (data.changeColor == true)
113 pen.setColor(data.pen.getColor());
115 if (data.changeLineType == true)
116 pen.setLineType(data.pen.getLineType());
118 if (data.changeWidth == true)
119 pen.setWidth(data.pen.getWidth());
123 //if (data.useCurrentLayer) {
124 // ec->setLayerToActive();
126 //if (data.useCurrentAttributes) {
127 // ec->setPenToActive();
129 //if (ec->rtti()==RS2::EntityInsert) {
130 // ((RS_Insert*)ec)->update();
137 deselectOriginals(true);
138 addNewEntities(addList);
140 if (document != NULL)
141 document->endUndoCycle();
143 if (graphicView != NULL)
144 graphicView->redraw();
151 * Copies all selected entities from the given container to the clipboard.
152 * Layers and blocks that are needed are also copied if the container is
153 * or is part of an Drawing.
155 * @param container The entity container.
156 * @param ref Reference point. The entities will be moved by -ref.
157 * @param cut true: cut instead of copying, false: copy
159 void RS_Modification::copy(const Vector& ref, const bool cut) {
161 if (container==NULL) {
162 RS_DEBUG->print("RS_Modification::copy: no valid container",
163 RS_Debug::D_WARNING);
167 RS_CLIPBOARD->clear();
169 RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
171 RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
174 // start undo cycle for the container if we're cutting
175 if (cut && document!=NULL) {
176 document->startUndoCycle();
179 // copy entities / layers / blocks
180 for (RS_Entity* e=container->firstEntity(); e!=NULL;
181 e=container->nextEntity()) {
182 //for (uint i=0; i<container->count(); ++i) {
183 //RS_Entity* e = container->entityAt(i);
185 if (e!=NULL && e->isSelected()) {
186 copyEntity(e, ref, cut);
190 if (cut && document!=NULL) {
191 document->endUndoCycle();
198 * Copies the given entity from the given container to the clipboard.
199 * Layers and blocks that are needed are also copied if the container is
200 * or is part of an Drawing.
202 * @param e The entity.
203 * @param ref Reference point. The entities will be moved by -ref.
204 * @param cut true: cut instead of copying, false: copy
206 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
209 if (e!=NULL && e->isSelected()) {
210 // delete entity in graphic view:
212 if (graphicView!=NULL) {
213 graphicView->deleteEntity(e);
215 e->setSelected(false);
217 if (graphicView!=NULL) {
218 graphicView->deleteEntity(e);
220 e->setSelected(false);
221 if (graphicView!=NULL) {
222 graphicView->drawEntity(e);
226 // add entity to clipboard:
227 RS_Entity* c = e->clone();
229 RS_CLIPBOARD->addEntity(c);
234 // set layer to the layer clone:
235 RS_Layer* l = e->getLayer();
237 c->setLayer(l->getName());
240 // make sure all sub entities point to layers of the clipboard
241 if (c->isContainer()) {
242 RS_EntityContainer* ec = (RS_EntityContainer*)c;
244 for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
245 e2 = ec->nextEntity(RS2::ResolveAll)) {
247 //RS_Entity* e2 = ec->entityAt(i);
248 RS_Layer* l2 = e2->getLayer();
251 e2->setLayer(l2->getName());
257 e->changeUndoState();
258 if (document!=NULL) {
259 document->addUndoable(e);
269 * Copies all layers of the given entity to the clipboard.
271 void RS_Modification::copyLayers(RS_Entity* e) {
277 // add layer(s) of the entity if it's not an insert
278 // (inserts are on layer '0'):
279 if (e->rtti()!=RS2::EntityInsert) {
280 RS_Layer* l = e->getLayer();
282 if (!RS_CLIPBOARD->hasLayer(l->getName())) {
283 RS_CLIPBOARD->addLayer(l->clone());
288 // special handling of inserts:
290 // insert: add layer(s) of subentities:
291 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
293 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
294 e2=b->nextEntity()) {
295 //for (uint i=0; i<b->count(); ++i) {
296 //RS_Entity* e2 = b->entityAt(i);
306 * Copies all blocks of the given entity to the clipboard.
308 void RS_Modification::copyBlocks(RS_Entity* e) {
314 // add block of the entity if it's an insert
315 if (e->rtti()==RS2::EntityInsert) {
316 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
318 // add block of an insert:
319 if (!RS_CLIPBOARD->hasBlock(b->getName())) {
320 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
323 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
324 e2=b->nextEntity()) {
325 //for (uint i=0; i<b->count(); ++i) {
326 //RS_Entity* e2 = b->entityAt(i);
336 * Pastes all entities from the clipboard into the container.
337 * Layers and blocks that are needed are also copied if the container is
338 * or is part of an Drawing.
340 * @param data Paste data.
341 * @param source The source from where to paste. NULL means the source
344 void RS_Modification::paste(const RS_PasteData& data, Drawing* source) {
347 RS_DEBUG->print(RS_Debug::D_WARNING,
348 "RS_Modification::paste: Graphic is NULL");
355 source = RS_CLIPBOARD->getGraphic();
357 // graphics from the clipboard need to be scaled. from the part lib not:
358 RS2::Unit sourceUnit = source->getUnit();
359 RS2::Unit targetUnit = graphic->getUnit();
360 factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
363 if (document!=NULL) {
364 document->startUndoCycle();
370 RS_Layer* layer = graphic->getActiveLayer();
371 for(uint i=0; i<source->countLayers(); ++i) {
372 RS_Layer* l = source->layerAt(i);
374 if (graphic->findLayer(l->getName())==NULL) {
375 graphic->addLayer(l->clone());
379 graphic->activateLayer(layer);
384 for(uint i=0; i<source->countBlocks(); ++i) {
385 RS_Block* b = source->blockAt(i);
387 if (graphic->findBlock(b->getName())==NULL) {
388 RS_Block* bc = (RS_Block*)b->clone();
389 bc->reparent(container);
390 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
391 // scale block but don't scale inserts in block
392 // (they already scale with their block)
393 for(uint i2=0; i2<bc->count(); ++i2) {
394 RS_Entity* e = bc->entityAt(i2);
395 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
396 e->scale(bc->getBasePoint(),
397 Vector(factor, factor));
399 Vector ip = ((RS_Insert*)e)->getInsertionPoint();
400 ip.scale(bc->getBasePoint(),
401 Vector(factor, factor));
402 ((RS_Insert*)e)->setInsertionPoint(ip);
407 graphic->addBlock(bc);
413 // add entities to this host (graphic or a new block)
414 RS_EntityContainer* host = container;
419 if (data.asInsert==true) {
420 RS_BlockList* blkList = graphic->getBlockList();
422 blockName = blkList->newName(data.blockName);
425 new RS_Block(graphic,
426 RS_BlockData(blockName,
427 Vector(0.0,0.0), false));
428 graphic->addBlock(blk);
436 //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
437 //RS_Entity* e = source->entityAt(i);
438 for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
440 e=((RS_EntityContainer*)source)->nextEntity()) {
444 QString layerName = "0";
445 RS_Layer* layer = e->getLayer();
447 layerName = layer->getName();
449 RS_Entity* e2 = e->clone();
451 if (data.asInsert==false) {
452 e2->move(data.insertionPoint);
454 // don't adjust insert factor - block was already adjusted to unit
455 if (e2->rtti()==RS2::EntityInsert) {
456 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
457 ip.scale(data.insertionPoint, Vector(factor, factor));
458 ((RS_Insert*)e2)->setInsertionPoint(ip);
461 e2->scale(data.insertionPoint, Vector(factor, factor));
464 e2->setLayer(layerName);
466 // make sure all sub entities point to layers of the container
467 if (e2->isContainer()) {
468 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
470 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
471 e3 = ec->nextEntity(RS2::ResolveAll)) {
473 //RS_Entity* e3 = ec->entityAt(i);
474 RS_Layer* l2 = e3->getLayer();
476 e3->setLayer(l2->getName());
481 if (document!=NULL && data.asInsert==false) {
482 document->addUndoable(e2);
487 if (data.asInsert==true) {
489 new RS_Insert(container,
493 Vector(data.factor, data.factor),
495 1,1,Vector(0.0,0.0)));
496 container->addEntity(ins);
497 ins->setLayerToActive();
498 ins->setPenToActive();
500 if (document!=NULL) {
501 document->addUndoable(ins);
505 if (document!=NULL) {
506 document->endUndoCycle();
512 * Splits a polyline into two leaving out a gap.
514 * @param polyline The original polyline
515 * @param e1 1st entity on which the first cutting point is.
516 * @param v1 1st cutting point.
517 * @param e2 2nd entity on which the first cutting point is.
518 * @param v2 2nd cutting point.
519 * @param polyline1 Pointer to a polyline pointer which will hold the
520 * 1st resulting new polyline. Pass NULL if you don't
521 * need those pointers.
522 * @param polyline2 Pointer to a polyline pointer which will hold the
523 * 2nd resulting new polyline. Pass NULL if you don't
524 * need those pointers.
526 * @todo Support arcs in polylines, check for wrong parameters
530 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
531 RS_Entity& e1, Vector v1,
532 RS_Entity& e2, Vector v2,
533 RS_Polyline** polyline1,
534 RS_Polyline** polyline2) const {
536 if (container==NULL) {
537 RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
538 RS_Debug::D_WARNING);
542 RS_Entity* firstEntity = polyline.firstEntity();
543 Vector firstPoint(false);
544 if (firstEntity->rtti()==RS2::EntityLine) {
545 firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
548 new RS_Polyline(container,
549 RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
550 RS_Polyline* pl2 = new RS_Polyline(container);
551 RS_Polyline* pl = pl1; // Current polyline
552 RS_Line* line = NULL;
555 if (polyline1!=NULL) {
558 if (polyline2!=NULL) {
562 for (RS_Entity* e = polyline.firstEntity();
564 e = polyline.nextEntity()) {
566 if (e->rtti()==RS2::EntityLine) {
569 } else if (e->rtti()==RS2::EntityArc) {
577 if (line!=NULL /*|| arc!=NULL*/) {
579 if (e==&e1 && e==&e2) {
580 // Trim within a single entity:
581 Vector sp = line->getStartpoint();
582 double dist1 = (v1-sp).magnitude();
583 double dist2 = (v2-sp).magnitude();
584 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
586 pl->setStartpoint(dist1<dist2 ? v2 : v1);
587 pl->addVertex(line->getEndpoint(), 0.0);
588 } else if (e==&e1 || e==&e2) {
590 Vector v = (e==&e1 ? v1 : v2);
592 // Trim endpoint of entity to first vector
593 pl->addVertex(v, 0.0);
596 // Trim startpoint of entity to second vector
598 pl->setStartpoint(v);
599 pl->addVertex(line->getEndpoint(), 0.0);
602 // Add entities to polylines
603 if (line!=NULL && pl!=NULL) {
604 pl->addVertex(line->getEndpoint(), 0.0);
610 container->addEntity(pl1);
611 container->addEntity(pl2);
612 //container->removeEntity(&polyline);
613 polyline.changeUndoState();
621 * Adds a node to the given polyline. The new node is placed between
622 * the start and end point of the given segment.
624 * @param node The position of the new node.
626 * @return Pointer to the new polyline or NULL.
629 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
630 const RS_AtomicEntity& segment,
631 const Vector& node) {
632 RS_DEBUG->print("RS_Modification::addPolylineNode");
634 if (container==NULL) {
635 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
636 RS_Debug::D_WARNING);
640 if (segment.getParent()!=&polyline) {
641 RS_DEBUG->print("RS_Modification::addPolylineNode: "
642 "segment not part of the polyline",
643 RS_Debug::D_WARNING);
647 RS_Polyline* newPolyline = new RS_Polyline(container);
648 newPolyline->setClosed(polyline.isClosed());
649 newPolyline->setSelected(polyline.isSelected());
650 newPolyline->setLayer(polyline.getLayer());
651 newPolyline->setPen(polyline.getPen());
653 // copy polyline and add new node:
655 RS_Entity* lastEntity = polyline.lastEntity();
656 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
657 e=polyline.nextEntity()) {
660 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
662 if (ae->rtti()==RS2::EntityArc) {
663 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
664 bulge = ((RS_Arc*)ae)->getBulge();
666 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
671 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
672 ae->getStartpoint().x, ae->getStartpoint().y);
674 newPolyline->setNextBulge(bulge);
675 newPolyline->addVertex(ae->getStartpoint());
681 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
683 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
686 newPolyline->setNextBulge(0.0);
687 newPolyline->addVertex(node);
689 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
690 ae->getEndpoint().x, ae->getEndpoint().y);
692 if (ae!=lastEntity || polyline.isClosed()==false) {
693 newPolyline->setNextBulge(0.0);
694 newPolyline->addVertex(ae->getEndpoint());
697 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
698 ae->getEndpoint().x, ae->getEndpoint().y);
700 if (ae!=lastEntity || polyline.isClosed()==false) {
701 newPolyline->setNextBulge(bulge);
702 newPolyline->addVertex(ae->getEndpoint());
706 RS_DEBUG->print("RS_Modification::addPolylineNode: "
707 "Polyline contains non-atomic entities",
708 RS_Debug::D_WARNING);
712 newPolyline->setNextBulge(polyline.getClosingBulge());
713 newPolyline->endPolyline();
716 container->addEntity(newPolyline);
717 if (graphicView!=NULL) {
718 graphicView->deleteEntity(&polyline);
719 graphicView->drawEntity(newPolyline);
722 if (document!=NULL && handleUndo) {
723 document->startUndoCycle();
725 polyline.setUndoState(true);
726 document->addUndoable(&polyline);
727 document->addUndoable(newPolyline);
729 document->endUndoCycle();
739 * Deletes a node from a polyline.
741 * @param node The node to delete.
743 * @return Pointer to the new polyline or NULL.
746 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
747 const Vector& node) {
749 RS_DEBUG->print("RS_Modification::deletePolylineNode");
751 if (container==NULL) {
752 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
753 RS_Debug::D_WARNING);
757 if (node.valid==false) {
758 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
760 RS_Debug::D_WARNING);
764 // check if the polyline is no longer there after deleting the node:
765 if (polyline.count()==1) {
766 RS_Entity* e = polyline.firstEntity();
767 if (e!=NULL && e->isAtomic()) {
768 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
769 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
770 node.distanceTo(ae->getEndpoint())<1.0e-6) {
772 if (graphicView!=NULL) {
773 graphicView->deleteEntity(&polyline);
776 if (document!=NULL && handleUndo) {
777 document->startUndoCycle();
778 polyline.setUndoState(true);
779 document->addUndoable(&polyline);
780 document->endUndoCycle();
787 RS_Polyline* newPolyline = new RS_Polyline(container);
788 newPolyline->setClosed(polyline.isClosed());
789 newPolyline->setSelected(polyline.isSelected());
790 newPolyline->setLayer(polyline.getLayer());
791 newPolyline->setPen(polyline.getPen());
793 // copy polyline and drop deleted node:
795 bool lastDropped = false;
796 RS_Entity* lastEntity = polyline.lastEntity();
797 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
798 e=polyline.nextEntity()) {
801 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
803 if (ae->rtti()==RS2::EntityArc) {
804 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
805 bulge = ((RS_Arc*)ae)->getBulge();
807 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
811 // last entity is closing entity and will be added below with endPolyline()
812 if (e==lastEntity && polyline.isClosed()) {
816 // first vertex (startpoint)
817 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
818 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
819 ae->getStartpoint().x, ae->getStartpoint().y);
821 newPolyline->setNextBulge(bulge);
822 newPolyline->addVertex(ae->getStartpoint());
826 // normal node (not deleted):
827 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
828 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
829 ae->getEndpoint().x, ae->getEndpoint().y);
833 newPolyline->setNextBulge(bulge);
834 newPolyline->addVertex(ae->getEndpoint());
838 // drop deleted node:
840 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
841 ae->getEndpoint().x, ae->getEndpoint().y);
845 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
846 "Polyline contains non-atomic entities",
847 RS_Debug::D_WARNING);
851 RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
852 newPolyline->setNextBulge(polyline.getClosingBulge());
853 newPolyline->endPolyline();
855 //if (newPolyline->count()==1) {
859 RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
860 container->addEntity(newPolyline);
861 if (graphicView!=NULL) {
862 graphicView->deleteEntity(&polyline);
863 graphicView->drawEntity(newPolyline);
866 RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
867 if (document!=NULL && handleUndo) {
868 document->startUndoCycle();
870 polyline.setUndoState(true);
871 document->addUndoable(&polyline);
872 document->addUndoable(newPolyline);
874 document->endUndoCycle();
884 * Deletes all nodes between the two given nodes (exclusive).
886 * @param node1 First limiting node.
887 * @param node2 Second limiting node.
889 * @return Pointer to the new polyline or NULL.
892 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
893 RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
895 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
897 if (container==NULL) {
898 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
899 RS_Debug::D_WARNING);
903 if (node1.valid==false || node2.valid==false) {
904 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
906 RS_Debug::D_WARNING);
910 if (node1.distanceTo(node2)<1.0e-6) {
911 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
912 "nodes are identical",
913 RS_Debug::D_WARNING);
917 // check if there's nothing to delete:
918 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
919 e=polyline.nextEntity()) {
922 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
924 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
925 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
926 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
927 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
929 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
931 RS_Debug::D_WARNING);
938 // check if the start point is involved:
939 bool startpointInvolved = false;
940 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
941 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
942 startpointInvolved = true;
946 // check which part of the polyline has to be deleted:
947 bool deleteStart = false;
948 if (polyline.isClosed()) {
950 double length1 = 0.0;
951 double length2 = 0.0;
952 RS_Entity* e=polyline.firstEntity();
954 if (startpointInvolved) {
956 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
957 length1+=ae->getLength();
959 e = polyline.nextEntity();
961 for (; e!=NULL; e=polyline.nextEntity()) {
964 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
966 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
967 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
973 length2+=ae->getLength();
975 length1+=ae->getLength();
979 if (length1<length2) {
986 RS_Polyline* newPolyline = new RS_Polyline(container);
987 newPolyline->setClosed(polyline.isClosed());
988 newPolyline->setSelected(polyline.isSelected());
989 newPolyline->setLayer(polyline.getLayer());
990 newPolyline->setPen(polyline.getPen());
992 if (startpointInvolved && deleteStart && polyline.isClosed()) {
993 newPolyline->setNextBulge(0.0);
994 newPolyline->addVertex(polyline.getStartpoint());
997 // copy polyline and drop deleted nodes:
999 bool removing = deleteStart;
1001 bool nextIsStraight = false;
1002 RS_Entity* lastEntity = polyline.lastEntity();
1005 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1006 e=polyline.nextEntity()) {
1008 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1009 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1011 if (e->isAtomic()) {
1012 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1013 if (ae->rtti()==RS2::EntityArc) {
1014 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1015 bulge = ((RS_Arc*)ae)->getBulge();
1017 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1021 // last entity is closing entity and will be added below with endPolyline()
1022 if (e==lastEntity && polyline.isClosed()) {
1023 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1024 "dropping last vertex of closed polyline");
1028 // first vertex (startpoint)
1031 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1032 ae->getStartpoint().x, ae->getStartpoint().y);
1033 newPolyline->setNextBulge(bulge);
1034 newPolyline->addVertex(ae->getStartpoint());
1039 // stop removing nodes:
1040 if (removing==true &&
1041 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1042 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1043 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1044 "stop removing at: %f/%f",
1045 ae->getEndpoint().x, ae->getEndpoint().y);
1049 nextIsStraight = true;
1053 // normal node (not deleted):
1054 if (removing==false && (done==false || deleteStart==false)) {
1055 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1056 "normal vertex found: %f/%f",
1057 ae->getEndpoint().x, ae->getEndpoint().y);
1058 if (nextIsStraight) {
1060 nextIsStraight = false;
1062 newPolyline->setNextBulge(bulge);
1063 newPolyline->addVertex(ae->getEndpoint());
1066 // drop deleted node:
1068 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1069 "deleting vertex: %f/%f",
1070 ae->getEndpoint().x, ae->getEndpoint().y);
1073 // start to remove nodes from now on:
1074 if (done==false && removing==false &&
1075 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1076 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1077 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1078 "start removing at: %f/%f",
1079 ae->getEndpoint().x, ae->getEndpoint().y);
1087 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1088 "Polyline contains non-atomic entities",
1089 RS_Debug::D_WARNING);
1093 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1094 newPolyline->setNextBulge(polyline.getClosingBulge());
1095 newPolyline->endPolyline();
1097 // add new polyline:
1098 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1099 container->addEntity(newPolyline);
1100 if (graphicView!=NULL) {
1101 graphicView->deleteEntity(&polyline);
1102 graphicView->drawEntity(newPolyline);
1105 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1106 if (document!=NULL && handleUndo) {
1107 document->startUndoCycle();
1109 polyline.setUndoState(true);
1110 document->addUndoable(&polyline);
1111 document->addUndoable(newPolyline);
1113 document->endUndoCycle();
1123 * Trims two segments of a polyline all nodes between the two trim segments
1126 * @param polyline The polyline entity.
1127 * @param segment1 First segment to trim.
1128 * @param segment2 Second segment to trim.
1130 * @return Pointer to the new polyline or NULL.
1133 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1134 RS_AtomicEntity& segment1,
1135 RS_AtomicEntity& segment2) {
1137 RS_DEBUG->print("RS_Modification::polylineTrim");
1139 if (container==NULL) {
1140 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1141 RS_Debug::D_WARNING);
1145 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1146 RS_DEBUG->print("RS_Modification::polylineTrim: "
1147 "segments not in polyline",
1148 RS_Debug::D_WARNING);
1152 if (&segment1==&segment2) {
1153 RS_DEBUG->print("RS_Modification::polylineTrim: "
1154 "segments are identical",
1155 RS_Debug::D_WARNING);
1159 VectorSolutions sol;
1160 sol = RS_Information::getIntersection(&segment1, &segment2, false);
1162 if (sol.getNumber()==0) {
1163 RS_DEBUG->print("RS_Modification::polylineTrim: "
1164 "segments cannot be trimmed",
1165 RS_Debug::D_WARNING);
1169 // check which segment comes first in the polyline:
1170 RS_AtomicEntity* firstSegment;
1171 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1172 firstSegment = &segment2;
1174 firstSegment = &segment1;
1177 // find out if we need to trim towards the open part of the polyline
1179 reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1180 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1181 //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1182 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1184 RS_Polyline* newPolyline = new RS_Polyline(container);
1185 newPolyline->setClosed(polyline.isClosed());
1186 newPolyline->setSelected(polyline.isSelected());
1187 newPolyline->setLayer(polyline.getLayer());
1188 newPolyline->setPen(polyline.getPen());
1190 // normal trimming: start removing nodes at trim segment. ends stay the same
1191 if (reverseTrim==false) {
1192 // copy polyline, trim segments and drop between nodes:
1194 bool removing = false;
1195 bool nextIsStraight = false;
1196 RS_Entity* lastEntity = polyline.lastEntity();
1197 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1198 e=polyline.nextEntity()) {
1200 if (e->isAtomic()) {
1201 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1203 if (ae->rtti()==RS2::EntityArc) {
1204 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1205 bulge = ((RS_Arc*)ae)->getBulge();
1207 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1211 // last entity is closing entity and will be added below with endPolyline()
1212 if (e==lastEntity && polyline.isClosed()) {
1213 RS_DEBUG->print("RS_Modification::polylineTrim: "
1214 "dropping last vertex of closed polyline");
1218 // first vertex (startpoint)
1220 RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1221 ae->getStartpoint().x, ae->getStartpoint().y);
1223 newPolyline->setNextBulge(bulge);
1224 newPolyline->addVertex(ae->getStartpoint());
1228 // trim and start removing nodes:
1229 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1230 RS_DEBUG->print("RS_Modification::polylineTrim: "
1231 "start removing at trim point %f/%f",
1232 sol.get(0).x, sol.get(0).y);
1233 newPolyline->setNextBulge(0.0);
1234 newPolyline->addVertex(sol.get(0));
1236 nextIsStraight = true;
1239 // stop removing nodes:
1240 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1241 RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1242 ae->getEndpoint().x, ae->getEndpoint().y);
1246 // normal node (not deleted):
1247 if (removing==false) {
1248 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1249 ae->getEndpoint().x, ae->getEndpoint().y);
1250 if (nextIsStraight) {
1251 newPolyline->setNextBulge(0.0);
1252 nextIsStraight = false;
1254 newPolyline->setNextBulge(bulge);
1256 newPolyline->addVertex(ae->getEndpoint());
1259 RS_DEBUG->print("RS_Modification::polylineTrim: "
1260 "Polyline contains non-atomic entities",
1261 RS_Debug::D_WARNING);
1266 // reverse trimming: remove nodes at the ends and keep those in between
1268 // copy polyline, trim segments and drop between nodes:
1269 //bool first = true;
1270 bool removing = true;
1271 bool nextIsStraight = false;
1272 RS_Entity* lastEntity = polyline.lastEntity();
1273 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1274 e=polyline.nextEntity()) {
1276 if (e->isAtomic()) {
1277 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1279 if (ae->rtti()==RS2::EntityArc) {
1280 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1281 bulge = ((RS_Arc*)ae)->getBulge();
1283 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1287 // last entity is closing entity and will be added below with endPolyline()
1288 if (e==lastEntity && polyline.isClosed()) {
1289 RS_DEBUG->print("RS_Modification::polylineTrim: "
1290 "dropping last vertex of closed polyline");
1294 // trim and stop removing nodes:
1295 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1296 RS_DEBUG->print("RS_Modification::polylineTrim: "
1297 "stop removing at trim point %f/%f",
1298 sol.get(0).x, sol.get(0).y);
1299 newPolyline->setNextBulge(0.0);
1300 // start of new polyline:
1301 newPolyline->addVertex(sol.get(0));
1303 nextIsStraight = true;
1306 // start removing nodes again:
1307 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1308 RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1309 ae->getEndpoint().x, ae->getEndpoint().y);
1310 newPolyline->setNextBulge(0.0);
1311 // start of new polyline:
1312 newPolyline->addVertex(sol.get(0));
1316 // normal node (not deleted):
1317 if (removing==false) {
1318 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1319 ae->getEndpoint().x, ae->getEndpoint().y);
1320 if (nextIsStraight) {
1321 newPolyline->setNextBulge(0.0);
1322 nextIsStraight = false;
1324 newPolyline->setNextBulge(bulge);
1326 newPolyline->addVertex(ae->getEndpoint());
1329 RS_DEBUG->print("RS_Modification::polylineTrim: "
1330 "Polyline contains non-atomic entities",
1331 RS_Debug::D_WARNING);
1336 RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1337 newPolyline->setNextBulge(polyline.getClosingBulge());
1338 newPolyline->endPolyline();
1340 // add new polyline:
1341 RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1342 container->addEntity(newPolyline);
1343 if (graphicView!=NULL) {
1344 graphicView->deleteEntity(&polyline);
1345 graphicView->drawEntity(newPolyline);
1348 RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1349 if (document!=NULL && handleUndo) {
1350 document->startUndoCycle();
1352 polyline.setUndoState(true);
1353 document->addUndoable(&polyline);
1354 document->addUndoable(newPolyline);
1356 document->endUndoCycle();
1364 * Moves all selected entities with the given data for the move
1367 bool RS_Modification::move(RS_MoveData & data)
1369 if (container == NULL)
1371 RS_DEBUG->print("RS_Modification::move: no valid container", RS_Debug::D_WARNING);
1375 // Q3PtrList<RS_Entity> addList;
1376 // addList.setAutoDelete(false);
1377 QList<RS_Entity *> addList;
1379 if (document != NULL && handleUndo)
1380 document->startUndoCycle();
1382 // Create new entites
1383 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1386 //for (uint i=0; i<container->count(); ++i) {
1387 //RS_Entity* e = container->entityAt(i);
1388 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1390 if (e != NULL && e->isSelected())
1392 RS_Entity * ec = e->clone();
1393 ec->move(data.offset * num);
1395 if (data.useCurrentLayer)
1396 ec->setLayerToActive();
1398 if (data.useCurrentAttributes)
1399 ec->setPenToActive();
1401 if (ec->rtti() == RS2::EntityInsert)
1402 ((RS_Insert *)ec)->update();
1404 // since 2.0.4.0: keep selection
1405 ec->setSelected(true);
1411 deselectOriginals(data.number==0);
1412 addNewEntities(addList);
1414 if (document != NULL && handleUndo)
1415 document->endUndoCycle();
1417 if (graphicView != NULL)
1418 graphicView->redraw();
1424 * Rotates all selected entities with the given data for the rotation.
1426 bool RS_Modification::rotate(RS_RotateData & data)
1428 if (container == NULL)
1430 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1431 RS_Debug::D_WARNING);
1435 // Q3PtrList<RS_Entity> addList;
1436 // addList.setAutoDelete(false);
1437 QList<RS_Entity *> addList;
1439 if (document!=NULL && handleUndo)
1440 document->startUndoCycle();
1442 // Create new entites
1443 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1445 for (RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1447 //for (uint i=0; i<container->count(); ++i) {
1448 //RS_Entity* e = container->entityAt(i);
1450 if (e != NULL && e->isSelected())
1452 RS_Entity * ec = e->clone();
1453 ec->setSelected(false);
1454 ec->rotate(data.center, data.angle*num);
1456 if (data.useCurrentLayer)
1457 ec->setLayerToActive();
1459 if (data.useCurrentAttributes)
1460 ec->setPenToActive();
1462 if (ec->rtti() == RS2::EntityInsert)
1463 ((RS_Insert *)ec)->update();
1470 deselectOriginals(data.number == 0);
1471 addNewEntities(addList);
1473 if (document != NULL && handleUndo)
1474 document->endUndoCycle();
1476 if (graphicView != NULL)
1477 graphicView->redraw();
1483 * Moves all selected entities with the given data for the scale
1486 bool RS_Modification::scale(RS_ScaleData & data)
1488 if (container == NULL)
1490 RS_DEBUG->print("RS_Modification::scale: no valid container", RS_Debug::D_WARNING);
1494 // Q3PtrList<RS_Entity> addList;
1495 // addList.setAutoDelete(false);
1496 QList<RS_Entity *> addList;
1498 if (document!=NULL && handleUndo)
1499 document->startUndoCycle();
1501 // Create new entites
1502 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1504 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1506 //for (uint i=0; i<container->count(); ++i) {
1507 //RS_Entity* e = container->entityAt(i);
1508 if (e != NULL && e->isSelected())
1510 RS_Entity * ec = e->clone();
1511 ec->setSelected(false);
1512 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1514 if (data.useCurrentLayer)
1515 ec->setLayerToActive();
1517 if (data.useCurrentAttributes)
1518 ec->setPenToActive();
1520 if (ec->rtti()==RS2::EntityInsert)
1521 ((RS_Insert*)ec)->update();
1528 deselectOriginals(data.number == 0);
1529 addNewEntities(addList);
1531 if (document != NULL && handleUndo)
1532 document->endUndoCycle();
1534 if (graphicView != NULL)
1535 graphicView->redraw();
1541 * Mirror all selected entities with the given data for the mirror
1544 bool RS_Modification::mirror(RS_MirrorData & data)
1546 if (container==NULL) {
1547 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1548 RS_Debug::D_WARNING);
1552 // Q3PtrList<RS_Entity> addList;
1553 // addList.setAutoDelete(false);
1554 QList<RS_Entity *> addList;
1556 if (document!=NULL && handleUndo) {
1557 document->startUndoCycle();
1560 // Create new entites
1562 num<=(int)data.copy || (data.copy==false && num<=1);
1564 for (RS_Entity* e=container->firstEntity();
1566 e=container->nextEntity()) {
1567 //for (uint i=0; i<container->count(); ++i) {
1568 //RS_Entity* e = container->entityAt(i);
1570 if (e!=NULL && e->isSelected()) {
1571 RS_Entity* ec = e->clone();
1572 ec->setSelected(false);
1574 ec->mirror(data.axisPoint1, data.axisPoint2);
1575 if (data.useCurrentLayer) {
1576 ec->setLayerToActive();
1578 if (data.useCurrentAttributes) {
1579 ec->setPenToActive();
1581 if (ec->rtti()==RS2::EntityInsert) {
1582 ((RS_Insert*)ec)->update();
1589 deselectOriginals(data.copy==false);
1590 addNewEntities(addList);
1592 if (document!=NULL && handleUndo) {
1593 document->endUndoCycle();
1596 if (graphicView!=NULL) {
1597 graphicView->redraw();
1603 * Rotates entities around two centers with the given parameters.
1605 bool RS_Modification::rotate2(RS_Rotate2Data & data)
1607 if (container==NULL) {
1608 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1609 RS_Debug::D_WARNING);
1613 // Q3PtrList<RS_Entity> addList;
1614 // addList.setAutoDelete(false);
1615 QList<RS_Entity *> addList;
1617 if (document!=NULL && handleUndo) {
1618 document->startUndoCycle();
1621 // Create new entites
1623 num<=data.number || (data.number==0 && num<=1);
1626 for (RS_Entity* e=container->firstEntity();
1628 e=container->nextEntity()) {
1629 //for (uint i=0; i<container->count(); ++i) {
1630 //RS_Entity* e = container->entityAt(i);
1632 if (e!=NULL && e->isSelected()) {
1633 RS_Entity* ec = e->clone();
1634 ec->setSelected(false);
1636 ec->rotate(data.center1, data.angle1*num);
1637 Vector center2 = data.center2;
1638 center2.rotate(data.center1, data.angle1*num);
1640 ec->rotate(center2, data.angle2*num);
1641 if (data.useCurrentLayer) {
1642 ec->setLayerToActive();
1644 if (data.useCurrentAttributes) {
1645 ec->setPenToActive();
1647 if (ec->rtti()==RS2::EntityInsert) {
1648 ((RS_Insert*)ec)->update();
1655 deselectOriginals(data.number==0);
1656 addNewEntities(addList);
1658 if (document!=NULL && handleUndo) {
1659 document->endUndoCycle();
1662 if (graphicView!=NULL) {
1663 graphicView->redraw();
1669 * Moves and rotates entities with the given parameters.
1671 bool RS_Modification::moveRotate(RS_MoveRotateData & data)
1673 if (container==NULL) {
1674 RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1675 RS_Debug::D_WARNING);
1679 // Q3PtrList<RS_Entity> addList;
1680 // addList.setAutoDelete(false);
1681 QList<RS_Entity *> addList;
1683 if (document!=NULL && handleUndo) {
1684 document->startUndoCycle();
1687 // Create new entites
1689 num<=data.number || (data.number==0 && num<=1);
1691 for (RS_Entity* e=container->firstEntity();
1693 e=container->nextEntity()) {
1694 //for (uint i=0; i<container->count(); ++i) {
1695 //RS_Entity* e = container->entityAt(i);
1697 if (e!=NULL && e->isSelected()) {
1698 RS_Entity* ec = e->clone();
1699 ec->setSelected(false);
1701 ec->move(data.offset*num);
1702 ec->rotate(data.referencePoint + data.offset*num,
1704 if (data.useCurrentLayer) {
1705 ec->setLayerToActive();
1707 if (data.useCurrentAttributes) {
1708 ec->setPenToActive();
1710 if (ec->rtti()==RS2::EntityInsert) {
1711 ((RS_Insert*)ec)->update();
1718 deselectOriginals(data.number==0);
1719 addNewEntities(addList);
1721 if (document!=NULL && handleUndo) {
1722 document->endUndoCycle();
1724 if (graphicView!=NULL) {
1725 graphicView->redraw();
1732 * Deselects all selected entities and removes them if remove is true;
1734 * @param remove true: Remove entites.
1736 void RS_Modification::deselectOriginals(bool remove)
1738 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1740 //for (uint i=0; i<container->count(); ++i) {
1741 //RS_Entity* e = container->entityAt(i);
1745 bool selected = false;
1747 if (e->isAtomic()) {
1748 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1749 if (ae->isStartpointSelected() ||
1750 ae->isEndpointSelected()) {
1757 if (e->isSelected())
1762 e->setSelected(false);
1766 //if (graphicView!=NULL) {
1767 // graphicView->deleteEntity(e);
1769 e->changeUndoState();
1771 if (document != NULL && handleUndo)
1772 document->addUndoable(e);
1776 //if (graphicView!=NULL) {
1777 // graphicView->drawEntity(e);
1786 * Adds the given entities to the container and draws the entities if
1787 * there's a graphic view available.
1789 * @param addList Entities to add.
1791 //void RS_Modification::addNewEntities(Q3PtrList<RS_Entity> & addList)
1792 void RS_Modification::addNewEntities(QList<RS_Entity *> & addList)
1794 // for(RS_Entity * e=addList.first(); e!=NULL; e=addList.next())
1795 for(int i=0; i<addList.size(); i++)
1797 RS_Entity * e = addList[i];
1801 container->addEntity(e);
1803 if (document != NULL && handleUndo)
1804 document->addUndoable(e);
1805 //if (graphicView!=NULL) {
1806 // graphicView->drawEntity(e);
1813 * Trims or extends the given trimEntity to the intersection point of the
1814 * trimEntity and the limitEntity.
1816 * @param trimCoord Coordinate which defines which endpoint of the
1817 * trim entity to trim.
1818 * @param trimEntity Entity which will be trimmed.
1819 * @param limitCoord Coordinate which defines the intersection to which the
1820 * trim entity will be trimmed.
1821 * @param limitEntity Entity to which the trim entity will be trimmed.
1822 * @param both true: Trim both entities. false: trim trimEntity only.
1824 bool RS_Modification::trim(const Vector& trimCoord, RS_AtomicEntity* trimEntity,
1825 const Vector& limitCoord, RS_Entity* limitEntity, bool both)
1827 if (trimEntity==NULL || limitEntity==NULL)
1829 RS_DEBUG->print(RS_Debug::D_WARNING,
1830 "RS_Modification::trim: At least one entity is NULL");
1834 if (both && !limitEntity->isAtomic())
1836 RS_DEBUG->print(RS_Debug::D_WARNING,
1837 "RS_Modification::trim: limitEntity is not atomic");
1840 VectorSolutions sol;
1842 if (limitEntity->isAtomic())
1844 // intersection(s) of the two entities:
1845 sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1846 } else if (limitEntity->isContainer()) {
1847 RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1852 for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1853 e=ec->nextEntity(RS2::ResolveAll)) {
1854 //for (int i=0; i<container->count(); ++i) {
1855 // RS_Entity* e = container->entityAt(i);
1859 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1862 if (s2.hasValid()) {
1863 for (int k=0; k<s2.getNumber(); ++k) {
1864 if (i<128 && s2.get(k).valid) {
1865 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1866 sol.set(i++, s2.get(k));
1876 if (sol.hasValid()==false) {
1880 RS_AtomicEntity* trimmed1 = NULL;
1881 RS_AtomicEntity* trimmed2 = NULL;
1883 // remove trim entity from view:
1884 if (trimEntity->rtti()==RS2::EntityCircle) {
1885 // convert a circle into a trimmable arc
1886 RS_Circle* c = (RS_Circle*)trimEntity;
1887 double am = c->getCenter().angleTo(trimCoord);
1888 RS_ArcData d(c->getCenter(),
1890 RS_Math::correctAngle(am-M_PI/2),
1891 RS_Math::correctAngle(am+M_PI/2), false);
1892 trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1894 trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1895 trimmed1->setHighlighted(false);
1897 if (graphicView!=NULL) {
1898 graphicView->deleteEntity(trimEntity);
1901 // remove limit entity from view:
1903 trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1904 trimmed2->setHighlighted(false);
1905 if (graphicView!=NULL) {
1906 graphicView->deleteEntity(limitEntity);
1912 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1913 //sol.getClosest(limitCoord, NULL, &ind);
1914 RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1915 RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1916 RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1917 RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1918 Vector is2 = sol.get(ind==0 ? 1 : 0);
1919 //Vector is2 = sol.get(ind);
1920 RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1922 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1923 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1926 case RS2::EndingStart:
1927 trimmed1->trimStartpoint(is);
1928 if (trimEntity->rtti()==RS2::EntityCircle) {
1929 trimmed1->trimEndpoint(is2);
1932 case RS2::EndingEnd:
1933 trimmed1->trimEndpoint(is);
1934 if (trimEntity->rtti()==RS2::EntityCircle) {
1935 trimmed1->trimStartpoint(is2);
1942 // trim limit entity:
1944 Vector is = sol.getClosest(limitCoord);
1946 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1949 case RS2::EndingStart:
1950 trimmed2->trimStartpoint(is);
1952 case RS2::EndingEnd:
1953 trimmed2->trimEndpoint(is);
1960 // add new trimmed trim entity:
1961 container->addEntity(trimmed1);
1962 if (graphicView!=NULL) {
1963 graphicView->drawEntity(trimmed1);
1966 // add new trimmed limit entity:
1968 container->addEntity(trimmed2);
1969 if (graphicView!=NULL) {
1970 graphicView->drawEntity(trimmed2);
1974 if (document!=NULL && handleUndo) {
1975 document->startUndoCycle();
1976 document->addUndoable(trimmed1);
1977 trimEntity->setUndoState(true);
1978 document->addUndoable(trimEntity);
1980 document->addUndoable(trimmed2);
1981 limitEntity->setUndoState(true);
1982 document->addUndoable(limitEntity);
1984 document->endUndoCycle();
1993 * Trims or extends the given trimEntity by the given amount.
1995 * @param trimCoord Coordinate which defines which endpoint of the
1996 * trim entity to trim.
1997 * @param trimEntity Entity which will be trimmed.
1998 * @param dist Amount to trim by.
2000 bool RS_Modification::trimAmount(const Vector& trimCoord,
2001 RS_AtomicEntity* trimEntity,
2004 if (trimEntity==NULL) {
2005 RS_DEBUG->print(RS_Debug::D_WARNING,
2006 "RS_Modification::trimAmount: Entity is NULL");
2010 RS_AtomicEntity* trimmed = NULL;
2012 // remove trim entity:
2013 trimmed = (RS_AtomicEntity*)trimEntity->clone();
2014 if (graphicView!=NULL) {
2015 graphicView->deleteEntity(trimEntity);
2019 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2020 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2021 trimCoord.distanceTo(trimmed->getEndpoint())) {
2022 trimmed->trimStartpoint(is);
2024 trimmed->trimEndpoint(is);
2027 // add new trimmed trim entity:
2028 container->addEntity(trimmed);
2030 if (graphicView!=NULL) {
2031 graphicView->drawEntity(trimmed);
2034 if (document!=NULL && handleUndo) {
2035 document->startUndoCycle();
2036 document->addUndoable(trimmed);
2037 trimEntity->setUndoState(true);
2038 document->addUndoable(trimEntity);
2039 document->endUndoCycle();
2048 * Cuts the given entity at the given point.
2050 bool RS_Modification::cut(const Vector& cutCoord,
2051 RS_AtomicEntity* cutEntity) {
2053 if (cutEntity==NULL) {
2054 RS_DEBUG->print(RS_Debug::D_WARNING,
2055 "RS_Modification::cut: Entity is NULL");
2059 if (!cutCoord.valid) {
2060 RS_DEBUG->print(RS_Debug::D_WARNING,
2061 "RS_Modification::cut: Point invalid.");
2065 // cut point is at endpoint of entity:
2066 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2067 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2068 RS_DEBUG->print(RS_Debug::D_WARNING,
2069 "RS_Modification::cut: Cutting point on endpoint");
2073 // delete cut entity on the screen:
2074 if (graphicView!=NULL) {
2075 graphicView->deleteEntity(cutEntity);
2078 RS_AtomicEntity* cut1 = NULL;
2079 RS_AtomicEntity* cut2 = NULL;
2081 // create new two halves:
2082 if (cutEntity->rtti()==RS2::EntityCircle) {
2083 RS_Circle* c = (RS_Circle*)cutEntity;
2084 cut1 = new RS_Arc(cutEntity->getParent(),
2085 RS_ArcData(c->getCenter(),
2088 cut1->setPen(cutEntity->getPen());
2089 cut1->setLayer(cutEntity->getLayer());
2092 cut1->trimEndpoint(cutCoord);
2093 cut1->trimStartpoint(cutCoord);
2095 cut1 = (RS_AtomicEntity*)cutEntity->clone();
2096 cut2 = (RS_AtomicEntity*)cutEntity->clone();
2098 cut1->trimEndpoint(cutCoord);
2099 cut2->trimStartpoint(cutCoord);
2102 // add new cut entity:
2103 container->addEntity(cut1);
2105 container->addEntity(cut2);
2108 if (graphicView!=NULL) {
2109 graphicView->drawEntity(cut1);
2111 graphicView->drawEntity(cut2);
2115 if (document!=NULL && handleUndo) {
2116 document->startUndoCycle();
2117 document->addUndoable(cut1);
2119 document->addUndoable(cut2);
2121 cutEntity->setUndoState(true);
2122 document->addUndoable(cutEntity);
2123 document->endUndoCycle();
2132 bool RS_Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2133 const Vector& offset)
2137 RS_DEBUG->print(RS_Debug::D_WARNING,
2138 "RS_Modification::stretch: Offset invalid");
2142 // Q3PtrList<RS_Entity> addList;
2143 // addList.setAutoDelete(false);
2144 QList<RS_Entity *> addList;
2146 if (document!=NULL && handleUndo) {
2147 document->startUndoCycle();
2150 // Create new entites
2151 for (RS_Entity* e=container->firstEntity();
2153 e=container->nextEntity()) {
2154 //for (int i=0; i<container->count(); ++i) {
2155 // RS_Entity* e = container->entityAt(i);
2160 (e->isInWindow(firstCorner, secondCorner) ||
2161 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2163 RS_Entity* ec = e->clone();
2164 ec->stretch(firstCorner, secondCorner, offset);
2166 e->setSelected(true);
2170 deselectOriginals(true);
2171 addNewEntities(addList);
2173 if (document!=NULL && handleUndo) {
2174 document->endUndoCycle();
2177 if (graphicView!=NULL) {
2178 graphicView->redraw();
2188 * @param coord1 Mouse coordinate to specify direction from intersection.
2189 * @param entity1 First entity of the corner.
2190 * @param coord2 Mouse coordinate to specify direction from intersection.
2191 * @param entity2 Second entity of the corner.
2192 * @param data Lengths and trim flag.
2194 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2195 const Vector& coord2, RS_AtomicEntity* entity2,
2196 RS_BevelData& data) {
2198 RS_DEBUG->print("RS_Modification::bevel");
2200 if (entity1==NULL || entity2==NULL) {
2201 RS_DEBUG->print(RS_Debug::D_WARNING,
2202 "RS_Modification::bevel: At least one entity is NULL");
2206 RS_EntityContainer* baseContainer = container;
2207 bool isPolyline = false;
2208 bool isClosedPolyline = false;
2210 if (document!=NULL && handleUndo) {
2211 document->startUndoCycle();
2214 // find out whether we're bevelling within a polyline:
2215 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2216 RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2217 if (entity1->getParent()!=entity2->getParent()) {
2218 RS_DEBUG->print(RS_Debug::D_WARNING,
2219 "RS_Modification::bevel: entities not in the same polyline");
2222 // clone polyline for undo
2223 if (document!=NULL && handleUndo) {
2224 RS_EntityContainer* cl =
2225 (RS_EntityContainer*)entity1->getParent()->clone();
2226 container->addEntity(cl);
2227 //cl->setUndoState(true);
2228 document->addUndoable(cl);
2230 document->addUndoable(entity1->getParent());
2231 entity1->getParent()->setUndoState(true);
2236 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2237 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2239 //baseContainer = entity1->getParent();
2241 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2244 RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2246 VectorSolutions sol =
2247 RS_Information::getIntersection(entity1, entity2, false);
2249 if (sol.getNumber()==0) {
2253 RS_AtomicEntity* trimmed1 = NULL;
2254 RS_AtomicEntity* trimmed2 = NULL;
2256 //if (data.trim || isPolyline) {
2261 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2262 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2265 // remove trim entity (on screen):
2266 if (data.trim==true || isPolyline) {
2267 if (graphicView!=NULL) {
2269 graphicView->deleteEntity(baseContainer);
2271 graphicView->deleteEntity(entity1);
2272 graphicView->deleteEntity(entity2);
2277 // trim entities to intersection
2278 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2279 bool start1 = false;
2280 Vector is = sol.getClosest(coord2);
2281 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2283 case RS2::EndingStart:
2284 trimmed1->trimStartpoint(is);
2287 case RS2::EndingEnd:
2288 trimmed1->trimEndpoint(is);
2295 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2296 bool start2 = false;
2297 is = sol.getClosest(coord1);
2298 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2300 case RS2::EndingStart:
2301 trimmed2->trimStartpoint(is);
2304 case RS2::EndingEnd:
2305 trimmed2->trimEndpoint(is);
2314 // find definitive bevel points
2315 RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2316 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2317 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2320 RS_DEBUG->print("RS_Modification::bevel: final trim");
2321 if (data.trim==true) {
2323 case RS2::EndingStart:
2324 trimmed1->trimStartpoint(bp1);
2326 case RS2::EndingEnd:
2327 trimmed1->trimEndpoint(bp1);
2334 case RS2::EndingStart:
2335 trimmed2->trimStartpoint(bp2);
2337 case RS2::EndingEnd:
2338 trimmed2->trimEndpoint(bp2);
2344 // add new trimmed entities:
2345 if (isPolyline==false) {
2346 container->addEntity(trimmed1);
2347 container->addEntity(trimmed2);
2349 if (graphicView!=NULL) {
2351 graphicView->drawEntity(trimmed1);
2352 graphicView->drawEntity(trimmed2);
2359 RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2360 RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2362 if (isPolyline==false) {
2363 baseContainer->addEntity(bevel);
2365 int idx1 = baseContainer->findEntity(trimmed1);
2366 int idx2 = baseContainer->findEntity(trimmed2);
2368 bevel->setSelected(baseContainer->isSelected());
2369 bevel->setLayer(baseContainer->getLayer());
2370 bevel->setPen(baseContainer->getPen());
2372 bool insertAfter1 = false;
2373 if (!isClosedPolyline) {
2374 insertAfter1 = (idx1<idx2);
2377 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2378 (idx2==0 && idx1==(int)baseContainer->count()-1));
2381 // insert bevel at the right position:
2382 //if ((idx1<idx2 && idx1!=0) ||
2383 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2385 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2388 baseContainer->insertEntity(idx1+1, bevel);
2390 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2393 baseContainer->insertEntity(idx2+1, bevel);
2398 ((RS_Polyline*)baseContainer)->updateEndpoints();
2401 if (graphicView!=NULL) {
2403 graphicView->drawEntity(baseContainer);
2405 graphicView->drawEntity(bevel);
2409 RS_DEBUG->print("RS_Modification::bevel: handling undo");
2411 if (document!=NULL && handleUndo) {
2412 //document->startUndoCycle();
2414 if (isPolyline==false && data.trim==true) {
2415 document->addUndoable(trimmed1);
2416 entity1->setUndoState(true);
2417 document->addUndoable(entity1);
2419 document->addUndoable(trimmed2);
2420 entity2->setUndoState(true);
2421 document->addUndoable(entity2);
2424 if (isPolyline==false) {
2425 document->addUndoable(bevel);
2428 document->endUndoCycle();
2431 if (data.trim==false) {
2432 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2435 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2447 * @param coord Mouse coordinate to specify the rounding.
2448 * @param entity1 First entity of the corner.
2449 * @param entity2 Second entity of the corner.
2450 * @param data Radius and trim flag.
2452 bool RS_Modification::round(const Vector& coord,
2453 const Vector& coord1,
2454 RS_AtomicEntity* entity1,
2455 const Vector& coord2,
2456 RS_AtomicEntity* entity2,
2457 RS_RoundData& data) {
2459 if (entity1==NULL || entity2==NULL) {
2460 RS_DEBUG->print(RS_Debug::D_WARNING,
2461 "RS_Modification::round: At least one entity is NULL");
2465 RS_EntityContainer* baseContainer = container;
2466 bool isPolyline = false;
2467 bool isClosedPolyline = false;
2469 if (document!=NULL && handleUndo) {
2470 document->startUndoCycle();
2473 // find out whether we're rounding within a polyline:
2474 if (entity1->getParent()!=NULL &&
2475 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2477 if (entity1->getParent()!=entity2->getParent()) {
2478 RS_DEBUG->print(RS_Debug::D_WARNING,
2479 "RS_Modification::round: entities not in "
2480 "the same polyline");
2481 if (document!=NULL && handleUndo) {
2482 document->endUndoCycle();
2487 // clone polyline for undo
2488 if (document!=NULL && handleUndo) {
2489 RS_EntityContainer* cl =
2490 (RS_EntityContainer*)entity1->getParent()->clone();
2491 container->addEntity(cl);
2492 document->addUndoable(cl);
2494 document->addUndoable(entity1->getParent());
2495 entity1->getParent()->setUndoState(true);
2500 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2501 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2504 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2507 // create 2 tmp parallels
2508 RS_Creation creation(NULL, NULL);
2509 RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2510 RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2512 VectorSolutions sol2 =
2513 RS_Information::getIntersection(entity1, entity2, false);
2515 VectorSolutions sol =
2516 RS_Information::getIntersection(par1, par2, false);
2518 if (sol.getNumber()==0) {
2519 if (document!=NULL && handleUndo) {
2520 document->endUndoCycle();
2525 // there might be two intersections: choose the closest:
2526 Vector is = sol.getClosest(coord);
2527 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2528 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2529 double ang1 = is.angleTo(p1);
2530 double ang2 = is.angleTo(p2);
2531 bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2533 RS_Arc* arc = new RS_Arc(baseContainer,
2540 RS_AtomicEntity* trimmed1 = NULL;
2541 RS_AtomicEntity* trimmed2 = NULL;
2543 if (data.trim || isPolyline) {
2548 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2549 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2552 // remove trim entity:
2553 if (graphicView!=NULL) {
2555 graphicView->deleteEntity(baseContainer);
2557 graphicView->deleteEntity(entity1);
2558 graphicView->deleteEntity(entity2);
2562 // trim entities to intersection
2563 Vector is2 = sol2.getClosest(coord2);
2564 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2566 case RS2::EndingStart:
2567 trimmed1->trimStartpoint(p1);
2569 case RS2::EndingEnd:
2570 trimmed1->trimEndpoint(p1);
2576 is2 = sol2.getClosest(coord1);
2577 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2579 case RS2::EndingStart:
2580 trimmed2->trimStartpoint(p2);
2582 case RS2::EndingEnd:
2583 trimmed2->trimEndpoint(p2);
2589 // add new trimmed entities:
2590 if (isPolyline==false) {
2591 container->addEntity(trimmed1);
2592 container->addEntity(trimmed2);
2594 if (graphicView!=NULL) {
2596 graphicView->drawEntity(trimmed1);
2597 graphicView->drawEntity(trimmed2);
2603 if (isPolyline==false) {
2604 baseContainer->addEntity(arc);
2606 // find out which base entity is before the rounding:
2607 int idx1 = baseContainer->findEntity(trimmed1);
2608 int idx2 = baseContainer->findEntity(trimmed2);
2610 arc->setSelected(baseContainer->isSelected());
2611 arc->setLayer(baseContainer->getLayer());
2612 arc->setPen(baseContainer->getPen());
2614 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2615 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2616 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2617 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2618 (int)(idx1==(int)baseContainer->count()-1));
2620 bool insertAfter1 = false;
2621 if (!isClosedPolyline) {
2622 insertAfter1 = (idx1<idx2);
2625 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2626 (idx2==0 && idx1==(int)baseContainer->count()-1));
2629 // insert rounding at the right position:
2630 //if ((idx1<idx2 && idx1!=0) ||
2631 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2634 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2637 baseContainer->insertEntity(idx1+1, arc);
2639 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2642 baseContainer->insertEntity(idx2+1, arc);
2647 ((RS_Polyline*)baseContainer)->updateEndpoints();
2650 if (graphicView!=NULL) {
2652 graphicView->drawEntity(baseContainer);
2654 graphicView->drawEntity(arc);
2658 if (document!=NULL && handleUndo) {
2659 if (isPolyline==false && data.trim==true) {
2660 document->addUndoable(trimmed1);
2661 entity1->setUndoState(true);
2662 document->addUndoable(entity1);
2664 document->addUndoable(trimmed2);
2665 entity2->setUndoState(true);
2666 document->addUndoable(entity2);
2669 if (isPolyline==false) {
2670 document->addUndoable(arc);
2673 document->endUndoCycle();
2683 * Removes the selected entity containers and adds the entities in them as
2684 * new single entities.
2686 bool RS_Modification::explode()
2688 if (container == NULL)
2690 RS_DEBUG->print("RS_Modification::explode: no valid container for addinge entities",
2691 RS_Debug::D_WARNING);
2695 // Q3PtrList<RS_Entity> addList;
2696 // addList.setAutoDelete(false);
2697 QList<RS_Entity *> addList;
2699 if (document!=NULL && handleUndo) {
2700 document->startUndoCycle();
2703 for (RS_Entity* e=container->firstEntity();
2705 e=container->nextEntity()) {
2706 //for (uint i=0; i<container->count(); ++i) {
2707 //RS_Entity* e = container->entityAt(i);
2709 if (e!=NULL && e->isSelected()) {
2710 if (e->isContainer()) {
2712 // add entities from container:
2713 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2714 //ec->setSelected(false);
2716 // iterate and explode container:
2717 //for (uint i2=0; i2<ec->count(); ++i2) {
2718 // RS_Entity* e2 = ec->entityAt(i2);
2719 RS2::ResolveLevel rl;
2723 switch (ec->rtti()) {
2724 case RS2::EntityText:
2725 case RS2::EntityHatch:
2726 case RS2::EntityPolyline:
2727 rl = RS2::ResolveAll;
2728 resolveLayer = true;
2732 case RS2::EntityInsert:
2734 resolveLayer = false;
2735 rl = RS2::ResolveNone;
2738 case RS2::EntityDimAligned:
2739 case RS2::EntityDimLinear:
2740 case RS2::EntityDimRadial:
2741 case RS2::EntityDimDiametric:
2742 case RS2::EntityDimAngular:
2743 case RS2::EntityDimLeader:
2744 rl = RS2::ResolveNone;
2745 resolveLayer = true;
2750 rl = RS2::ResolveAll;
2751 resolveLayer = true;
2756 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2757 e2 = ec->nextEntity(rl)) {
2760 RS_Entity* clone = e2->clone();
2761 clone->setSelected(false);
2762 clone->reparent(container);
2765 clone->setLayer(ec->getLayer());
2767 clone->setLayer(e2->getLayer());
2770 clone->setPen(ec->getPen(resolvePen));
2772 addList.append(clone);
2778 e->setSelected(false);
2783 deselectOriginals(true);
2784 addNewEntities(addList);
2786 if (document!=NULL && handleUndo) {
2787 document->endUndoCycle();
2790 if (graphicView!=NULL) {
2791 graphicView->redraw();
2797 bool RS_Modification::explodeTextIntoLetters()
2799 if (container == NULL)
2801 RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2802 " for addinge entities", RS_Debug::D_WARNING);
2806 // Q3PtrList<RS_Entity> addList;
2807 // addList.setAutoDelete(false);
2808 QList<RS_Entity *> addList;
2810 if (document!=NULL && handleUndo) {
2811 document->startUndoCycle();
2814 for (RS_Entity* e=container->firstEntity();
2816 e=container->nextEntity()) {
2817 if (e!=NULL && e->isSelected()) {
2818 if (e->rtti()==RS2::EntityText) {
2819 // add letters of text:
2820 RS_Text* text = (RS_Text*)e;
2821 explodeTextIntoLetters(text, addList);
2823 e->setSelected(false);
2828 deselectOriginals(true);
2829 addNewEntities(addList);
2831 if (document!=NULL && handleUndo) {
2832 document->endUndoCycle();
2835 if (graphicView!=NULL) {
2836 graphicView->redraw();
2842 //bool RS_Modification::explodeTextIntoLetters(RS_Text* text, Q3PtrList<RS_Entity>& addList)
2843 bool RS_Modification::explodeTextIntoLetters(RS_Text * text, QList<RS_Entity *> & addList)
2848 // iterate though lines:
2849 for(RS_Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2855 if (e2->rtti() == RS2::EntityContainer)
2857 RS_EntityContainer * line = (RS_EntityContainer *)e2;
2859 // iterate though letters:
2860 for(RS_Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2865 // super / sub texts:
2866 if (e3->rtti() == RS2::EntityText)
2867 explodeTextIntoLetters((RS_Text *)e3, addList);
2869 else if (e3->rtti() == RS2::EntityInsert)
2871 RS_Insert * letter = (RS_Insert *)e3;
2873 RS_Text * tl = new RS_Text(container, RS_TextData(letter->getInsertionPoint(),
2874 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2875 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2876 letter->getAngle(), RS2::Update));
2878 tl->setLayer(text->getLayer());
2879 tl->setPen(text->getPen());
2892 * Moves all reference points of selected entities with the given data.
2894 bool RS_Modification::moveRef(RS_MoveRefData& data)
2896 if (container == NULL)
2898 RS_DEBUG->print("RS_Modification::moveRef: no valid container", RS_Debug::D_WARNING);
2902 // Q3PtrList<RS_Entity> addList;
2903 // addList.setAutoDelete(false);
2904 QList<RS_Entity *> addList;
2906 if (document != NULL && handleUndo)
2907 document->startUndoCycle();
2909 // Create new entites
2910 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2912 if (e != NULL && e->isSelected())
2914 RS_Entity * ec = e->clone();
2915 ec->moveRef(data.ref, data.offset);
2916 // since 2.0.4.0: keep it selected
2917 ec->setSelected(true);
2922 deselectOriginals(true);
2923 addNewEntities(addList);
2925 if (document != NULL && handleUndo)
2926 document->endUndoCycle();
2928 if (graphicView != NULL)
2929 graphicView->redraw();