3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/01/2010 Added this text. :-)
17 #include "rs_modification.h"
19 #include "rs_clipboard.h"
20 #include "rs_creation.h"
21 #include "rs_entity.h"
23 #include "rs_information.h"
24 #include "rs_insert.h"
25 #include "rs_polyline.h"
30 * Default constructor.
32 * @param container The container to which we will add
33 * entities. Usually that's an Drawing entity but
34 * it can also be a polyline, text, ...
35 * @param graphicView Pointer to graphic view or NULL if you don't want the
36 * any views to be updated.
37 * @param handleUndo true: Handle undo functionalitiy.
39 RS_Modification::RS_Modification(RS_EntityContainer & container,
40 GraphicView * graphicView, bool handleUndo)
42 this->container = &container;
43 this->graphicView = graphicView;
44 this->handleUndo = handleUndo;
45 graphic = container.getGraphic();
46 document = container.getDocument();
50 * Deletes all selected entities.
52 void RS_Modification::remove()
54 if (container == NULL)
56 RS_DEBUG->print("RS_Modification::remove: no valid container", RS_Debug::D_WARNING);
61 document->startUndoCycle();
64 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
66 if (e != NULL && e->isSelected())
68 e->setSelected(false);
72 document->addUndoable(e);
77 document->endUndoCycle();
79 graphicView->redraw();
83 * Changes the attributes of all selected
85 bool RS_Modification::changeAttributes(RS_AttributesData & data)
87 if (container == NULL)
89 RS_DEBUG->print("RS_Modification::changeAttributes: no valid container", RS_Debug::D_WARNING);
93 // Q3PtrList<RS_Entity> addList;
94 // addList.setAutoDelete(false);
95 QList<RS_Entity *> addList;
98 document->startUndoCycle();
100 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
102 //for (uint i=0; i<container->count(); ++i) {
103 //RS_Entity* e = container->entityAt(i);
104 if (e != NULL && e->isSelected())
106 RS_Entity * ec = e->clone();
107 ec->setSelected(false);
109 RS_Pen pen = ec->getPen(false);
111 if (data.changeLayer == true)
112 ec->setLayer(data.layer);
114 if (data.changeColor == true)
115 pen.setColor(data.pen.getColor());
117 if (data.changeLineType == true)
118 pen.setLineType(data.pen.getLineType());
120 if (data.changeWidth == true)
121 pen.setWidth(data.pen.getWidth());
125 //if (data.useCurrentLayer) {
126 // ec->setLayerToActive();
128 //if (data.useCurrentAttributes) {
129 // ec->setPenToActive();
131 //if (ec->rtti()==RS2::EntityInsert) {
132 // ((RS_Insert*)ec)->update();
139 deselectOriginals(true);
140 addNewEntities(addList);
142 if (document != NULL)
143 document->endUndoCycle();
145 if (graphicView != NULL)
146 graphicView->redraw();
153 * Copies all selected entities from the given container to the clipboard.
154 * Layers and blocks that are needed are also copied if the container is
155 * or is part of an Drawing.
157 * @param container The entity container.
158 * @param ref Reference point. The entities will be moved by -ref.
159 * @param cut true: cut instead of copying, false: copy
161 void RS_Modification::copy(const Vector& ref, const bool cut) {
163 if (container==NULL) {
164 RS_DEBUG->print("RS_Modification::copy: no valid container",
165 RS_Debug::D_WARNING);
169 RS_CLIPBOARD->clear();
171 RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
173 RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
176 // start undo cycle for the container if we're cutting
177 if (cut && document!=NULL) {
178 document->startUndoCycle();
181 // copy entities / layers / blocks
182 for (RS_Entity* e=container->firstEntity(); e!=NULL;
183 e=container->nextEntity()) {
184 //for (uint i=0; i<container->count(); ++i) {
185 //RS_Entity* e = container->entityAt(i);
187 if (e!=NULL && e->isSelected()) {
188 copyEntity(e, ref, cut);
192 if (cut && document!=NULL) {
193 document->endUndoCycle();
200 * Copies the given entity from the given container to the clipboard.
201 * Layers and blocks that are needed are also copied if the container is
202 * or is part of an Drawing.
204 * @param e The entity.
205 * @param ref Reference point. The entities will be moved by -ref.
206 * @param cut true: cut instead of copying, false: copy
208 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
211 if (e!=NULL && e->isSelected()) {
212 // delete entity in graphic view:
214 if (graphicView!=NULL) {
215 graphicView->deleteEntity(e);
217 e->setSelected(false);
219 if (graphicView!=NULL) {
220 graphicView->deleteEntity(e);
222 e->setSelected(false);
223 if (graphicView!=NULL) {
224 graphicView->drawEntity(e);
228 // add entity to clipboard:
229 RS_Entity* c = e->clone();
231 RS_CLIPBOARD->addEntity(c);
236 // set layer to the layer clone:
237 RS_Layer* l = e->getLayer();
239 c->setLayer(l->getName());
242 // make sure all sub entities point to layers of the clipboard
243 if (c->isContainer()) {
244 RS_EntityContainer* ec = (RS_EntityContainer*)c;
246 for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
247 e2 = ec->nextEntity(RS2::ResolveAll)) {
249 //RS_Entity* e2 = ec->entityAt(i);
250 RS_Layer* l2 = e2->getLayer();
253 e2->setLayer(l2->getName());
259 e->changeUndoState();
260 if (document!=NULL) {
261 document->addUndoable(e);
271 * Copies all layers of the given entity to the clipboard.
273 void RS_Modification::copyLayers(RS_Entity* e) {
279 // add layer(s) of the entity if it's not an insert
280 // (inserts are on layer '0'):
281 if (e->rtti()!=RS2::EntityInsert) {
282 RS_Layer* l = e->getLayer();
284 if (!RS_CLIPBOARD->hasLayer(l->getName())) {
285 RS_CLIPBOARD->addLayer(l->clone());
290 // special handling of inserts:
292 // insert: add layer(s) of subentities:
293 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
295 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
296 e2=b->nextEntity()) {
297 //for (uint i=0; i<b->count(); ++i) {
298 //RS_Entity* e2 = b->entityAt(i);
308 * Copies all blocks of the given entity to the clipboard.
310 void RS_Modification::copyBlocks(RS_Entity* e) {
316 // add block of the entity if it's an insert
317 if (e->rtti()==RS2::EntityInsert) {
318 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
320 // add block of an insert:
321 if (!RS_CLIPBOARD->hasBlock(b->getName())) {
322 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
325 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
326 e2=b->nextEntity()) {
327 //for (uint i=0; i<b->count(); ++i) {
328 //RS_Entity* e2 = b->entityAt(i);
338 * Pastes all entities from the clipboard into the container.
339 * Layers and blocks that are needed are also copied if the container is
340 * or is part of an Drawing.
342 * @param data Paste data.
343 * @param source The source from where to paste. NULL means the source
346 void RS_Modification::paste(const RS_PasteData& data, Drawing* source) {
349 RS_DEBUG->print(RS_Debug::D_WARNING,
350 "RS_Modification::paste: Graphic is NULL");
357 source = RS_CLIPBOARD->getGraphic();
359 // graphics from the clipboard need to be scaled. from the part lib not:
360 RS2::Unit sourceUnit = source->getUnit();
361 RS2::Unit targetUnit = graphic->getUnit();
362 factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
365 if (document!=NULL) {
366 document->startUndoCycle();
372 RS_Layer* layer = graphic->getActiveLayer();
373 for(uint i=0; i<source->countLayers(); ++i) {
374 RS_Layer* l = source->layerAt(i);
376 if (graphic->findLayer(l->getName())==NULL) {
377 graphic->addLayer(l->clone());
381 graphic->activateLayer(layer);
386 for(uint i=0; i<source->countBlocks(); ++i) {
387 RS_Block* b = source->blockAt(i);
389 if (graphic->findBlock(b->getName())==NULL) {
390 RS_Block* bc = (RS_Block*)b->clone();
391 bc->reparent(container);
392 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
393 // scale block but don't scale inserts in block
394 // (they already scale with their block)
395 for(uint i2=0; i2<bc->count(); ++i2) {
396 RS_Entity* e = bc->entityAt(i2);
397 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
398 e->scale(bc->getBasePoint(),
399 Vector(factor, factor));
401 Vector ip = ((RS_Insert*)e)->getInsertionPoint();
402 ip.scale(bc->getBasePoint(),
403 Vector(factor, factor));
404 ((RS_Insert*)e)->setInsertionPoint(ip);
409 graphic->addBlock(bc);
415 // add entities to this host (graphic or a new block)
416 RS_EntityContainer* host = container;
421 if (data.asInsert==true) {
422 RS_BlockList* blkList = graphic->getBlockList();
424 blockName = blkList->newName(data.blockName);
427 new RS_Block(graphic,
428 RS_BlockData(blockName,
429 Vector(0.0,0.0), false));
430 graphic->addBlock(blk);
438 //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
439 //RS_Entity* e = source->entityAt(i);
440 for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
442 e=((RS_EntityContainer*)source)->nextEntity()) {
446 QString layerName = "0";
447 RS_Layer* layer = e->getLayer();
449 layerName = layer->getName();
451 RS_Entity* e2 = e->clone();
453 if (data.asInsert==false) {
454 e2->move(data.insertionPoint);
456 // don't adjust insert factor - block was already adjusted to unit
457 if (e2->rtti()==RS2::EntityInsert) {
458 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
459 ip.scale(data.insertionPoint, Vector(factor, factor));
460 ((RS_Insert*)e2)->setInsertionPoint(ip);
463 e2->scale(data.insertionPoint, Vector(factor, factor));
466 e2->setLayer(layerName);
468 // make sure all sub entities point to layers of the container
469 if (e2->isContainer()) {
470 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
472 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
473 e3 = ec->nextEntity(RS2::ResolveAll)) {
475 //RS_Entity* e3 = ec->entityAt(i);
476 RS_Layer* l2 = e3->getLayer();
478 e3->setLayer(l2->getName());
483 if (document!=NULL && data.asInsert==false) {
484 document->addUndoable(e2);
489 if (data.asInsert==true) {
491 new RS_Insert(container,
495 Vector(data.factor, data.factor),
497 1,1,Vector(0.0,0.0)));
498 container->addEntity(ins);
499 ins->setLayerToActive();
500 ins->setPenToActive();
502 if (document!=NULL) {
503 document->addUndoable(ins);
507 if (document!=NULL) {
508 document->endUndoCycle();
514 * Splits a polyline into two leaving out a gap.
516 * @param polyline The original polyline
517 * @param e1 1st entity on which the first cutting point is.
518 * @param v1 1st cutting point.
519 * @param e2 2nd entity on which the first cutting point is.
520 * @param v2 2nd cutting point.
521 * @param polyline1 Pointer to a polyline pointer which will hold the
522 * 1st resulting new polyline. Pass NULL if you don't
523 * need those pointers.
524 * @param polyline2 Pointer to a polyline pointer which will hold the
525 * 2nd resulting new polyline. Pass NULL if you don't
526 * need those pointers.
528 * @todo Support arcs in polylines, check for wrong parameters
532 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
533 RS_Entity& e1, Vector v1,
534 RS_Entity& e2, Vector v2,
535 RS_Polyline** polyline1,
536 RS_Polyline** polyline2) const {
538 if (container==NULL) {
539 RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
540 RS_Debug::D_WARNING);
544 RS_Entity* firstEntity = polyline.firstEntity();
545 Vector firstPoint(false);
546 if (firstEntity->rtti()==RS2::EntityLine) {
547 firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
550 new RS_Polyline(container,
551 RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
552 RS_Polyline* pl2 = new RS_Polyline(container);
553 RS_Polyline* pl = pl1; // Current polyline
554 RS_Line* line = NULL;
557 if (polyline1!=NULL) {
560 if (polyline2!=NULL) {
564 for (RS_Entity* e = polyline.firstEntity();
566 e = polyline.nextEntity()) {
568 if (e->rtti()==RS2::EntityLine) {
571 } else if (e->rtti()==RS2::EntityArc) {
579 if (line!=NULL /*|| arc!=NULL*/) {
581 if (e==&e1 && e==&e2) {
582 // Trim within a single entity:
583 Vector sp = line->getStartpoint();
584 double dist1 = (v1-sp).magnitude();
585 double dist2 = (v2-sp).magnitude();
586 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
588 pl->setStartpoint(dist1<dist2 ? v2 : v1);
589 pl->addVertex(line->getEndpoint(), 0.0);
590 } else if (e==&e1 || e==&e2) {
592 Vector v = (e==&e1 ? v1 : v2);
594 // Trim endpoint of entity to first vector
595 pl->addVertex(v, 0.0);
598 // Trim startpoint of entity to second vector
600 pl->setStartpoint(v);
601 pl->addVertex(line->getEndpoint(), 0.0);
604 // Add entities to polylines
605 if (line!=NULL && pl!=NULL) {
606 pl->addVertex(line->getEndpoint(), 0.0);
612 container->addEntity(pl1);
613 container->addEntity(pl2);
614 //container->removeEntity(&polyline);
615 polyline.changeUndoState();
623 * Adds a node to the given polyline. The new node is placed between
624 * the start and end point of the given segment.
626 * @param node The position of the new node.
628 * @return Pointer to the new polyline or NULL.
631 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
632 const RS_AtomicEntity& segment,
633 const Vector& node) {
634 RS_DEBUG->print("RS_Modification::addPolylineNode");
636 if (container==NULL) {
637 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
638 RS_Debug::D_WARNING);
642 if (segment.getParent()!=&polyline) {
643 RS_DEBUG->print("RS_Modification::addPolylineNode: "
644 "segment not part of the polyline",
645 RS_Debug::D_WARNING);
649 RS_Polyline* newPolyline = new RS_Polyline(container);
650 newPolyline->setClosed(polyline.isClosed());
651 newPolyline->setSelected(polyline.isSelected());
652 newPolyline->setLayer(polyline.getLayer());
653 newPolyline->setPen(polyline.getPen());
655 // copy polyline and add new node:
657 RS_Entity* lastEntity = polyline.lastEntity();
658 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
659 e=polyline.nextEntity()) {
662 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
664 if (ae->rtti()==RS2::EntityArc) {
665 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
666 bulge = ((RS_Arc*)ae)->getBulge();
668 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
673 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
674 ae->getStartpoint().x, ae->getStartpoint().y);
676 newPolyline->setNextBulge(bulge);
677 newPolyline->addVertex(ae->getStartpoint());
683 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
685 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
688 newPolyline->setNextBulge(0.0);
689 newPolyline->addVertex(node);
691 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
692 ae->getEndpoint().x, ae->getEndpoint().y);
694 if (ae!=lastEntity || polyline.isClosed()==false) {
695 newPolyline->setNextBulge(0.0);
696 newPolyline->addVertex(ae->getEndpoint());
699 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
700 ae->getEndpoint().x, ae->getEndpoint().y);
702 if (ae!=lastEntity || polyline.isClosed()==false) {
703 newPolyline->setNextBulge(bulge);
704 newPolyline->addVertex(ae->getEndpoint());
708 RS_DEBUG->print("RS_Modification::addPolylineNode: "
709 "Polyline contains non-atomic entities",
710 RS_Debug::D_WARNING);
714 newPolyline->setNextBulge(polyline.getClosingBulge());
715 newPolyline->endPolyline();
718 container->addEntity(newPolyline);
719 if (graphicView!=NULL) {
720 graphicView->deleteEntity(&polyline);
721 graphicView->drawEntity(newPolyline);
724 if (document!=NULL && handleUndo) {
725 document->startUndoCycle();
727 polyline.setUndoState(true);
728 document->addUndoable(&polyline);
729 document->addUndoable(newPolyline);
731 document->endUndoCycle();
741 * Deletes a node from a polyline.
743 * @param node The node to delete.
745 * @return Pointer to the new polyline or NULL.
748 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
749 const Vector& node) {
751 RS_DEBUG->print("RS_Modification::deletePolylineNode");
753 if (container==NULL) {
754 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
755 RS_Debug::D_WARNING);
759 if (node.valid==false) {
760 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
762 RS_Debug::D_WARNING);
766 // check if the polyline is no longer there after deleting the node:
767 if (polyline.count()==1) {
768 RS_Entity* e = polyline.firstEntity();
769 if (e!=NULL && e->isAtomic()) {
770 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
771 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
772 node.distanceTo(ae->getEndpoint())<1.0e-6) {
774 if (graphicView!=NULL) {
775 graphicView->deleteEntity(&polyline);
778 if (document!=NULL && handleUndo) {
779 document->startUndoCycle();
780 polyline.setUndoState(true);
781 document->addUndoable(&polyline);
782 document->endUndoCycle();
789 RS_Polyline* newPolyline = new RS_Polyline(container);
790 newPolyline->setClosed(polyline.isClosed());
791 newPolyline->setSelected(polyline.isSelected());
792 newPolyline->setLayer(polyline.getLayer());
793 newPolyline->setPen(polyline.getPen());
795 // copy polyline and drop deleted node:
797 bool lastDropped = false;
798 RS_Entity* lastEntity = polyline.lastEntity();
799 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
800 e=polyline.nextEntity()) {
803 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
805 if (ae->rtti()==RS2::EntityArc) {
806 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
807 bulge = ((RS_Arc*)ae)->getBulge();
809 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
813 // last entity is closing entity and will be added below with endPolyline()
814 if (e==lastEntity && polyline.isClosed()) {
818 // first vertex (startpoint)
819 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
820 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
821 ae->getStartpoint().x, ae->getStartpoint().y);
823 newPolyline->setNextBulge(bulge);
824 newPolyline->addVertex(ae->getStartpoint());
828 // normal node (not deleted):
829 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
830 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
831 ae->getEndpoint().x, ae->getEndpoint().y);
835 newPolyline->setNextBulge(bulge);
836 newPolyline->addVertex(ae->getEndpoint());
840 // drop deleted node:
842 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
843 ae->getEndpoint().x, ae->getEndpoint().y);
847 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
848 "Polyline contains non-atomic entities",
849 RS_Debug::D_WARNING);
853 RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
854 newPolyline->setNextBulge(polyline.getClosingBulge());
855 newPolyline->endPolyline();
857 //if (newPolyline->count()==1) {
861 RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
862 container->addEntity(newPolyline);
863 if (graphicView!=NULL) {
864 graphicView->deleteEntity(&polyline);
865 graphicView->drawEntity(newPolyline);
868 RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
869 if (document!=NULL && handleUndo) {
870 document->startUndoCycle();
872 polyline.setUndoState(true);
873 document->addUndoable(&polyline);
874 document->addUndoable(newPolyline);
876 document->endUndoCycle();
886 * Deletes all nodes between the two given nodes (exclusive).
888 * @param node1 First limiting node.
889 * @param node2 Second limiting node.
891 * @return Pointer to the new polyline or NULL.
894 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
895 RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
897 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
899 if (container==NULL) {
900 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
901 RS_Debug::D_WARNING);
905 if (node1.valid==false || node2.valid==false) {
906 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
908 RS_Debug::D_WARNING);
912 if (node1.distanceTo(node2)<1.0e-6) {
913 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
914 "nodes are identical",
915 RS_Debug::D_WARNING);
919 // check if there's nothing to delete:
920 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
921 e=polyline.nextEntity()) {
924 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
926 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
927 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
928 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
929 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
931 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
933 RS_Debug::D_WARNING);
940 // check if the start point is involved:
941 bool startpointInvolved = false;
942 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
943 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
944 startpointInvolved = true;
948 // check which part of the polyline has to be deleted:
949 bool deleteStart = false;
950 if (polyline.isClosed()) {
952 double length1 = 0.0;
953 double length2 = 0.0;
954 RS_Entity* e=polyline.firstEntity();
956 if (startpointInvolved) {
958 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
959 length1+=ae->getLength();
961 e = polyline.nextEntity();
963 for (; e!=NULL; e=polyline.nextEntity()) {
966 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
968 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
969 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
975 length2+=ae->getLength();
977 length1+=ae->getLength();
981 if (length1<length2) {
988 RS_Polyline* newPolyline = new RS_Polyline(container);
989 newPolyline->setClosed(polyline.isClosed());
990 newPolyline->setSelected(polyline.isSelected());
991 newPolyline->setLayer(polyline.getLayer());
992 newPolyline->setPen(polyline.getPen());
994 if (startpointInvolved && deleteStart && polyline.isClosed()) {
995 newPolyline->setNextBulge(0.0);
996 newPolyline->addVertex(polyline.getStartpoint());
999 // copy polyline and drop deleted nodes:
1001 bool removing = deleteStart;
1003 bool nextIsStraight = false;
1004 RS_Entity* lastEntity = polyline.lastEntity();
1007 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1008 e=polyline.nextEntity()) {
1010 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1011 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1013 if (e->isAtomic()) {
1014 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1015 if (ae->rtti()==RS2::EntityArc) {
1016 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1017 bulge = ((RS_Arc*)ae)->getBulge();
1019 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1023 // last entity is closing entity and will be added below with endPolyline()
1024 if (e==lastEntity && polyline.isClosed()) {
1025 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1026 "dropping last vertex of closed polyline");
1030 // first vertex (startpoint)
1033 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1034 ae->getStartpoint().x, ae->getStartpoint().y);
1035 newPolyline->setNextBulge(bulge);
1036 newPolyline->addVertex(ae->getStartpoint());
1041 // stop removing nodes:
1042 if (removing==true &&
1043 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1044 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1045 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1046 "stop removing at: %f/%f",
1047 ae->getEndpoint().x, ae->getEndpoint().y);
1051 nextIsStraight = true;
1055 // normal node (not deleted):
1056 if (removing==false && (done==false || deleteStart==false)) {
1057 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1058 "normal vertex found: %f/%f",
1059 ae->getEndpoint().x, ae->getEndpoint().y);
1060 if (nextIsStraight) {
1062 nextIsStraight = false;
1064 newPolyline->setNextBulge(bulge);
1065 newPolyline->addVertex(ae->getEndpoint());
1068 // drop deleted node:
1070 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1071 "deleting vertex: %f/%f",
1072 ae->getEndpoint().x, ae->getEndpoint().y);
1075 // start to remove nodes from now on:
1076 if (done==false && removing==false &&
1077 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1078 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1079 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1080 "start removing at: %f/%f",
1081 ae->getEndpoint().x, ae->getEndpoint().y);
1089 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1090 "Polyline contains non-atomic entities",
1091 RS_Debug::D_WARNING);
1095 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1096 newPolyline->setNextBulge(polyline.getClosingBulge());
1097 newPolyline->endPolyline();
1099 // add new polyline:
1100 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1101 container->addEntity(newPolyline);
1102 if (graphicView!=NULL) {
1103 graphicView->deleteEntity(&polyline);
1104 graphicView->drawEntity(newPolyline);
1107 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1108 if (document!=NULL && handleUndo) {
1109 document->startUndoCycle();
1111 polyline.setUndoState(true);
1112 document->addUndoable(&polyline);
1113 document->addUndoable(newPolyline);
1115 document->endUndoCycle();
1125 * Trims two segments of a polyline all nodes between the two trim segments
1128 * @param polyline The polyline entity.
1129 * @param segment1 First segment to trim.
1130 * @param segment2 Second segment to trim.
1132 * @return Pointer to the new polyline or NULL.
1135 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1136 RS_AtomicEntity& segment1,
1137 RS_AtomicEntity& segment2) {
1139 RS_DEBUG->print("RS_Modification::polylineTrim");
1141 if (container==NULL) {
1142 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1143 RS_Debug::D_WARNING);
1147 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1148 RS_DEBUG->print("RS_Modification::polylineTrim: "
1149 "segments not in polyline",
1150 RS_Debug::D_WARNING);
1154 if (&segment1==&segment2) {
1155 RS_DEBUG->print("RS_Modification::polylineTrim: "
1156 "segments are identical",
1157 RS_Debug::D_WARNING);
1161 VectorSolutions sol;
1162 sol = RS_Information::getIntersection(&segment1, &segment2, false);
1164 if (sol.getNumber()==0) {
1165 RS_DEBUG->print("RS_Modification::polylineTrim: "
1166 "segments cannot be trimmed",
1167 RS_Debug::D_WARNING);
1171 // check which segment comes first in the polyline:
1172 RS_AtomicEntity* firstSegment;
1173 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1174 firstSegment = &segment2;
1176 firstSegment = &segment1;
1179 // find out if we need to trim towards the open part of the polyline
1181 reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1182 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1183 //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1184 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1186 RS_Polyline* newPolyline = new RS_Polyline(container);
1187 newPolyline->setClosed(polyline.isClosed());
1188 newPolyline->setSelected(polyline.isSelected());
1189 newPolyline->setLayer(polyline.getLayer());
1190 newPolyline->setPen(polyline.getPen());
1192 // normal trimming: start removing nodes at trim segment. ends stay the same
1193 if (reverseTrim==false) {
1194 // copy polyline, trim segments and drop between nodes:
1196 bool removing = false;
1197 bool nextIsStraight = false;
1198 RS_Entity* lastEntity = polyline.lastEntity();
1199 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1200 e=polyline.nextEntity()) {
1202 if (e->isAtomic()) {
1203 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1205 if (ae->rtti()==RS2::EntityArc) {
1206 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1207 bulge = ((RS_Arc*)ae)->getBulge();
1209 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1213 // last entity is closing entity and will be added below with endPolyline()
1214 if (e==lastEntity && polyline.isClosed()) {
1215 RS_DEBUG->print("RS_Modification::polylineTrim: "
1216 "dropping last vertex of closed polyline");
1220 // first vertex (startpoint)
1222 RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1223 ae->getStartpoint().x, ae->getStartpoint().y);
1225 newPolyline->setNextBulge(bulge);
1226 newPolyline->addVertex(ae->getStartpoint());
1230 // trim and start removing nodes:
1231 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1232 RS_DEBUG->print("RS_Modification::polylineTrim: "
1233 "start removing at trim point %f/%f",
1234 sol.get(0).x, sol.get(0).y);
1235 newPolyline->setNextBulge(0.0);
1236 newPolyline->addVertex(sol.get(0));
1238 nextIsStraight = true;
1241 // stop removing nodes:
1242 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1243 RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1244 ae->getEndpoint().x, ae->getEndpoint().y);
1248 // normal node (not deleted):
1249 if (removing==false) {
1250 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1251 ae->getEndpoint().x, ae->getEndpoint().y);
1252 if (nextIsStraight) {
1253 newPolyline->setNextBulge(0.0);
1254 nextIsStraight = false;
1256 newPolyline->setNextBulge(bulge);
1258 newPolyline->addVertex(ae->getEndpoint());
1261 RS_DEBUG->print("RS_Modification::polylineTrim: "
1262 "Polyline contains non-atomic entities",
1263 RS_Debug::D_WARNING);
1268 // reverse trimming: remove nodes at the ends and keep those in between
1270 // copy polyline, trim segments and drop between nodes:
1271 //bool first = true;
1272 bool removing = true;
1273 bool nextIsStraight = false;
1274 RS_Entity* lastEntity = polyline.lastEntity();
1275 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1276 e=polyline.nextEntity()) {
1278 if (e->isAtomic()) {
1279 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1281 if (ae->rtti()==RS2::EntityArc) {
1282 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1283 bulge = ((RS_Arc*)ae)->getBulge();
1285 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1289 // last entity is closing entity and will be added below with endPolyline()
1290 if (e==lastEntity && polyline.isClosed()) {
1291 RS_DEBUG->print("RS_Modification::polylineTrim: "
1292 "dropping last vertex of closed polyline");
1296 // trim and stop removing nodes:
1297 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1298 RS_DEBUG->print("RS_Modification::polylineTrim: "
1299 "stop removing at trim point %f/%f",
1300 sol.get(0).x, sol.get(0).y);
1301 newPolyline->setNextBulge(0.0);
1302 // start of new polyline:
1303 newPolyline->addVertex(sol.get(0));
1305 nextIsStraight = true;
1308 // start removing nodes again:
1309 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1310 RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1311 ae->getEndpoint().x, ae->getEndpoint().y);
1312 newPolyline->setNextBulge(0.0);
1313 // start of new polyline:
1314 newPolyline->addVertex(sol.get(0));
1318 // normal node (not deleted):
1319 if (removing==false) {
1320 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1321 ae->getEndpoint().x, ae->getEndpoint().y);
1322 if (nextIsStraight) {
1323 newPolyline->setNextBulge(0.0);
1324 nextIsStraight = false;
1326 newPolyline->setNextBulge(bulge);
1328 newPolyline->addVertex(ae->getEndpoint());
1331 RS_DEBUG->print("RS_Modification::polylineTrim: "
1332 "Polyline contains non-atomic entities",
1333 RS_Debug::D_WARNING);
1338 RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1339 newPolyline->setNextBulge(polyline.getClosingBulge());
1340 newPolyline->endPolyline();
1342 // add new polyline:
1343 RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1344 container->addEntity(newPolyline);
1345 if (graphicView!=NULL) {
1346 graphicView->deleteEntity(&polyline);
1347 graphicView->drawEntity(newPolyline);
1350 RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1351 if (document!=NULL && handleUndo) {
1352 document->startUndoCycle();
1354 polyline.setUndoState(true);
1355 document->addUndoable(&polyline);
1356 document->addUndoable(newPolyline);
1358 document->endUndoCycle();
1366 * Moves all selected entities with the given data for the move
1369 bool RS_Modification::move(RS_MoveData & data)
1371 if (container == NULL)
1373 RS_DEBUG->print("RS_Modification::move: no valid container", RS_Debug::D_WARNING);
1377 // Q3PtrList<RS_Entity> addList;
1378 // addList.setAutoDelete(false);
1379 QList<RS_Entity *> addList;
1381 if (document != NULL && handleUndo)
1382 document->startUndoCycle();
1384 // Create new entites
1385 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1388 //for (uint i=0; i<container->count(); ++i) {
1389 //RS_Entity* e = container->entityAt(i);
1390 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1392 if (e != NULL && e->isSelected())
1394 RS_Entity * ec = e->clone();
1395 ec->move(data.offset * num);
1397 if (data.useCurrentLayer)
1398 ec->setLayerToActive();
1400 if (data.useCurrentAttributes)
1401 ec->setPenToActive();
1403 if (ec->rtti() == RS2::EntityInsert)
1404 ((RS_Insert *)ec)->update();
1406 // since 2.0.4.0: keep selection
1407 ec->setSelected(true);
1413 deselectOriginals(data.number==0);
1414 addNewEntities(addList);
1416 if (document != NULL && handleUndo)
1417 document->endUndoCycle();
1419 if (graphicView != NULL)
1420 graphicView->redraw();
1426 * Rotates all selected entities with the given data for the rotation.
1428 bool RS_Modification::rotate(RS_RotateData & data)
1430 if (container == NULL)
1432 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1433 RS_Debug::D_WARNING);
1437 // Q3PtrList<RS_Entity> addList;
1438 // addList.setAutoDelete(false);
1439 QList<RS_Entity *> addList;
1441 if (document!=NULL && handleUndo)
1442 document->startUndoCycle();
1444 // Create new entites
1445 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1447 for (RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1449 //for (uint i=0; i<container->count(); ++i) {
1450 //RS_Entity* e = container->entityAt(i);
1452 if (e != NULL && e->isSelected())
1454 RS_Entity * ec = e->clone();
1455 ec->setSelected(false);
1456 ec->rotate(data.center, data.angle*num);
1458 if (data.useCurrentLayer)
1459 ec->setLayerToActive();
1461 if (data.useCurrentAttributes)
1462 ec->setPenToActive();
1464 if (ec->rtti() == RS2::EntityInsert)
1465 ((RS_Insert *)ec)->update();
1472 deselectOriginals(data.number == 0);
1473 addNewEntities(addList);
1475 if (document != NULL && handleUndo)
1476 document->endUndoCycle();
1478 if (graphicView != NULL)
1479 graphicView->redraw();
1485 * Moves all selected entities with the given data for the scale
1488 bool RS_Modification::scale(RS_ScaleData & data)
1490 if (container == NULL)
1492 RS_DEBUG->print("RS_Modification::scale: no valid container", RS_Debug::D_WARNING);
1496 // Q3PtrList<RS_Entity> addList;
1497 // addList.setAutoDelete(false);
1498 QList<RS_Entity *> addList;
1500 if (document!=NULL && handleUndo)
1501 document->startUndoCycle();
1503 // Create new entites
1504 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1506 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1508 //for (uint i=0; i<container->count(); ++i) {
1509 //RS_Entity* e = container->entityAt(i);
1510 if (e != NULL && e->isSelected())
1512 RS_Entity * ec = e->clone();
1513 ec->setSelected(false);
1514 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1516 if (data.useCurrentLayer)
1517 ec->setLayerToActive();
1519 if (data.useCurrentAttributes)
1520 ec->setPenToActive();
1522 if (ec->rtti()==RS2::EntityInsert)
1523 ((RS_Insert*)ec)->update();
1530 deselectOriginals(data.number == 0);
1531 addNewEntities(addList);
1533 if (document != NULL && handleUndo)
1534 document->endUndoCycle();
1536 if (graphicView != NULL)
1537 graphicView->redraw();
1543 * Mirror all selected entities with the given data for the mirror
1546 bool RS_Modification::mirror(RS_MirrorData & data)
1548 if (container==NULL) {
1549 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1550 RS_Debug::D_WARNING);
1554 // Q3PtrList<RS_Entity> addList;
1555 // addList.setAutoDelete(false);
1556 QList<RS_Entity *> addList;
1558 if (document!=NULL && handleUndo) {
1559 document->startUndoCycle();
1562 // Create new entites
1564 num<=(int)data.copy || (data.copy==false && num<=1);
1566 for (RS_Entity* e=container->firstEntity();
1568 e=container->nextEntity()) {
1569 //for (uint i=0; i<container->count(); ++i) {
1570 //RS_Entity* e = container->entityAt(i);
1572 if (e!=NULL && e->isSelected()) {
1573 RS_Entity* ec = e->clone();
1574 ec->setSelected(false);
1576 ec->mirror(data.axisPoint1, data.axisPoint2);
1577 if (data.useCurrentLayer) {
1578 ec->setLayerToActive();
1580 if (data.useCurrentAttributes) {
1581 ec->setPenToActive();
1583 if (ec->rtti()==RS2::EntityInsert) {
1584 ((RS_Insert*)ec)->update();
1591 deselectOriginals(data.copy==false);
1592 addNewEntities(addList);
1594 if (document!=NULL && handleUndo) {
1595 document->endUndoCycle();
1598 if (graphicView!=NULL) {
1599 graphicView->redraw();
1605 * Rotates entities around two centers with the given parameters.
1607 bool RS_Modification::rotate2(RS_Rotate2Data & data)
1609 if (container==NULL) {
1610 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1611 RS_Debug::D_WARNING);
1615 // Q3PtrList<RS_Entity> addList;
1616 // addList.setAutoDelete(false);
1617 QList<RS_Entity *> addList;
1619 if (document!=NULL && handleUndo) {
1620 document->startUndoCycle();
1623 // Create new entites
1625 num<=data.number || (data.number==0 && num<=1);
1628 for (RS_Entity* e=container->firstEntity();
1630 e=container->nextEntity()) {
1631 //for (uint i=0; i<container->count(); ++i) {
1632 //RS_Entity* e = container->entityAt(i);
1634 if (e!=NULL && e->isSelected()) {
1635 RS_Entity* ec = e->clone();
1636 ec->setSelected(false);
1638 ec->rotate(data.center1, data.angle1*num);
1639 Vector center2 = data.center2;
1640 center2.rotate(data.center1, data.angle1*num);
1642 ec->rotate(center2, data.angle2*num);
1643 if (data.useCurrentLayer) {
1644 ec->setLayerToActive();
1646 if (data.useCurrentAttributes) {
1647 ec->setPenToActive();
1649 if (ec->rtti()==RS2::EntityInsert) {
1650 ((RS_Insert*)ec)->update();
1657 deselectOriginals(data.number==0);
1658 addNewEntities(addList);
1660 if (document!=NULL && handleUndo) {
1661 document->endUndoCycle();
1664 if (graphicView!=NULL) {
1665 graphicView->redraw();
1671 * Moves and rotates entities with the given parameters.
1673 bool RS_Modification::moveRotate(RS_MoveRotateData & data)
1675 if (container==NULL) {
1676 RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1677 RS_Debug::D_WARNING);
1681 // Q3PtrList<RS_Entity> addList;
1682 // addList.setAutoDelete(false);
1683 QList<RS_Entity *> addList;
1685 if (document!=NULL && handleUndo) {
1686 document->startUndoCycle();
1689 // Create new entites
1691 num<=data.number || (data.number==0 && num<=1);
1693 for (RS_Entity* e=container->firstEntity();
1695 e=container->nextEntity()) {
1696 //for (uint i=0; i<container->count(); ++i) {
1697 //RS_Entity* e = container->entityAt(i);
1699 if (e!=NULL && e->isSelected()) {
1700 RS_Entity* ec = e->clone();
1701 ec->setSelected(false);
1703 ec->move(data.offset*num);
1704 ec->rotate(data.referencePoint + data.offset*num,
1706 if (data.useCurrentLayer) {
1707 ec->setLayerToActive();
1709 if (data.useCurrentAttributes) {
1710 ec->setPenToActive();
1712 if (ec->rtti()==RS2::EntityInsert) {
1713 ((RS_Insert*)ec)->update();
1720 deselectOriginals(data.number==0);
1721 addNewEntities(addList);
1723 if (document!=NULL && handleUndo) {
1724 document->endUndoCycle();
1726 if (graphicView!=NULL) {
1727 graphicView->redraw();
1734 * Deselects all selected entities and removes them if remove is true;
1736 * @param remove true: Remove entites.
1738 void RS_Modification::deselectOriginals(bool remove)
1740 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1742 //for (uint i=0; i<container->count(); ++i) {
1743 //RS_Entity* e = container->entityAt(i);
1747 bool selected = false;
1749 if (e->isAtomic()) {
1750 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1751 if (ae->isStartpointSelected() ||
1752 ae->isEndpointSelected()) {
1759 if (e->isSelected())
1764 e->setSelected(false);
1768 //if (graphicView!=NULL) {
1769 // graphicView->deleteEntity(e);
1771 e->changeUndoState();
1773 if (document != NULL && handleUndo)
1774 document->addUndoable(e);
1778 //if (graphicView!=NULL) {
1779 // graphicView->drawEntity(e);
1788 * Adds the given entities to the container and draws the entities if
1789 * there's a graphic view available.
1791 * @param addList Entities to add.
1793 //void RS_Modification::addNewEntities(Q3PtrList<RS_Entity> & addList)
1794 void RS_Modification::addNewEntities(QList<RS_Entity *> & addList)
1796 // for(RS_Entity * e=addList.first(); e!=NULL; e=addList.next())
1797 for(int i=0; i<addList.size(); i++)
1799 RS_Entity * e = addList[i];
1803 container->addEntity(e);
1805 if (document != NULL && handleUndo)
1806 document->addUndoable(e);
1807 //if (graphicView!=NULL) {
1808 // graphicView->drawEntity(e);
1815 * Trims or extends the given trimEntity to the intersection point of the
1816 * trimEntity and the limitEntity.
1818 * @param trimCoord Coordinate which defines which endpoint of the
1819 * trim entity to trim.
1820 * @param trimEntity Entity which will be trimmed.
1821 * @param limitCoord Coordinate which defines the intersection to which the
1822 * trim entity will be trimmed.
1823 * @param limitEntity Entity to which the trim entity will be trimmed.
1824 * @param both true: Trim both entities. false: trim trimEntity only.
1826 bool RS_Modification::trim(const Vector& trimCoord, RS_AtomicEntity* trimEntity,
1827 const Vector& limitCoord, RS_Entity* limitEntity, bool both)
1829 if (trimEntity==NULL || limitEntity==NULL)
1831 RS_DEBUG->print(RS_Debug::D_WARNING,
1832 "RS_Modification::trim: At least one entity is NULL");
1836 if (both && !limitEntity->isAtomic())
1838 RS_DEBUG->print(RS_Debug::D_WARNING,
1839 "RS_Modification::trim: limitEntity is not atomic");
1842 VectorSolutions sol;
1844 if (limitEntity->isAtomic())
1846 // intersection(s) of the two entities:
1847 sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1848 } else if (limitEntity->isContainer()) {
1849 RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1854 for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1855 e=ec->nextEntity(RS2::ResolveAll)) {
1856 //for (int i=0; i<container->count(); ++i) {
1857 // RS_Entity* e = container->entityAt(i);
1861 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1864 if (s2.hasValid()) {
1865 for (int k=0; k<s2.getNumber(); ++k) {
1866 if (i<128 && s2.get(k).valid) {
1867 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1868 sol.set(i++, s2.get(k));
1878 if (sol.hasValid()==false) {
1882 RS_AtomicEntity* trimmed1 = NULL;
1883 RS_AtomicEntity* trimmed2 = NULL;
1885 // remove trim entity from view:
1886 if (trimEntity->rtti()==RS2::EntityCircle) {
1887 // convert a circle into a trimmable arc
1888 RS_Circle* c = (RS_Circle*)trimEntity;
1889 double am = c->getCenter().angleTo(trimCoord);
1890 RS_ArcData d(c->getCenter(),
1892 RS_Math::correctAngle(am-M_PI/2),
1893 RS_Math::correctAngle(am+M_PI/2), false);
1894 trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1896 trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1897 trimmed1->setHighlighted(false);
1899 if (graphicView!=NULL) {
1900 graphicView->deleteEntity(trimEntity);
1903 // remove limit entity from view:
1905 trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1906 trimmed2->setHighlighted(false);
1907 if (graphicView!=NULL) {
1908 graphicView->deleteEntity(limitEntity);
1914 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1915 //sol.getClosest(limitCoord, NULL, &ind);
1916 RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1917 RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1918 RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1919 RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1920 Vector is2 = sol.get(ind==0 ? 1 : 0);
1921 //Vector is2 = sol.get(ind);
1922 RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1924 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1925 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1928 case RS2::EndingStart:
1929 trimmed1->trimStartpoint(is);
1930 if (trimEntity->rtti()==RS2::EntityCircle) {
1931 trimmed1->trimEndpoint(is2);
1934 case RS2::EndingEnd:
1935 trimmed1->trimEndpoint(is);
1936 if (trimEntity->rtti()==RS2::EntityCircle) {
1937 trimmed1->trimStartpoint(is2);
1944 // trim limit entity:
1946 Vector is = sol.getClosest(limitCoord);
1948 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1951 case RS2::EndingStart:
1952 trimmed2->trimStartpoint(is);
1954 case RS2::EndingEnd:
1955 trimmed2->trimEndpoint(is);
1962 // add new trimmed trim entity:
1963 container->addEntity(trimmed1);
1964 if (graphicView!=NULL) {
1965 graphicView->drawEntity(trimmed1);
1968 // add new trimmed limit entity:
1970 container->addEntity(trimmed2);
1971 if (graphicView!=NULL) {
1972 graphicView->drawEntity(trimmed2);
1976 if (document!=NULL && handleUndo) {
1977 document->startUndoCycle();
1978 document->addUndoable(trimmed1);
1979 trimEntity->setUndoState(true);
1980 document->addUndoable(trimEntity);
1982 document->addUndoable(trimmed2);
1983 limitEntity->setUndoState(true);
1984 document->addUndoable(limitEntity);
1986 document->endUndoCycle();
1995 * Trims or extends the given trimEntity by the given amount.
1997 * @param trimCoord Coordinate which defines which endpoint of the
1998 * trim entity to trim.
1999 * @param trimEntity Entity which will be trimmed.
2000 * @param dist Amount to trim by.
2002 bool RS_Modification::trimAmount(const Vector& trimCoord,
2003 RS_AtomicEntity* trimEntity,
2006 if (trimEntity==NULL) {
2007 RS_DEBUG->print(RS_Debug::D_WARNING,
2008 "RS_Modification::trimAmount: Entity is NULL");
2012 RS_AtomicEntity* trimmed = NULL;
2014 // remove trim entity:
2015 trimmed = (RS_AtomicEntity*)trimEntity->clone();
2016 if (graphicView!=NULL) {
2017 graphicView->deleteEntity(trimEntity);
2021 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2022 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2023 trimCoord.distanceTo(trimmed->getEndpoint())) {
2024 trimmed->trimStartpoint(is);
2026 trimmed->trimEndpoint(is);
2029 // add new trimmed trim entity:
2030 container->addEntity(trimmed);
2032 if (graphicView!=NULL) {
2033 graphicView->drawEntity(trimmed);
2036 if (document!=NULL && handleUndo) {
2037 document->startUndoCycle();
2038 document->addUndoable(trimmed);
2039 trimEntity->setUndoState(true);
2040 document->addUndoable(trimEntity);
2041 document->endUndoCycle();
2050 * Cuts the given entity at the given point.
2052 bool RS_Modification::cut(const Vector& cutCoord,
2053 RS_AtomicEntity* cutEntity) {
2055 if (cutEntity==NULL) {
2056 RS_DEBUG->print(RS_Debug::D_WARNING,
2057 "RS_Modification::cut: Entity is NULL");
2061 if (!cutCoord.valid) {
2062 RS_DEBUG->print(RS_Debug::D_WARNING,
2063 "RS_Modification::cut: Point invalid.");
2067 // cut point is at endpoint of entity:
2068 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2069 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2070 RS_DEBUG->print(RS_Debug::D_WARNING,
2071 "RS_Modification::cut: Cutting point on endpoint");
2075 // delete cut entity on the screen:
2076 if (graphicView!=NULL) {
2077 graphicView->deleteEntity(cutEntity);
2080 RS_AtomicEntity* cut1 = NULL;
2081 RS_AtomicEntity* cut2 = NULL;
2083 // create new two halves:
2084 if (cutEntity->rtti()==RS2::EntityCircle) {
2085 RS_Circle* c = (RS_Circle*)cutEntity;
2086 cut1 = new RS_Arc(cutEntity->getParent(),
2087 RS_ArcData(c->getCenter(),
2090 cut1->setPen(cutEntity->getPen());
2091 cut1->setLayer(cutEntity->getLayer());
2094 cut1->trimEndpoint(cutCoord);
2095 cut1->trimStartpoint(cutCoord);
2097 cut1 = (RS_AtomicEntity*)cutEntity->clone();
2098 cut2 = (RS_AtomicEntity*)cutEntity->clone();
2100 cut1->trimEndpoint(cutCoord);
2101 cut2->trimStartpoint(cutCoord);
2104 // add new cut entity:
2105 container->addEntity(cut1);
2107 container->addEntity(cut2);
2110 if (graphicView!=NULL) {
2111 graphicView->drawEntity(cut1);
2113 graphicView->drawEntity(cut2);
2117 if (document!=NULL && handleUndo) {
2118 document->startUndoCycle();
2119 document->addUndoable(cut1);
2121 document->addUndoable(cut2);
2123 cutEntity->setUndoState(true);
2124 document->addUndoable(cutEntity);
2125 document->endUndoCycle();
2134 bool RS_Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2135 const Vector& offset)
2139 RS_DEBUG->print(RS_Debug::D_WARNING,
2140 "RS_Modification::stretch: Offset invalid");
2144 // Q3PtrList<RS_Entity> addList;
2145 // addList.setAutoDelete(false);
2146 QList<RS_Entity *> addList;
2148 if (document!=NULL && handleUndo) {
2149 document->startUndoCycle();
2152 // Create new entites
2153 for (RS_Entity* e=container->firstEntity();
2155 e=container->nextEntity()) {
2156 //for (int i=0; i<container->count(); ++i) {
2157 // RS_Entity* e = container->entityAt(i);
2162 (e->isInWindow(firstCorner, secondCorner) ||
2163 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2165 RS_Entity* ec = e->clone();
2166 ec->stretch(firstCorner, secondCorner, offset);
2168 e->setSelected(true);
2172 deselectOriginals(true);
2173 addNewEntities(addList);
2175 if (document!=NULL && handleUndo) {
2176 document->endUndoCycle();
2179 if (graphicView!=NULL) {
2180 graphicView->redraw();
2190 * @param coord1 Mouse coordinate to specify direction from intersection.
2191 * @param entity1 First entity of the corner.
2192 * @param coord2 Mouse coordinate to specify direction from intersection.
2193 * @param entity2 Second entity of the corner.
2194 * @param data Lengths and trim flag.
2196 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2197 const Vector& coord2, RS_AtomicEntity* entity2,
2198 RS_BevelData& data) {
2200 RS_DEBUG->print("RS_Modification::bevel");
2202 if (entity1==NULL || entity2==NULL) {
2203 RS_DEBUG->print(RS_Debug::D_WARNING,
2204 "RS_Modification::bevel: At least one entity is NULL");
2208 RS_EntityContainer* baseContainer = container;
2209 bool isPolyline = false;
2210 bool isClosedPolyline = false;
2212 if (document!=NULL && handleUndo) {
2213 document->startUndoCycle();
2216 // find out whether we're bevelling within a polyline:
2217 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2218 RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2219 if (entity1->getParent()!=entity2->getParent()) {
2220 RS_DEBUG->print(RS_Debug::D_WARNING,
2221 "RS_Modification::bevel: entities not in the same polyline");
2224 // clone polyline for undo
2225 if (document!=NULL && handleUndo) {
2226 RS_EntityContainer* cl =
2227 (RS_EntityContainer*)entity1->getParent()->clone();
2228 container->addEntity(cl);
2229 //cl->setUndoState(true);
2230 document->addUndoable(cl);
2232 document->addUndoable(entity1->getParent());
2233 entity1->getParent()->setUndoState(true);
2238 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2239 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2241 //baseContainer = entity1->getParent();
2243 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2246 RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2248 VectorSolutions sol =
2249 RS_Information::getIntersection(entity1, entity2, false);
2251 if (sol.getNumber()==0) {
2255 RS_AtomicEntity* trimmed1 = NULL;
2256 RS_AtomicEntity* trimmed2 = NULL;
2258 //if (data.trim || isPolyline) {
2263 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2264 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2267 // remove trim entity (on screen):
2268 if (data.trim==true || isPolyline) {
2269 if (graphicView!=NULL) {
2271 graphicView->deleteEntity(baseContainer);
2273 graphicView->deleteEntity(entity1);
2274 graphicView->deleteEntity(entity2);
2279 // trim entities to intersection
2280 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2281 bool start1 = false;
2282 Vector is = sol.getClosest(coord2);
2283 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2285 case RS2::EndingStart:
2286 trimmed1->trimStartpoint(is);
2289 case RS2::EndingEnd:
2290 trimmed1->trimEndpoint(is);
2297 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2298 bool start2 = false;
2299 is = sol.getClosest(coord1);
2300 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2302 case RS2::EndingStart:
2303 trimmed2->trimStartpoint(is);
2306 case RS2::EndingEnd:
2307 trimmed2->trimEndpoint(is);
2316 // find definitive bevel points
2317 RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2318 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2319 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2322 RS_DEBUG->print("RS_Modification::bevel: final trim");
2323 if (data.trim==true) {
2325 case RS2::EndingStart:
2326 trimmed1->trimStartpoint(bp1);
2328 case RS2::EndingEnd:
2329 trimmed1->trimEndpoint(bp1);
2336 case RS2::EndingStart:
2337 trimmed2->trimStartpoint(bp2);
2339 case RS2::EndingEnd:
2340 trimmed2->trimEndpoint(bp2);
2346 // add new trimmed entities:
2347 if (isPolyline==false) {
2348 container->addEntity(trimmed1);
2349 container->addEntity(trimmed2);
2351 if (graphicView!=NULL) {
2353 graphicView->drawEntity(trimmed1);
2354 graphicView->drawEntity(trimmed2);
2361 RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2362 RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2364 if (isPolyline==false) {
2365 baseContainer->addEntity(bevel);
2367 int idx1 = baseContainer->findEntity(trimmed1);
2368 int idx2 = baseContainer->findEntity(trimmed2);
2370 bevel->setSelected(baseContainer->isSelected());
2371 bevel->setLayer(baseContainer->getLayer());
2372 bevel->setPen(baseContainer->getPen());
2374 bool insertAfter1 = false;
2375 if (!isClosedPolyline) {
2376 insertAfter1 = (idx1<idx2);
2379 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2380 (idx2==0 && idx1==(int)baseContainer->count()-1));
2383 // insert bevel at the right position:
2384 //if ((idx1<idx2 && idx1!=0) ||
2385 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2387 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2390 baseContainer->insertEntity(idx1+1, bevel);
2392 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2395 baseContainer->insertEntity(idx2+1, bevel);
2400 ((RS_Polyline*)baseContainer)->updateEndpoints();
2403 if (graphicView!=NULL) {
2405 graphicView->drawEntity(baseContainer);
2407 graphicView->drawEntity(bevel);
2411 RS_DEBUG->print("RS_Modification::bevel: handling undo");
2413 if (document!=NULL && handleUndo) {
2414 //document->startUndoCycle();
2416 if (isPolyline==false && data.trim==true) {
2417 document->addUndoable(trimmed1);
2418 entity1->setUndoState(true);
2419 document->addUndoable(entity1);
2421 document->addUndoable(trimmed2);
2422 entity2->setUndoState(true);
2423 document->addUndoable(entity2);
2426 if (isPolyline==false) {
2427 document->addUndoable(bevel);
2430 document->endUndoCycle();
2433 if (data.trim==false) {
2434 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2437 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2449 * @param coord Mouse coordinate to specify the rounding.
2450 * @param entity1 First entity of the corner.
2451 * @param entity2 Second entity of the corner.
2452 * @param data Radius and trim flag.
2454 bool RS_Modification::round(const Vector& coord,
2455 const Vector& coord1,
2456 RS_AtomicEntity* entity1,
2457 const Vector& coord2,
2458 RS_AtomicEntity* entity2,
2459 RS_RoundData& data) {
2461 if (entity1==NULL || entity2==NULL) {
2462 RS_DEBUG->print(RS_Debug::D_WARNING,
2463 "RS_Modification::round: At least one entity is NULL");
2467 RS_EntityContainer* baseContainer = container;
2468 bool isPolyline = false;
2469 bool isClosedPolyline = false;
2471 if (document!=NULL && handleUndo) {
2472 document->startUndoCycle();
2475 // find out whether we're rounding within a polyline:
2476 if (entity1->getParent()!=NULL &&
2477 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2479 if (entity1->getParent()!=entity2->getParent()) {
2480 RS_DEBUG->print(RS_Debug::D_WARNING,
2481 "RS_Modification::round: entities not in "
2482 "the same polyline");
2483 if (document!=NULL && handleUndo) {
2484 document->endUndoCycle();
2489 // clone polyline for undo
2490 if (document!=NULL && handleUndo) {
2491 RS_EntityContainer* cl =
2492 (RS_EntityContainer*)entity1->getParent()->clone();
2493 container->addEntity(cl);
2494 document->addUndoable(cl);
2496 document->addUndoable(entity1->getParent());
2497 entity1->getParent()->setUndoState(true);
2502 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2503 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2506 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2509 // create 2 tmp parallels
2510 RS_Creation creation(NULL, NULL);
2511 RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2512 RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2514 VectorSolutions sol2 =
2515 RS_Information::getIntersection(entity1, entity2, false);
2517 VectorSolutions sol =
2518 RS_Information::getIntersection(par1, par2, false);
2520 if (sol.getNumber()==0) {
2521 if (document!=NULL && handleUndo) {
2522 document->endUndoCycle();
2527 // there might be two intersections: choose the closest:
2528 Vector is = sol.getClosest(coord);
2529 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2530 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2531 double ang1 = is.angleTo(p1);
2532 double ang2 = is.angleTo(p2);
2533 bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2535 RS_Arc* arc = new RS_Arc(baseContainer,
2542 RS_AtomicEntity* trimmed1 = NULL;
2543 RS_AtomicEntity* trimmed2 = NULL;
2545 if (data.trim || isPolyline) {
2550 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2551 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2554 // remove trim entity:
2555 if (graphicView!=NULL) {
2557 graphicView->deleteEntity(baseContainer);
2559 graphicView->deleteEntity(entity1);
2560 graphicView->deleteEntity(entity2);
2564 // trim entities to intersection
2565 Vector is2 = sol2.getClosest(coord2);
2566 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2568 case RS2::EndingStart:
2569 trimmed1->trimStartpoint(p1);
2571 case RS2::EndingEnd:
2572 trimmed1->trimEndpoint(p1);
2578 is2 = sol2.getClosest(coord1);
2579 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2581 case RS2::EndingStart:
2582 trimmed2->trimStartpoint(p2);
2584 case RS2::EndingEnd:
2585 trimmed2->trimEndpoint(p2);
2591 // add new trimmed entities:
2592 if (isPolyline==false) {
2593 container->addEntity(trimmed1);
2594 container->addEntity(trimmed2);
2596 if (graphicView!=NULL) {
2598 graphicView->drawEntity(trimmed1);
2599 graphicView->drawEntity(trimmed2);
2605 if (isPolyline==false) {
2606 baseContainer->addEntity(arc);
2608 // find out which base entity is before the rounding:
2609 int idx1 = baseContainer->findEntity(trimmed1);
2610 int idx2 = baseContainer->findEntity(trimmed2);
2612 arc->setSelected(baseContainer->isSelected());
2613 arc->setLayer(baseContainer->getLayer());
2614 arc->setPen(baseContainer->getPen());
2616 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2617 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2618 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2619 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2620 (int)(idx1==(int)baseContainer->count()-1));
2622 bool insertAfter1 = false;
2623 if (!isClosedPolyline) {
2624 insertAfter1 = (idx1<idx2);
2627 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2628 (idx2==0 && idx1==(int)baseContainer->count()-1));
2631 // insert rounding at the right position:
2632 //if ((idx1<idx2 && idx1!=0) ||
2633 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2636 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2639 baseContainer->insertEntity(idx1+1, arc);
2641 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2644 baseContainer->insertEntity(idx2+1, arc);
2649 ((RS_Polyline*)baseContainer)->updateEndpoints();
2652 if (graphicView!=NULL) {
2654 graphicView->drawEntity(baseContainer);
2656 graphicView->drawEntity(arc);
2660 if (document!=NULL && handleUndo) {
2661 if (isPolyline==false && data.trim==true) {
2662 document->addUndoable(trimmed1);
2663 entity1->setUndoState(true);
2664 document->addUndoable(entity1);
2666 document->addUndoable(trimmed2);
2667 entity2->setUndoState(true);
2668 document->addUndoable(entity2);
2671 if (isPolyline==false) {
2672 document->addUndoable(arc);
2675 document->endUndoCycle();
2685 * Removes the selected entity containers and adds the entities in them as
2686 * new single entities.
2688 bool RS_Modification::explode()
2690 if (container == NULL)
2692 RS_DEBUG->print("RS_Modification::explode: no valid container for addinge entities",
2693 RS_Debug::D_WARNING);
2697 // Q3PtrList<RS_Entity> addList;
2698 // addList.setAutoDelete(false);
2699 QList<RS_Entity *> addList;
2701 if (document!=NULL && handleUndo) {
2702 document->startUndoCycle();
2705 for (RS_Entity* e=container->firstEntity();
2707 e=container->nextEntity()) {
2708 //for (uint i=0; i<container->count(); ++i) {
2709 //RS_Entity* e = container->entityAt(i);
2711 if (e!=NULL && e->isSelected()) {
2712 if (e->isContainer()) {
2714 // add entities from container:
2715 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2716 //ec->setSelected(false);
2718 // iterate and explode container:
2719 //for (uint i2=0; i2<ec->count(); ++i2) {
2720 // RS_Entity* e2 = ec->entityAt(i2);
2721 RS2::ResolveLevel rl;
2725 switch (ec->rtti()) {
2726 case RS2::EntityText:
2727 case RS2::EntityHatch:
2728 case RS2::EntityPolyline:
2729 rl = RS2::ResolveAll;
2730 resolveLayer = true;
2734 case RS2::EntityInsert:
2736 resolveLayer = false;
2737 rl = RS2::ResolveNone;
2740 case RS2::EntityDimAligned:
2741 case RS2::EntityDimLinear:
2742 case RS2::EntityDimRadial:
2743 case RS2::EntityDimDiametric:
2744 case RS2::EntityDimAngular:
2745 case RS2::EntityDimLeader:
2746 rl = RS2::ResolveNone;
2747 resolveLayer = true;
2752 rl = RS2::ResolveAll;
2753 resolveLayer = true;
2758 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2759 e2 = ec->nextEntity(rl)) {
2762 RS_Entity* clone = e2->clone();
2763 clone->setSelected(false);
2764 clone->reparent(container);
2767 clone->setLayer(ec->getLayer());
2769 clone->setLayer(e2->getLayer());
2772 clone->setPen(ec->getPen(resolvePen));
2774 addList.append(clone);
2780 e->setSelected(false);
2785 deselectOriginals(true);
2786 addNewEntities(addList);
2788 if (document!=NULL && handleUndo) {
2789 document->endUndoCycle();
2792 if (graphicView!=NULL) {
2793 graphicView->redraw();
2799 bool RS_Modification::explodeTextIntoLetters()
2801 if (container == NULL)
2803 RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2804 " for addinge entities", RS_Debug::D_WARNING);
2808 // Q3PtrList<RS_Entity> addList;
2809 // addList.setAutoDelete(false);
2810 QList<RS_Entity *> addList;
2812 if (document!=NULL && handleUndo) {
2813 document->startUndoCycle();
2816 for (RS_Entity* e=container->firstEntity();
2818 e=container->nextEntity()) {
2819 if (e!=NULL && e->isSelected()) {
2820 if (e->rtti()==RS2::EntityText) {
2821 // add letters of text:
2822 RS_Text* text = (RS_Text*)e;
2823 explodeTextIntoLetters(text, addList);
2825 e->setSelected(false);
2830 deselectOriginals(true);
2831 addNewEntities(addList);
2833 if (document!=NULL && handleUndo) {
2834 document->endUndoCycle();
2837 if (graphicView!=NULL) {
2838 graphicView->redraw();
2844 //bool RS_Modification::explodeTextIntoLetters(RS_Text* text, Q3PtrList<RS_Entity>& addList)
2845 bool RS_Modification::explodeTextIntoLetters(RS_Text * text, QList<RS_Entity *> & addList)
2850 // iterate though lines:
2851 for(RS_Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2857 if (e2->rtti() == RS2::EntityContainer)
2859 RS_EntityContainer * line = (RS_EntityContainer *)e2;
2861 // iterate though letters:
2862 for(RS_Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2867 // super / sub texts:
2868 if (e3->rtti() == RS2::EntityText)
2869 explodeTextIntoLetters((RS_Text *)e3, addList);
2871 else if (e3->rtti() == RS2::EntityInsert)
2873 RS_Insert * letter = (RS_Insert *)e3;
2875 RS_Text * tl = new RS_Text(container, RS_TextData(letter->getInsertionPoint(),
2876 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2877 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2878 letter->getAngle(), RS2::Update));
2880 tl->setLayer(text->getLayer());
2881 tl->setPen(text->getPen());
2894 * Moves all reference points of selected entities with the given data.
2896 bool RS_Modification::moveRef(RS_MoveRefData& data)
2898 if (container == NULL)
2900 RS_DEBUG->print("RS_Modification::moveRef: no valid container", RS_Debug::D_WARNING);
2904 // Q3PtrList<RS_Entity> addList;
2905 // addList.setAutoDelete(false);
2906 QList<RS_Entity *> addList;
2908 if (document != NULL && handleUndo)
2909 document->startUndoCycle();
2911 // Create new entites
2912 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2914 if (e != NULL && e->isSelected())
2916 RS_Entity * ec = e->clone();
2917 ec->moveRef(data.ref, data.offset);
2918 // since 2.0.4.0: keep it selected
2919 ec->setSelected(true);
2924 deselectOriginals(true);
2925 addNewEntities(addList);
2927 if (document != NULL && handleUndo)
2928 document->endUndoCycle();
2930 if (graphicView != NULL)
2931 graphicView->redraw();