1 /****************************************************************************
2 ** $Id: rs_modification.cpp 2419 2005-07-01 16:47:27Z andrew $
4 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
6 ** This file is part of the qcadlib Library project.
8 ** This file may be distributed and/or modified under the terms of the
9 ** GNU General Public License version 2 as published by the Free Software
10 ** Foundation and appearing in the file LICENSE.GPL included in the
11 ** packaging of this file.
13 ** Licensees holding valid qcadlib Professional Edition licenses may use
14 ** this file in accordance with the qcadlib Commercial License
15 ** Agreement provided with the Software.
17 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 ** See http://www.ribbonsoft.com for further details.
22 ** Contact info@ribbonsoft.com if any conditions of this licensing are
25 **********************************************************************/
27 #include "rs_modification.h"
29 #include "rs_clipboard.h"
30 #include "rs_creation.h"
31 #include "rs_entity.h"
32 #include "rs_graphic.h"
33 #include "rs_information.h"
34 #include "rs_insert.h"
35 #include "rs_polyline.h"
41 * Default constructor.
43 * @param container The container to which we will add
44 * entities. Usually that's an RS_Graphic entity but
45 * it can also be a polyline, text, ...
46 * @param graphicView Pointer to graphic view or NULL if you don't want the
47 * any views to be updated.
48 * @param handleUndo true: Handle undo functionalitiy.
50 RS_Modification::RS_Modification(RS_EntityContainer& container,
51 RS_GraphicView* graphicView,
53 this->container = &container;
54 this->graphicView = graphicView;
55 this->handleUndo = handleUndo;
56 graphic = container.getGraphic();
57 document = container.getDocument();
63 * Deletes all selected entities.
65 void RS_Modification::remove
67 if (container==NULL) {
68 RS_DEBUG->print("RS_Modification::remove: no valid container",
74 document->startUndoCycle();
78 for (RS_Entity* e=container->firstEntity(); e!=NULL;
79 e=container->nextEntity()) {
81 if (e!=NULL && e->isSelected()) {
82 e->setSelected(false);
85 document->addUndoable(e);
91 document->endUndoCycle();
94 graphicView->redraw();
100 * Changes the attributes of all selected
102 bool RS_Modification::changeAttributes(RS_AttributesData& data) {
103 if (container==NULL) {
104 RS_DEBUG->print("RS_Modification::changeAttributes: no valid container",
105 RS_Debug::D_WARNING);
109 RS_PtrList<RS_Entity> addList;
110 addList.setAutoDelete(false);
112 if (document!=NULL) {
113 document->startUndoCycle();
116 for (RS_Entity* e=container->firstEntity(); e!=NULL;
117 e=container->nextEntity()) {
118 //for (uint i=0; i<container->count(); ++i) {
119 //RS_Entity* e = container->entityAt(i);
120 if (e!=NULL && e->isSelected()) {
121 RS_Entity* ec = e->clone();
122 ec->setSelected(false);
124 RS_Pen pen = ec->getPen(false);
126 if (data.changeLayer==true) {
127 ec->setLayer(data.layer);
130 if (data.changeColor==true) {
131 pen.setColor(data.pen.getColor());
133 if (data.changeLineType==true) {
134 pen.setLineType(data.pen.getLineType());
136 if (data.changeWidth==true) {
137 pen.setWidth(data.pen.getWidth());
142 //if (data.useCurrentLayer) {
143 // ec->setLayerToActive();
145 //if (data.useCurrentAttributes) {
146 // ec->setPenToActive();
148 //if (ec->rtti()==RS2::EntityInsert) {
149 // ((RS_Insert*)ec)->update();
156 deselectOriginals(true);
157 addNewEntities(addList);
159 if (document!=NULL) {
160 document->endUndoCycle();
163 if (graphicView!=NULL) {
164 graphicView->redraw();
172 * Copies all selected entities from the given container to the clipboard.
173 * Layers and blocks that are needed are also copied if the container is
174 * or is part of an RS_Graphic.
176 * @param container The entity container.
177 * @param ref Reference point. The entities will be moved by -ref.
178 * @param cut true: cut instead of copying, false: copy
180 void RS_Modification::copy(const Vector& ref, const bool cut) {
182 if (container==NULL) {
183 RS_DEBUG->print("RS_Modification::copy: no valid container",
184 RS_Debug::D_WARNING);
188 RS_CLIPBOARD->clear();
190 RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
192 RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
195 // start undo cycle for the container if we're cutting
196 if (cut && document!=NULL) {
197 document->startUndoCycle();
200 // copy entities / layers / blocks
201 for (RS_Entity* e=container->firstEntity(); e!=NULL;
202 e=container->nextEntity()) {
203 //for (uint i=0; i<container->count(); ++i) {
204 //RS_Entity* e = container->entityAt(i);
206 if (e!=NULL && e->isSelected()) {
207 copyEntity(e, ref, cut);
211 if (cut && document!=NULL) {
212 document->endUndoCycle();
219 * Copies the given entity from the given container to the clipboard.
220 * Layers and blocks that are needed are also copied if the container is
221 * or is part of an RS_Graphic.
223 * @param e The entity.
224 * @param ref Reference point. The entities will be moved by -ref.
225 * @param cut true: cut instead of copying, false: copy
227 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
230 if (e!=NULL && e->isSelected()) {
231 // delete entity in graphic view:
233 if (graphicView!=NULL) {
234 graphicView->deleteEntity(e);
236 e->setSelected(false);
238 if (graphicView!=NULL) {
239 graphicView->deleteEntity(e);
241 e->setSelected(false);
242 if (graphicView!=NULL) {
243 graphicView->drawEntity(e);
247 // add entity to clipboard:
248 RS_Entity* c = e->clone();
250 RS_CLIPBOARD->addEntity(c);
255 // set layer to the layer clone:
256 RS_Layer* l = e->getLayer();
258 c->setLayer(l->getName());
261 // make sure all sub entities point to layers of the clipboard
262 if (c->isContainer()) {
263 RS_EntityContainer* ec = (RS_EntityContainer*)c;
265 for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
266 e2 = ec->nextEntity(RS2::ResolveAll)) {
268 //RS_Entity* e2 = ec->entityAt(i);
269 RS_Layer* l2 = e2->getLayer();
272 e2->setLayer(l2->getName());
278 e->changeUndoState();
279 if (document!=NULL) {
280 document->addUndoable(e);
290 * Copies all layers of the given entity to the clipboard.
292 void RS_Modification::copyLayers(RS_Entity* e) {
298 // add layer(s) of the entity if it's not an insert
299 // (inserts are on layer '0'):
300 if (e->rtti()!=RS2::EntityInsert) {
301 RS_Layer* l = e->getLayer();
303 if (!RS_CLIPBOARD->hasLayer(l->getName())) {
304 RS_CLIPBOARD->addLayer(l->clone());
309 // special handling of inserts:
311 // insert: add layer(s) of subentities:
312 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
314 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
315 e2=b->nextEntity()) {
316 //for (uint i=0; i<b->count(); ++i) {
317 //RS_Entity* e2 = b->entityAt(i);
327 * Copies all blocks of the given entity to the clipboard.
329 void RS_Modification::copyBlocks(RS_Entity* e) {
335 // add block of the entity if it's an insert
336 if (e->rtti()==RS2::EntityInsert) {
337 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
339 // add block of an insert:
340 if (!RS_CLIPBOARD->hasBlock(b->getName())) {
341 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
344 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
345 e2=b->nextEntity()) {
346 //for (uint i=0; i<b->count(); ++i) {
347 //RS_Entity* e2 = b->entityAt(i);
357 * Pastes all entities from the clipboard into the container.
358 * Layers and blocks that are needed are also copied if the container is
359 * or is part of an RS_Graphic.
361 * @param data Paste data.
362 * @param source The source from where to paste. NULL means the source
365 void RS_Modification::paste(const RS_PasteData& data, RS_Graphic* source) {
368 RS_DEBUG->print(RS_Debug::D_WARNING,
369 "RS_Modification::paste: Graphic is NULL");
376 source = RS_CLIPBOARD->getGraphic();
378 // graphics from the clipboard need to be scaled. from the part lib not:
379 RS2::Unit sourceUnit = source->getUnit();
380 RS2::Unit targetUnit = graphic->getUnit();
381 factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
384 if (document!=NULL) {
385 document->startUndoCycle();
391 RS_Layer* layer = graphic->getActiveLayer();
392 for(uint i=0; i<source->countLayers(); ++i) {
393 RS_Layer* l = source->layerAt(i);
395 if (graphic->findLayer(l->getName())==NULL) {
396 graphic->addLayer(l->clone());
400 graphic->activateLayer(layer);
405 for(uint i=0; i<source->countBlocks(); ++i) {
406 RS_Block* b = source->blockAt(i);
408 if (graphic->findBlock(b->getName())==NULL) {
409 RS_Block* bc = (RS_Block*)b->clone();
410 bc->reparent(container);
411 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
412 // scale block but don't scale inserts in block
413 // (they already scale with their block)
414 for(uint i2=0; i2<bc->count(); ++i2) {
415 RS_Entity* e = bc->entityAt(i2);
416 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
417 e->scale(bc->getBasePoint(),
418 Vector(factor, factor));
420 Vector ip = ((RS_Insert*)e)->getInsertionPoint();
421 ip.scale(bc->getBasePoint(),
422 Vector(factor, factor));
423 ((RS_Insert*)e)->setInsertionPoint(ip);
428 graphic->addBlock(bc);
434 // add entities to this host (graphic or a new block)
435 RS_EntityContainer* host = container;
440 if (data.asInsert==true) {
441 RS_BlockList* blkList = graphic->getBlockList();
443 blockName = blkList->newName(data.blockName);
446 new RS_Block(graphic,
447 RS_BlockData(blockName,
448 Vector(0.0,0.0), false));
449 graphic->addBlock(blk);
457 //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
458 //RS_Entity* e = source->entityAt(i);
459 for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
461 e=((RS_EntityContainer*)source)->nextEntity()) {
465 RS_String layerName = "0";
466 RS_Layer* layer = e->getLayer();
468 layerName = layer->getName();
470 RS_Entity* e2 = e->clone();
472 if (data.asInsert==false) {
473 e2->move(data.insertionPoint);
475 // don't adjust insert factor - block was already adjusted to unit
476 if (e2->rtti()==RS2::EntityInsert) {
477 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
478 ip.scale(data.insertionPoint, Vector(factor, factor));
479 ((RS_Insert*)e2)->setInsertionPoint(ip);
482 e2->scale(data.insertionPoint, Vector(factor, factor));
485 e2->setLayer(layerName);
487 // make sure all sub entities point to layers of the container
488 if (e2->isContainer()) {
489 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
491 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
492 e3 = ec->nextEntity(RS2::ResolveAll)) {
494 //RS_Entity* e3 = ec->entityAt(i);
495 RS_Layer* l2 = e3->getLayer();
497 e3->setLayer(l2->getName());
502 if (document!=NULL && data.asInsert==false) {
503 document->addUndoable(e2);
508 if (data.asInsert==true) {
510 new RS_Insert(container,
514 Vector(data.factor, data.factor),
516 1,1,Vector(0.0,0.0)));
517 container->addEntity(ins);
518 ins->setLayerToActive();
519 ins->setPenToActive();
521 if (document!=NULL) {
522 document->addUndoable(ins);
526 if (document!=NULL) {
527 document->endUndoCycle();
533 * Splits a polyline into two leaving out a gap.
535 * @param polyline The original polyline
536 * @param e1 1st entity on which the first cutting point is.
537 * @param v1 1st cutting point.
538 * @param e2 2nd entity on which the first cutting point is.
539 * @param v2 2nd cutting point.
540 * @param polyline1 Pointer to a polyline pointer which will hold the
541 * 1st resulting new polyline. Pass NULL if you don't
542 * need those pointers.
543 * @param polyline2 Pointer to a polyline pointer which will hold the
544 * 2nd resulting new polyline. Pass NULL if you don't
545 * need those pointers.
547 * @todo Support arcs in polylines, check for wrong parameters
551 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
552 RS_Entity& e1, Vector v1,
553 RS_Entity& e2, Vector v2,
554 RS_Polyline** polyline1,
555 RS_Polyline** polyline2) const {
557 if (container==NULL) {
558 RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
559 RS_Debug::D_WARNING);
563 RS_Entity* firstEntity = polyline.firstEntity();
564 Vector firstPoint(false);
565 if (firstEntity->rtti()==RS2::EntityLine) {
566 firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
569 new RS_Polyline(container,
570 RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
571 RS_Polyline* pl2 = new RS_Polyline(container);
572 RS_Polyline* pl = pl1; // Current polyline
573 RS_Line* line = NULL;
576 if (polyline1!=NULL) {
579 if (polyline2!=NULL) {
583 for (RS_Entity* e = polyline.firstEntity();
585 e = polyline.nextEntity()) {
587 if (e->rtti()==RS2::EntityLine) {
590 } else if (e->rtti()==RS2::EntityArc) {
598 if (line!=NULL /*|| arc!=NULL*/) {
600 if (e==&e1 && e==&e2) {
601 // Trim within a single entity:
602 Vector sp = line->getStartpoint();
603 double dist1 = (v1-sp).magnitude();
604 double dist2 = (v2-sp).magnitude();
605 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
607 pl->setStartpoint(dist1<dist2 ? v2 : v1);
608 pl->addVertex(line->getEndpoint(), 0.0);
609 } else if (e==&e1 || e==&e2) {
611 Vector v = (e==&e1 ? v1 : v2);
613 // Trim endpoint of entity to first vector
614 pl->addVertex(v, 0.0);
617 // Trim startpoint of entity to second vector
619 pl->setStartpoint(v);
620 pl->addVertex(line->getEndpoint(), 0.0);
623 // Add entities to polylines
624 if (line!=NULL && pl!=NULL) {
625 pl->addVertex(line->getEndpoint(), 0.0);
631 container->addEntity(pl1);
632 container->addEntity(pl2);
633 //container->removeEntity(&polyline);
634 polyline.changeUndoState();
642 * Adds a node to the given polyline. The new node is placed between
643 * the start and end point of the given segment.
645 * @param node The position of the new node.
647 * @return Pointer to the new polyline or NULL.
650 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
651 const RS_AtomicEntity& segment,
652 const Vector& node) {
653 RS_DEBUG->print("RS_Modification::addPolylineNode");
655 if (container==NULL) {
656 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
657 RS_Debug::D_WARNING);
661 if (segment.getParent()!=&polyline) {
662 RS_DEBUG->print("RS_Modification::addPolylineNode: "
663 "segment not part of the polyline",
664 RS_Debug::D_WARNING);
668 RS_Polyline* newPolyline = new RS_Polyline(container);
669 newPolyline->setClosed(polyline.isClosed());
670 newPolyline->setSelected(polyline.isSelected());
671 newPolyline->setLayer(polyline.getLayer());
672 newPolyline->setPen(polyline.getPen());
674 // copy polyline and add new node:
676 RS_Entity* lastEntity = polyline.lastEntity();
677 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
678 e=polyline.nextEntity()) {
681 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
683 if (ae->rtti()==RS2::EntityArc) {
684 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
685 bulge = ((RS_Arc*)ae)->getBulge();
687 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
692 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
693 ae->getStartpoint().x, ae->getStartpoint().y);
695 newPolyline->setNextBulge(bulge);
696 newPolyline->addVertex(ae->getStartpoint());
702 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
704 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
707 newPolyline->setNextBulge(0.0);
708 newPolyline->addVertex(node);
710 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
711 ae->getEndpoint().x, ae->getEndpoint().y);
713 if (ae!=lastEntity || polyline.isClosed()==false) {
714 newPolyline->setNextBulge(0.0);
715 newPolyline->addVertex(ae->getEndpoint());
718 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
719 ae->getEndpoint().x, ae->getEndpoint().y);
721 if (ae!=lastEntity || polyline.isClosed()==false) {
722 newPolyline->setNextBulge(bulge);
723 newPolyline->addVertex(ae->getEndpoint());
727 RS_DEBUG->print("RS_Modification::addPolylineNode: "
728 "Polyline contains non-atomic entities",
729 RS_Debug::D_WARNING);
733 newPolyline->setNextBulge(polyline.getClosingBulge());
734 newPolyline->endPolyline();
737 container->addEntity(newPolyline);
738 if (graphicView!=NULL) {
739 graphicView->deleteEntity(&polyline);
740 graphicView->drawEntity(newPolyline);
743 if (document!=NULL && handleUndo) {
744 document->startUndoCycle();
746 polyline.setUndoState(true);
747 document->addUndoable(&polyline);
748 document->addUndoable(newPolyline);
750 document->endUndoCycle();
760 * Deletes a node from a polyline.
762 * @param node The node to delete.
764 * @return Pointer to the new polyline or NULL.
767 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
768 const Vector& node) {
770 RS_DEBUG->print("RS_Modification::deletePolylineNode");
772 if (container==NULL) {
773 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
774 RS_Debug::D_WARNING);
778 if (node.valid==false) {
779 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
781 RS_Debug::D_WARNING);
785 // check if the polyline is no longer there after deleting the node:
786 if (polyline.count()==1) {
787 RS_Entity* e = polyline.firstEntity();
788 if (e!=NULL && e->isAtomic()) {
789 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
790 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
791 node.distanceTo(ae->getEndpoint())<1.0e-6) {
793 if (graphicView!=NULL) {
794 graphicView->deleteEntity(&polyline);
797 if (document!=NULL && handleUndo) {
798 document->startUndoCycle();
799 polyline.setUndoState(true);
800 document->addUndoable(&polyline);
801 document->endUndoCycle();
808 RS_Polyline* newPolyline = new RS_Polyline(container);
809 newPolyline->setClosed(polyline.isClosed());
810 newPolyline->setSelected(polyline.isSelected());
811 newPolyline->setLayer(polyline.getLayer());
812 newPolyline->setPen(polyline.getPen());
814 // copy polyline and drop deleted node:
816 bool lastDropped = false;
817 RS_Entity* lastEntity = polyline.lastEntity();
818 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
819 e=polyline.nextEntity()) {
822 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
824 if (ae->rtti()==RS2::EntityArc) {
825 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
826 bulge = ((RS_Arc*)ae)->getBulge();
828 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
832 // last entity is closing entity and will be added below with endPolyline()
833 if (e==lastEntity && polyline.isClosed()) {
837 // first vertex (startpoint)
838 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
839 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
840 ae->getStartpoint().x, ae->getStartpoint().y);
842 newPolyline->setNextBulge(bulge);
843 newPolyline->addVertex(ae->getStartpoint());
847 // normal node (not deleted):
848 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
849 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
850 ae->getEndpoint().x, ae->getEndpoint().y);
854 newPolyline->setNextBulge(bulge);
855 newPolyline->addVertex(ae->getEndpoint());
859 // drop deleted node:
861 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
862 ae->getEndpoint().x, ae->getEndpoint().y);
866 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
867 "Polyline contains non-atomic entities",
868 RS_Debug::D_WARNING);
872 RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
873 newPolyline->setNextBulge(polyline.getClosingBulge());
874 newPolyline->endPolyline();
876 //if (newPolyline->count()==1) {
880 RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
881 container->addEntity(newPolyline);
882 if (graphicView!=NULL) {
883 graphicView->deleteEntity(&polyline);
884 graphicView->drawEntity(newPolyline);
887 RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
888 if (document!=NULL && handleUndo) {
889 document->startUndoCycle();
891 polyline.setUndoState(true);
892 document->addUndoable(&polyline);
893 document->addUndoable(newPolyline);
895 document->endUndoCycle();
905 * Deletes all nodes between the two given nodes (exclusive).
907 * @param node1 First limiting node.
908 * @param node2 Second limiting node.
910 * @return Pointer to the new polyline or NULL.
913 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
914 RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
916 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
918 if (container==NULL) {
919 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
920 RS_Debug::D_WARNING);
924 if (node1.valid==false || node2.valid==false) {
925 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
927 RS_Debug::D_WARNING);
931 if (node1.distanceTo(node2)<1.0e-6) {
932 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
933 "nodes are identical",
934 RS_Debug::D_WARNING);
938 // check if there's nothing to delete:
939 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
940 e=polyline.nextEntity()) {
943 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
945 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
946 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
947 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
948 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
950 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
952 RS_Debug::D_WARNING);
959 // check if the start point is involved:
960 bool startpointInvolved = false;
961 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
962 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
963 startpointInvolved = true;
967 // check which part of the polyline has to be deleted:
968 bool deleteStart = false;
969 if (polyline.isClosed()) {
971 double length1 = 0.0;
972 double length2 = 0.0;
973 RS_Entity* e=polyline.firstEntity();
975 if (startpointInvolved) {
977 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
978 length1+=ae->getLength();
980 e = polyline.nextEntity();
982 for (; e!=NULL; e=polyline.nextEntity()) {
985 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
987 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
988 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
994 length2+=ae->getLength();
996 length1+=ae->getLength();
1000 if (length1<length2) {
1003 deleteStart = false;
1007 RS_Polyline* newPolyline = new RS_Polyline(container);
1008 newPolyline->setClosed(polyline.isClosed());
1009 newPolyline->setSelected(polyline.isSelected());
1010 newPolyline->setLayer(polyline.getLayer());
1011 newPolyline->setPen(polyline.getPen());
1013 if (startpointInvolved && deleteStart && polyline.isClosed()) {
1014 newPolyline->setNextBulge(0.0);
1015 newPolyline->addVertex(polyline.getStartpoint());
1018 // copy polyline and drop deleted nodes:
1020 bool removing = deleteStart;
1022 bool nextIsStraight = false;
1023 RS_Entity* lastEntity = polyline.lastEntity();
1026 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1027 e=polyline.nextEntity()) {
1029 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1030 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1032 if (e->isAtomic()) {
1033 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1034 if (ae->rtti()==RS2::EntityArc) {
1035 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1036 bulge = ((RS_Arc*)ae)->getBulge();
1038 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1042 // last entity is closing entity and will be added below with endPolyline()
1043 if (e==lastEntity && polyline.isClosed()) {
1044 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1045 "dropping last vertex of closed polyline");
1049 // first vertex (startpoint)
1052 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1053 ae->getStartpoint().x, ae->getStartpoint().y);
1054 newPolyline->setNextBulge(bulge);
1055 newPolyline->addVertex(ae->getStartpoint());
1060 // stop removing nodes:
1061 if (removing==true &&
1062 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1063 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1064 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1065 "stop removing at: %f/%f",
1066 ae->getEndpoint().x, ae->getEndpoint().y);
1070 nextIsStraight = true;
1074 // normal node (not deleted):
1075 if (removing==false && (done==false || deleteStart==false)) {
1076 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1077 "normal vertex found: %f/%f",
1078 ae->getEndpoint().x, ae->getEndpoint().y);
1079 if (nextIsStraight) {
1081 nextIsStraight = false;
1083 newPolyline->setNextBulge(bulge);
1084 newPolyline->addVertex(ae->getEndpoint());
1087 // drop deleted node:
1089 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1090 "deleting vertex: %f/%f",
1091 ae->getEndpoint().x, ae->getEndpoint().y);
1094 // start to remove nodes from now on:
1095 if (done==false && removing==false &&
1096 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1097 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1098 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1099 "start removing at: %f/%f",
1100 ae->getEndpoint().x, ae->getEndpoint().y);
1108 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1109 "Polyline contains non-atomic entities",
1110 RS_Debug::D_WARNING);
1114 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1115 newPolyline->setNextBulge(polyline.getClosingBulge());
1116 newPolyline->endPolyline();
1118 // add new polyline:
1119 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1120 container->addEntity(newPolyline);
1121 if (graphicView!=NULL) {
1122 graphicView->deleteEntity(&polyline);
1123 graphicView->drawEntity(newPolyline);
1126 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1127 if (document!=NULL && handleUndo) {
1128 document->startUndoCycle();
1130 polyline.setUndoState(true);
1131 document->addUndoable(&polyline);
1132 document->addUndoable(newPolyline);
1134 document->endUndoCycle();
1144 * Trims two segments of a polyline all nodes between the two trim segments
1147 * @param polyline The polyline entity.
1148 * @param segment1 First segment to trim.
1149 * @param segment2 Second segment to trim.
1151 * @return Pointer to the new polyline or NULL.
1154 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1155 RS_AtomicEntity& segment1,
1156 RS_AtomicEntity& segment2) {
1158 RS_DEBUG->print("RS_Modification::polylineTrim");
1160 if (container==NULL) {
1161 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1162 RS_Debug::D_WARNING);
1166 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1167 RS_DEBUG->print("RS_Modification::polylineTrim: "
1168 "segments not in polyline",
1169 RS_Debug::D_WARNING);
1173 if (&segment1==&segment2) {
1174 RS_DEBUG->print("RS_Modification::polylineTrim: "
1175 "segments are identical",
1176 RS_Debug::D_WARNING);
1180 VectorSolutions sol;
1181 sol = RS_Information::getIntersection(&segment1, &segment2, false);
1183 if (sol.getNumber()==0) {
1184 RS_DEBUG->print("RS_Modification::polylineTrim: "
1185 "segments cannot be trimmed",
1186 RS_Debug::D_WARNING);
1190 // check which segment comes first in the polyline:
1191 RS_AtomicEntity* firstSegment;
1192 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1193 firstSegment = &segment2;
1195 firstSegment = &segment1;
1198 // find out if we need to trim towards the open part of the polyline
1200 reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1201 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1202 //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1203 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1205 RS_Polyline* newPolyline = new RS_Polyline(container);
1206 newPolyline->setClosed(polyline.isClosed());
1207 newPolyline->setSelected(polyline.isSelected());
1208 newPolyline->setLayer(polyline.getLayer());
1209 newPolyline->setPen(polyline.getPen());
1211 // normal trimming: start removing nodes at trim segment. ends stay the same
1212 if (reverseTrim==false) {
1213 // copy polyline, trim segments and drop between nodes:
1215 bool removing = false;
1216 bool nextIsStraight = false;
1217 RS_Entity* lastEntity = polyline.lastEntity();
1218 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1219 e=polyline.nextEntity()) {
1221 if (e->isAtomic()) {
1222 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1224 if (ae->rtti()==RS2::EntityArc) {
1225 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1226 bulge = ((RS_Arc*)ae)->getBulge();
1228 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1232 // last entity is closing entity and will be added below with endPolyline()
1233 if (e==lastEntity && polyline.isClosed()) {
1234 RS_DEBUG->print("RS_Modification::polylineTrim: "
1235 "dropping last vertex of closed polyline");
1239 // first vertex (startpoint)
1241 RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1242 ae->getStartpoint().x, ae->getStartpoint().y);
1244 newPolyline->setNextBulge(bulge);
1245 newPolyline->addVertex(ae->getStartpoint());
1249 // trim and start removing nodes:
1250 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1251 RS_DEBUG->print("RS_Modification::polylineTrim: "
1252 "start removing at trim point %f/%f",
1253 sol.get(0).x, sol.get(0).y);
1254 newPolyline->setNextBulge(0.0);
1255 newPolyline->addVertex(sol.get(0));
1257 nextIsStraight = true;
1260 // stop removing nodes:
1261 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1262 RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1263 ae->getEndpoint().x, ae->getEndpoint().y);
1267 // normal node (not deleted):
1268 if (removing==false) {
1269 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1270 ae->getEndpoint().x, ae->getEndpoint().y);
1271 if (nextIsStraight) {
1272 newPolyline->setNextBulge(0.0);
1273 nextIsStraight = false;
1275 newPolyline->setNextBulge(bulge);
1277 newPolyline->addVertex(ae->getEndpoint());
1280 RS_DEBUG->print("RS_Modification::polylineTrim: "
1281 "Polyline contains non-atomic entities",
1282 RS_Debug::D_WARNING);
1287 // reverse trimming: remove nodes at the ends and keep those in between
1289 // copy polyline, trim segments and drop between nodes:
1290 //bool first = true;
1291 bool removing = true;
1292 bool nextIsStraight = false;
1293 RS_Entity* lastEntity = polyline.lastEntity();
1294 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1295 e=polyline.nextEntity()) {
1297 if (e->isAtomic()) {
1298 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1300 if (ae->rtti()==RS2::EntityArc) {
1301 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1302 bulge = ((RS_Arc*)ae)->getBulge();
1304 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1308 // last entity is closing entity and will be added below with endPolyline()
1309 if (e==lastEntity && polyline.isClosed()) {
1310 RS_DEBUG->print("RS_Modification::polylineTrim: "
1311 "dropping last vertex of closed polyline");
1315 // trim and stop removing nodes:
1316 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1317 RS_DEBUG->print("RS_Modification::polylineTrim: "
1318 "stop removing at trim point %f/%f",
1319 sol.get(0).x, sol.get(0).y);
1320 newPolyline->setNextBulge(0.0);
1321 // start of new polyline:
1322 newPolyline->addVertex(sol.get(0));
1324 nextIsStraight = true;
1327 // start removing nodes again:
1328 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1329 RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1330 ae->getEndpoint().x, ae->getEndpoint().y);
1331 newPolyline->setNextBulge(0.0);
1332 // start of new polyline:
1333 newPolyline->addVertex(sol.get(0));
1337 // normal node (not deleted):
1338 if (removing==false) {
1339 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1340 ae->getEndpoint().x, ae->getEndpoint().y);
1341 if (nextIsStraight) {
1342 newPolyline->setNextBulge(0.0);
1343 nextIsStraight = false;
1345 newPolyline->setNextBulge(bulge);
1347 newPolyline->addVertex(ae->getEndpoint());
1350 RS_DEBUG->print("RS_Modification::polylineTrim: "
1351 "Polyline contains non-atomic entities",
1352 RS_Debug::D_WARNING);
1357 RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1358 newPolyline->setNextBulge(polyline.getClosingBulge());
1359 newPolyline->endPolyline();
1361 // add new polyline:
1362 RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1363 container->addEntity(newPolyline);
1364 if (graphicView!=NULL) {
1365 graphicView->deleteEntity(&polyline);
1366 graphicView->drawEntity(newPolyline);
1369 RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1370 if (document!=NULL && handleUndo) {
1371 document->startUndoCycle();
1373 polyline.setUndoState(true);
1374 document->addUndoable(&polyline);
1375 document->addUndoable(newPolyline);
1377 document->endUndoCycle();
1387 * Moves all selected entities with the given data for the move
1390 bool RS_Modification::move(RS_MoveData& data) {
1391 if (container==NULL) {
1392 RS_DEBUG->print("RS_Modification::move: no valid container",
1393 RS_Debug::D_WARNING);
1397 RS_PtrList<RS_Entity> addList;
1398 addList.setAutoDelete(false);
1400 if (document!=NULL && handleUndo) {
1401 document->startUndoCycle();
1404 // Create new entites
1406 num<=data.number || (data.number==0 && num<=1);
1409 //for (uint i=0; i<container->count(); ++i) {
1410 //RS_Entity* e = container->entityAt(i);
1411 for (RS_Entity* e=container->firstEntity();
1413 e=container->nextEntity()) {
1414 if (e!=NULL && e->isSelected()) {
1415 RS_Entity* ec = e->clone();
1417 ec->move(data.offset*num);
1418 if (data.useCurrentLayer) {
1419 ec->setLayerToActive();
1421 if (data.useCurrentAttributes) {
1422 ec->setPenToActive();
1424 if (ec->rtti()==RS2::EntityInsert) {
1425 ((RS_Insert*)ec)->update();
1427 // since 2.0.4.0: keep selection
1428 ec->setSelected(true);
1434 deselectOriginals(data.number==0);
1435 addNewEntities(addList);
1437 if (document!=NULL && handleUndo) {
1438 document->endUndoCycle();
1441 if (graphicView!=NULL) {
1442 graphicView->redraw();
1451 * Rotates all selected entities with the given data for the rotation.
1453 bool RS_Modification::rotate(RS_RotateData& data) {
1454 if (container==NULL) {
1455 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1456 RS_Debug::D_WARNING);
1460 RS_PtrList<RS_Entity> addList;
1461 addList.setAutoDelete(false);
1463 if (document!=NULL && handleUndo) {
1464 document->startUndoCycle();
1467 // Create new entites
1469 num<=data.number || (data.number==0 && num<=1);
1471 for (RS_Entity* e=container->firstEntity();
1473 e=container->nextEntity()) {
1474 //for (uint i=0; i<container->count(); ++i) {
1475 //RS_Entity* e = container->entityAt(i);
1477 if (e!=NULL && e->isSelected()) {
1478 RS_Entity* ec = e->clone();
1479 ec->setSelected(false);
1481 ec->rotate(data.center, data.angle*num);
1482 if (data.useCurrentLayer) {
1483 ec->setLayerToActive();
1485 if (data.useCurrentAttributes) {
1486 ec->setPenToActive();
1488 if (ec->rtti()==RS2::EntityInsert) {
1489 ((RS_Insert*)ec)->update();
1496 deselectOriginals(data.number==0);
1497 addNewEntities(addList);
1499 if (document!=NULL && handleUndo) {
1500 document->endUndoCycle();
1502 if (graphicView!=NULL) {
1503 graphicView->redraw();
1512 * Moves all selected entities with the given data for the scale
1515 bool RS_Modification::scale(RS_ScaleData& data) {
1516 if (container==NULL) {
1517 RS_DEBUG->print("RS_Modification::scale: no valid container",
1518 RS_Debug::D_WARNING);
1522 RS_PtrList<RS_Entity> addList;
1523 addList.setAutoDelete(false);
1525 if (document!=NULL && handleUndo) {
1526 document->startUndoCycle();
1529 // Create new entites
1531 num<=data.number || (data.number==0 && num<=1);
1533 for (RS_Entity* e=container->firstEntity();
1535 e=container->nextEntity()) {
1536 //for (uint i=0; i<container->count(); ++i) {
1537 //RS_Entity* e = container->entityAt(i);
1538 if (e!=NULL && e->isSelected()) {
1539 RS_Entity* ec = e->clone();
1540 ec->setSelected(false);
1542 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1543 if (data.useCurrentLayer) {
1544 ec->setLayerToActive();
1546 if (data.useCurrentAttributes) {
1547 ec->setPenToActive();
1549 if (ec->rtti()==RS2::EntityInsert) {
1550 ((RS_Insert*)ec)->update();
1557 deselectOriginals(data.number==0);
1558 addNewEntities(addList);
1560 if (document!=NULL && handleUndo) {
1561 document->endUndoCycle();
1564 if (graphicView!=NULL) {
1565 graphicView->redraw();
1573 * Mirror all selected entities with the given data for the mirror
1576 bool RS_Modification::mirror(RS_MirrorData& data) {
1577 if (container==NULL) {
1578 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1579 RS_Debug::D_WARNING);
1583 RS_PtrList<RS_Entity> addList;
1584 addList.setAutoDelete(false);
1586 if (document!=NULL && handleUndo) {
1587 document->startUndoCycle();
1590 // Create new entites
1592 num<=(int)data.copy || (data.copy==false && num<=1);
1594 for (RS_Entity* e=container->firstEntity();
1596 e=container->nextEntity()) {
1597 //for (uint i=0; i<container->count(); ++i) {
1598 //RS_Entity* e = container->entityAt(i);
1600 if (e!=NULL && e->isSelected()) {
1601 RS_Entity* ec = e->clone();
1602 ec->setSelected(false);
1604 ec->mirror(data.axisPoint1, data.axisPoint2);
1605 if (data.useCurrentLayer) {
1606 ec->setLayerToActive();
1608 if (data.useCurrentAttributes) {
1609 ec->setPenToActive();
1611 if (ec->rtti()==RS2::EntityInsert) {
1612 ((RS_Insert*)ec)->update();
1619 deselectOriginals(data.copy==false);
1620 addNewEntities(addList);
1622 if (document!=NULL && handleUndo) {
1623 document->endUndoCycle();
1626 if (graphicView!=NULL) {
1627 graphicView->redraw();
1635 * Rotates entities around two centers with the given parameters.
1637 bool RS_Modification::rotate2(RS_Rotate2Data& data) {
1638 if (container==NULL) {
1639 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1640 RS_Debug::D_WARNING);
1644 RS_PtrList<RS_Entity> addList;
1645 addList.setAutoDelete(false);
1647 if (document!=NULL && handleUndo) {
1648 document->startUndoCycle();
1651 // Create new entites
1653 num<=data.number || (data.number==0 && num<=1);
1656 for (RS_Entity* e=container->firstEntity();
1658 e=container->nextEntity()) {
1659 //for (uint i=0; i<container->count(); ++i) {
1660 //RS_Entity* e = container->entityAt(i);
1662 if (e!=NULL && e->isSelected()) {
1663 RS_Entity* ec = e->clone();
1664 ec->setSelected(false);
1666 ec->rotate(data.center1, data.angle1*num);
1667 Vector center2 = data.center2;
1668 center2.rotate(data.center1, data.angle1*num);
1670 ec->rotate(center2, data.angle2*num);
1671 if (data.useCurrentLayer) {
1672 ec->setLayerToActive();
1674 if (data.useCurrentAttributes) {
1675 ec->setPenToActive();
1677 if (ec->rtti()==RS2::EntityInsert) {
1678 ((RS_Insert*)ec)->update();
1685 deselectOriginals(data.number==0);
1686 addNewEntities(addList);
1688 if (document!=NULL && handleUndo) {
1689 document->endUndoCycle();
1692 if (graphicView!=NULL) {
1693 graphicView->redraw();
1701 * Moves and rotates entities with the given parameters.
1703 bool RS_Modification::moveRotate(RS_MoveRotateData& data) {
1704 if (container==NULL) {
1705 RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1706 RS_Debug::D_WARNING);
1710 RS_PtrList<RS_Entity> addList;
1711 addList.setAutoDelete(false);
1713 if (document!=NULL && handleUndo) {
1714 document->startUndoCycle();
1717 // Create new entites
1719 num<=data.number || (data.number==0 && num<=1);
1721 for (RS_Entity* e=container->firstEntity();
1723 e=container->nextEntity()) {
1724 //for (uint i=0; i<container->count(); ++i) {
1725 //RS_Entity* e = container->entityAt(i);
1727 if (e!=NULL && e->isSelected()) {
1728 RS_Entity* ec = e->clone();
1729 ec->setSelected(false);
1731 ec->move(data.offset*num);
1732 ec->rotate(data.referencePoint + data.offset*num,
1734 if (data.useCurrentLayer) {
1735 ec->setLayerToActive();
1737 if (data.useCurrentAttributes) {
1738 ec->setPenToActive();
1740 if (ec->rtti()==RS2::EntityInsert) {
1741 ((RS_Insert*)ec)->update();
1748 deselectOriginals(data.number==0);
1749 addNewEntities(addList);
1751 if (document!=NULL && handleUndo) {
1752 document->endUndoCycle();
1754 if (graphicView!=NULL) {
1755 graphicView->redraw();
1764 * Deselects all selected entities and removes them if remove is true;
1766 * @param remove true: Remove entites.
1768 void RS_Modification::deselectOriginals(bool remove
1770 for (RS_Entity* e=container->firstEntity();
1772 e=container->nextEntity()) {
1774 //for (uint i=0; i<container->count(); ++i) {
1775 //RS_Entity* e = container->entityAt(i);
1778 bool selected = false;
1781 if (e->isAtomic()) {
1782 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1783 if (ae->isStartpointSelected() ||
1784 ae->isEndpointSelected()) {
1791 if (e->isSelected()) {
1796 e->setSelected(false);
1799 //if (graphicView!=NULL) {
1800 // graphicView->deleteEntity(e);
1802 e->changeUndoState();
1803 if (document!=NULL && handleUndo) {
1804 document->addUndoable(e);
1807 //if (graphicView!=NULL) {
1808 // graphicView->drawEntity(e);
1819 * Adds the given entities to the container and draws the entities if
1820 * there's a graphic view available.
1822 * @param addList Entities to add.
1824 void RS_Modification::addNewEntities(RS_PtrList<RS_Entity>& addList) {
1825 for (RS_Entity* e=addList.first();
1829 container->addEntity(e);
1830 if (document!=NULL && handleUndo) {
1831 document->addUndoable(e);
1833 //if (graphicView!=NULL) {
1834 // graphicView->drawEntity(e);
1843 * Trims or extends the given trimEntity to the intersection point of the
1844 * trimEntity and the limitEntity.
1846 * @param trimCoord Coordinate which defines which endpoint of the
1847 * trim entity to trim.
1848 * @param trimEntity Entity which will be trimmed.
1849 * @param limitCoord Coordinate which defines the intersection to which the
1850 * trim entity will be trimmed.
1851 * @param limitEntity Entity to which the trim entity will be trimmed.
1852 * @param both true: Trim both entities. false: trim trimEntity only.
1854 bool RS_Modification::trim(const Vector& trimCoord,
1855 RS_AtomicEntity* trimEntity,
1856 const Vector& limitCoord,
1857 RS_Entity* limitEntity,
1860 if (trimEntity==NULL || limitEntity==NULL) {
1861 RS_DEBUG->print(RS_Debug::D_WARNING,
1862 "RS_Modification::trim: At least one entity is NULL");
1866 if (both && !limitEntity->isAtomic()) {
1867 RS_DEBUG->print(RS_Debug::D_WARNING,
1868 "RS_Modification::trim: limitEntity is not atomic");
1871 VectorSolutions sol;
1872 if (limitEntity->isAtomic()) {
1873 // intersection(s) of the two entities:
1874 sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1875 } else if (limitEntity->isContainer()) {
1876 RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1881 for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1882 e=ec->nextEntity(RS2::ResolveAll)) {
1883 //for (int i=0; i<container->count(); ++i) {
1884 // RS_Entity* e = container->entityAt(i);
1888 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1891 if (s2.hasValid()) {
1892 for (int k=0; k<s2.getNumber(); ++k) {
1893 if (i<128 && s2.get(k).valid) {
1894 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1895 sol.set(i++, s2.get(k));
1905 if (sol.hasValid()==false) {
1909 RS_AtomicEntity* trimmed1 = NULL;
1910 RS_AtomicEntity* trimmed2 = NULL;
1912 // remove trim entity from view:
1913 if (trimEntity->rtti()==RS2::EntityCircle) {
1914 // convert a circle into a trimmable arc
1915 RS_Circle* c = (RS_Circle*)trimEntity;
1916 double am = c->getCenter().angleTo(trimCoord);
1917 RS_ArcData d(c->getCenter(),
1919 RS_Math::correctAngle(am-M_PI/2),
1920 RS_Math::correctAngle(am+M_PI/2), false);
1921 trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1923 trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1924 trimmed1->setHighlighted(false);
1926 if (graphicView!=NULL) {
1927 graphicView->deleteEntity(trimEntity);
1930 // remove limit entity from view:
1932 trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1933 trimmed2->setHighlighted(false);
1934 if (graphicView!=NULL) {
1935 graphicView->deleteEntity(limitEntity);
1941 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1942 //sol.getClosest(limitCoord, NULL, &ind);
1943 RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1944 RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1945 RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1946 RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1947 Vector is2 = sol.get(ind==0 ? 1 : 0);
1948 //Vector is2 = sol.get(ind);
1949 RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1951 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1952 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1955 case RS2::EndingStart:
1956 trimmed1->trimStartpoint(is);
1957 if (trimEntity->rtti()==RS2::EntityCircle) {
1958 trimmed1->trimEndpoint(is2);
1961 case RS2::EndingEnd:
1962 trimmed1->trimEndpoint(is);
1963 if (trimEntity->rtti()==RS2::EntityCircle) {
1964 trimmed1->trimStartpoint(is2);
1971 // trim limit entity:
1973 Vector is = sol.getClosest(limitCoord);
1975 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1978 case RS2::EndingStart:
1979 trimmed2->trimStartpoint(is);
1981 case RS2::EndingEnd:
1982 trimmed2->trimEndpoint(is);
1989 // add new trimmed trim entity:
1990 container->addEntity(trimmed1);
1991 if (graphicView!=NULL) {
1992 graphicView->drawEntity(trimmed1);
1995 // add new trimmed limit entity:
1997 container->addEntity(trimmed2);
1998 if (graphicView!=NULL) {
1999 graphicView->drawEntity(trimmed2);
2003 if (document!=NULL && handleUndo) {
2004 document->startUndoCycle();
2005 document->addUndoable(trimmed1);
2006 trimEntity->setUndoState(true);
2007 document->addUndoable(trimEntity);
2009 document->addUndoable(trimmed2);
2010 limitEntity->setUndoState(true);
2011 document->addUndoable(limitEntity);
2013 document->endUndoCycle();
2022 * Trims or extends the given trimEntity by the given amount.
2024 * @param trimCoord Coordinate which defines which endpoint of the
2025 * trim entity to trim.
2026 * @param trimEntity Entity which will be trimmed.
2027 * @param dist Amount to trim by.
2029 bool RS_Modification::trimAmount(const Vector& trimCoord,
2030 RS_AtomicEntity* trimEntity,
2033 if (trimEntity==NULL) {
2034 RS_DEBUG->print(RS_Debug::D_WARNING,
2035 "RS_Modification::trimAmount: Entity is NULL");
2039 RS_AtomicEntity* trimmed = NULL;
2041 // remove trim entity:
2042 trimmed = (RS_AtomicEntity*)trimEntity->clone();
2043 if (graphicView!=NULL) {
2044 graphicView->deleteEntity(trimEntity);
2048 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2049 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2050 trimCoord.distanceTo(trimmed->getEndpoint())) {
2051 trimmed->trimStartpoint(is);
2053 trimmed->trimEndpoint(is);
2056 // add new trimmed trim entity:
2057 container->addEntity(trimmed);
2059 if (graphicView!=NULL) {
2060 graphicView->drawEntity(trimmed);
2063 if (document!=NULL && handleUndo) {
2064 document->startUndoCycle();
2065 document->addUndoable(trimmed);
2066 trimEntity->setUndoState(true);
2067 document->addUndoable(trimEntity);
2068 document->endUndoCycle();
2077 * Cuts the given entity at the given point.
2079 bool RS_Modification::cut(const Vector& cutCoord,
2080 RS_AtomicEntity* cutEntity) {
2082 if (cutEntity==NULL) {
2083 RS_DEBUG->print(RS_Debug::D_WARNING,
2084 "RS_Modification::cut: Entity is NULL");
2088 if (!cutCoord.valid) {
2089 RS_DEBUG->print(RS_Debug::D_WARNING,
2090 "RS_Modification::cut: Point invalid.");
2094 // cut point is at endpoint of entity:
2095 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2096 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2097 RS_DEBUG->print(RS_Debug::D_WARNING,
2098 "RS_Modification::cut: Cutting point on endpoint");
2102 // delete cut entity on the screen:
2103 if (graphicView!=NULL) {
2104 graphicView->deleteEntity(cutEntity);
2107 RS_AtomicEntity* cut1 = NULL;
2108 RS_AtomicEntity* cut2 = NULL;
2110 // create new two halves:
2111 if (cutEntity->rtti()==RS2::EntityCircle) {
2112 RS_Circle* c = (RS_Circle*)cutEntity;
2113 cut1 = new RS_Arc(cutEntity->getParent(),
2114 RS_ArcData(c->getCenter(),
2117 cut1->setPen(cutEntity->getPen());
2118 cut1->setLayer(cutEntity->getLayer());
2121 cut1->trimEndpoint(cutCoord);
2122 cut1->trimStartpoint(cutCoord);
2124 cut1 = (RS_AtomicEntity*)cutEntity->clone();
2125 cut2 = (RS_AtomicEntity*)cutEntity->clone();
2127 cut1->trimEndpoint(cutCoord);
2128 cut2->trimStartpoint(cutCoord);
2131 // add new cut entity:
2132 container->addEntity(cut1);
2134 container->addEntity(cut2);
2137 if (graphicView!=NULL) {
2138 graphicView->drawEntity(cut1);
2140 graphicView->drawEntity(cut2);
2144 if (document!=NULL && handleUndo) {
2145 document->startUndoCycle();
2146 document->addUndoable(cut1);
2148 document->addUndoable(cut2);
2150 cutEntity->setUndoState(true);
2151 document->addUndoable(cutEntity);
2152 document->endUndoCycle();
2163 bool RS_Modification::stretch(const Vector& firstCorner,
2164 const Vector& secondCorner,
2165 const Vector& offset) {
2167 if (!offset.valid) {
2168 RS_DEBUG->print(RS_Debug::D_WARNING,
2169 "RS_Modification::stretch: Offset invalid");
2173 RS_PtrList<RS_Entity> addList;
2174 addList.setAutoDelete(false);
2176 if (document!=NULL && handleUndo) {
2177 document->startUndoCycle();
2180 // Create new entites
2181 for (RS_Entity* e=container->firstEntity();
2183 e=container->nextEntity()) {
2184 //for (int i=0; i<container->count(); ++i) {
2185 // RS_Entity* e = container->entityAt(i);
2190 (e->isInWindow(firstCorner, secondCorner) ||
2191 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2193 RS_Entity* ec = e->clone();
2194 ec->stretch(firstCorner, secondCorner, offset);
2196 e->setSelected(true);
2200 deselectOriginals(true);
2201 addNewEntities(addList);
2203 if (document!=NULL && handleUndo) {
2204 document->endUndoCycle();
2207 if (graphicView!=NULL) {
2208 graphicView->redraw();
2218 * @param coord1 Mouse coordinate to specify direction from intersection.
2219 * @param entity1 First entity of the corner.
2220 * @param coord2 Mouse coordinate to specify direction from intersection.
2221 * @param entity2 Second entity of the corner.
2222 * @param data Lengths and trim flag.
2224 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2225 const Vector& coord2, RS_AtomicEntity* entity2,
2226 RS_BevelData& data) {
2228 RS_DEBUG->print("RS_Modification::bevel");
2230 if (entity1==NULL || entity2==NULL) {
2231 RS_DEBUG->print(RS_Debug::D_WARNING,
2232 "RS_Modification::bevel: At least one entity is NULL");
2236 RS_EntityContainer* baseContainer = container;
2237 bool isPolyline = false;
2238 bool isClosedPolyline = false;
2240 if (document!=NULL && handleUndo) {
2241 document->startUndoCycle();
2244 // find out whether we're bevelling within a polyline:
2245 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2246 RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2247 if (entity1->getParent()!=entity2->getParent()) {
2248 RS_DEBUG->print(RS_Debug::D_WARNING,
2249 "RS_Modification::bevel: entities not in the same polyline");
2252 // clone polyline for undo
2253 if (document!=NULL && handleUndo) {
2254 RS_EntityContainer* cl =
2255 (RS_EntityContainer*)entity1->getParent()->clone();
2256 container->addEntity(cl);
2257 //cl->setUndoState(true);
2258 document->addUndoable(cl);
2260 document->addUndoable(entity1->getParent());
2261 entity1->getParent()->setUndoState(true);
2266 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2267 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2269 //baseContainer = entity1->getParent();
2271 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2274 RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2276 VectorSolutions sol =
2277 RS_Information::getIntersection(entity1, entity2, false);
2279 if (sol.getNumber()==0) {
2283 RS_AtomicEntity* trimmed1 = NULL;
2284 RS_AtomicEntity* trimmed2 = NULL;
2286 //if (data.trim || isPolyline) {
2291 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2292 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2295 // remove trim entity (on screen):
2296 if (data.trim==true || isPolyline) {
2297 if (graphicView!=NULL) {
2299 graphicView->deleteEntity(baseContainer);
2301 graphicView->deleteEntity(entity1);
2302 graphicView->deleteEntity(entity2);
2307 // trim entities to intersection
2308 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2309 bool start1 = false;
2310 Vector is = sol.getClosest(coord2);
2311 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2313 case RS2::EndingStart:
2314 trimmed1->trimStartpoint(is);
2317 case RS2::EndingEnd:
2318 trimmed1->trimEndpoint(is);
2325 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2326 bool start2 = false;
2327 is = sol.getClosest(coord1);
2328 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2330 case RS2::EndingStart:
2331 trimmed2->trimStartpoint(is);
2334 case RS2::EndingEnd:
2335 trimmed2->trimEndpoint(is);
2344 // find definitive bevel points
2345 RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2346 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2347 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2350 RS_DEBUG->print("RS_Modification::bevel: final trim");
2351 if (data.trim==true) {
2353 case RS2::EndingStart:
2354 trimmed1->trimStartpoint(bp1);
2356 case RS2::EndingEnd:
2357 trimmed1->trimEndpoint(bp1);
2364 case RS2::EndingStart:
2365 trimmed2->trimStartpoint(bp2);
2367 case RS2::EndingEnd:
2368 trimmed2->trimEndpoint(bp2);
2374 // add new trimmed entities:
2375 if (isPolyline==false) {
2376 container->addEntity(trimmed1);
2377 container->addEntity(trimmed2);
2379 if (graphicView!=NULL) {
2381 graphicView->drawEntity(trimmed1);
2382 graphicView->drawEntity(trimmed2);
2389 RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2390 RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2392 if (isPolyline==false) {
2393 baseContainer->addEntity(bevel);
2395 int idx1 = baseContainer->findEntity(trimmed1);
2396 int idx2 = baseContainer->findEntity(trimmed2);
2398 bevel->setSelected(baseContainer->isSelected());
2399 bevel->setLayer(baseContainer->getLayer());
2400 bevel->setPen(baseContainer->getPen());
2402 bool insertAfter1 = false;
2403 if (!isClosedPolyline) {
2404 insertAfter1 = (idx1<idx2);
2407 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2408 (idx2==0 && idx1==(int)baseContainer->count()-1));
2411 // insert bevel at the right position:
2412 //if ((idx1<idx2 && idx1!=0) ||
2413 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2415 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2418 baseContainer->insertEntity(idx1+1, bevel);
2420 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2423 baseContainer->insertEntity(idx2+1, bevel);
2428 ((RS_Polyline*)baseContainer)->updateEndpoints();
2431 if (graphicView!=NULL) {
2433 graphicView->drawEntity(baseContainer);
2435 graphicView->drawEntity(bevel);
2439 RS_DEBUG->print("RS_Modification::bevel: handling undo");
2441 if (document!=NULL && handleUndo) {
2442 //document->startUndoCycle();
2444 if (isPolyline==false && data.trim==true) {
2445 document->addUndoable(trimmed1);
2446 entity1->setUndoState(true);
2447 document->addUndoable(entity1);
2449 document->addUndoable(trimmed2);
2450 entity2->setUndoState(true);
2451 document->addUndoable(entity2);
2454 if (isPolyline==false) {
2455 document->addUndoable(bevel);
2458 document->endUndoCycle();
2461 if (data.trim==false) {
2462 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2465 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2477 * @param coord Mouse coordinate to specify the rounding.
2478 * @param entity1 First entity of the corner.
2479 * @param entity2 Second entity of the corner.
2480 * @param data Radius and trim flag.
2482 bool RS_Modification::round(const Vector& coord,
2483 const Vector& coord1,
2484 RS_AtomicEntity* entity1,
2485 const Vector& coord2,
2486 RS_AtomicEntity* entity2,
2487 RS_RoundData& data) {
2489 if (entity1==NULL || entity2==NULL) {
2490 RS_DEBUG->print(RS_Debug::D_WARNING,
2491 "RS_Modification::round: At least one entity is NULL");
2495 RS_EntityContainer* baseContainer = container;
2496 bool isPolyline = false;
2497 bool isClosedPolyline = false;
2499 if (document!=NULL && handleUndo) {
2500 document->startUndoCycle();
2503 // find out whether we're rounding within a polyline:
2504 if (entity1->getParent()!=NULL &&
2505 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2507 if (entity1->getParent()!=entity2->getParent()) {
2508 RS_DEBUG->print(RS_Debug::D_WARNING,
2509 "RS_Modification::round: entities not in "
2510 "the same polyline");
2511 if (document!=NULL && handleUndo) {
2512 document->endUndoCycle();
2517 // clone polyline for undo
2518 if (document!=NULL && handleUndo) {
2519 RS_EntityContainer* cl =
2520 (RS_EntityContainer*)entity1->getParent()->clone();
2521 container->addEntity(cl);
2522 document->addUndoable(cl);
2524 document->addUndoable(entity1->getParent());
2525 entity1->getParent()->setUndoState(true);
2530 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2531 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2534 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2537 // create 2 tmp parallels
2538 RS_Creation creation(NULL, NULL);
2539 RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2540 RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2542 VectorSolutions sol2 =
2543 RS_Information::getIntersection(entity1, entity2, false);
2545 VectorSolutions sol =
2546 RS_Information::getIntersection(par1, par2, false);
2548 if (sol.getNumber()==0) {
2549 if (document!=NULL && handleUndo) {
2550 document->endUndoCycle();
2555 // there might be two intersections: choose the closest:
2556 Vector is = sol.getClosest(coord);
2557 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2558 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2559 double ang1 = is.angleTo(p1);
2560 double ang2 = is.angleTo(p2);
2561 bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2563 RS_Arc* arc = new RS_Arc(baseContainer,
2570 RS_AtomicEntity* trimmed1 = NULL;
2571 RS_AtomicEntity* trimmed2 = NULL;
2573 if (data.trim || isPolyline) {
2578 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2579 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2582 // remove trim entity:
2583 if (graphicView!=NULL) {
2585 graphicView->deleteEntity(baseContainer);
2587 graphicView->deleteEntity(entity1);
2588 graphicView->deleteEntity(entity2);
2592 // trim entities to intersection
2593 Vector is2 = sol2.getClosest(coord2);
2594 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2596 case RS2::EndingStart:
2597 trimmed1->trimStartpoint(p1);
2599 case RS2::EndingEnd:
2600 trimmed1->trimEndpoint(p1);
2606 is2 = sol2.getClosest(coord1);
2607 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2609 case RS2::EndingStart:
2610 trimmed2->trimStartpoint(p2);
2612 case RS2::EndingEnd:
2613 trimmed2->trimEndpoint(p2);
2619 // add new trimmed entities:
2620 if (isPolyline==false) {
2621 container->addEntity(trimmed1);
2622 container->addEntity(trimmed2);
2624 if (graphicView!=NULL) {
2626 graphicView->drawEntity(trimmed1);
2627 graphicView->drawEntity(trimmed2);
2633 if (isPolyline==false) {
2634 baseContainer->addEntity(arc);
2636 // find out which base entity is before the rounding:
2637 int idx1 = baseContainer->findEntity(trimmed1);
2638 int idx2 = baseContainer->findEntity(trimmed2);
2640 arc->setSelected(baseContainer->isSelected());
2641 arc->setLayer(baseContainer->getLayer());
2642 arc->setPen(baseContainer->getPen());
2644 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2645 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2646 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2647 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2648 (int)(idx1==(int)baseContainer->count()-1));
2650 bool insertAfter1 = false;
2651 if (!isClosedPolyline) {
2652 insertAfter1 = (idx1<idx2);
2655 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2656 (idx2==0 && idx1==(int)baseContainer->count()-1));
2659 // insert rounding at the right position:
2660 //if ((idx1<idx2 && idx1!=0) ||
2661 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2664 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2667 baseContainer->insertEntity(idx1+1, arc);
2669 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2672 baseContainer->insertEntity(idx2+1, arc);
2677 ((RS_Polyline*)baseContainer)->updateEndpoints();
2680 if (graphicView!=NULL) {
2682 graphicView->drawEntity(baseContainer);
2684 graphicView->drawEntity(arc);
2688 if (document!=NULL && handleUndo) {
2689 if (isPolyline==false && data.trim==true) {
2690 document->addUndoable(trimmed1);
2691 entity1->setUndoState(true);
2692 document->addUndoable(entity1);
2694 document->addUndoable(trimmed2);
2695 entity2->setUndoState(true);
2696 document->addUndoable(entity2);
2699 if (isPolyline==false) {
2700 document->addUndoable(arc);
2703 document->endUndoCycle();
2715 * Removes the selected entity containers and adds the entities in them as
2716 * new single entities.
2718 bool RS_Modification::explode() {
2720 if (container==NULL) {
2721 RS_DEBUG->print("RS_Modification::explode: no valid container"
2722 " for addinge entities",
2723 RS_Debug::D_WARNING);
2727 RS_PtrList<RS_Entity> addList;
2728 addList.setAutoDelete(false);
2730 if (document!=NULL && handleUndo) {
2731 document->startUndoCycle();
2734 for (RS_Entity* e=container->firstEntity();
2736 e=container->nextEntity()) {
2737 //for (uint i=0; i<container->count(); ++i) {
2738 //RS_Entity* e = container->entityAt(i);
2740 if (e!=NULL && e->isSelected()) {
2741 if (e->isContainer()) {
2743 // add entities from container:
2744 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2745 //ec->setSelected(false);
2747 // iterate and explode container:
2748 //for (uint i2=0; i2<ec->count(); ++i2) {
2749 // RS_Entity* e2 = ec->entityAt(i2);
2750 RS2::ResolveLevel rl;
2754 switch (ec->rtti()) {
2755 case RS2::EntityText:
2756 case RS2::EntityHatch:
2757 case RS2::EntityPolyline:
2758 rl = RS2::ResolveAll;
2759 resolveLayer = true;
2763 case RS2::EntityInsert:
2765 resolveLayer = false;
2766 rl = RS2::ResolveNone;
2769 case RS2::EntityDimAligned:
2770 case RS2::EntityDimLinear:
2771 case RS2::EntityDimRadial:
2772 case RS2::EntityDimDiametric:
2773 case RS2::EntityDimAngular:
2774 case RS2::EntityDimLeader:
2775 rl = RS2::ResolveNone;
2776 resolveLayer = true;
2781 rl = RS2::ResolveAll;
2782 resolveLayer = true;
2787 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2788 e2 = ec->nextEntity(rl)) {
2791 RS_Entity* clone = e2->clone();
2792 clone->setSelected(false);
2793 clone->reparent(container);
2796 clone->setLayer(ec->getLayer());
2798 clone->setLayer(e2->getLayer());
2801 clone->setPen(ec->getPen(resolvePen));
2803 addList.append(clone);
2809 e->setSelected(false);
2814 deselectOriginals(true);
2815 addNewEntities(addList);
2817 if (document!=NULL && handleUndo) {
2818 document->endUndoCycle();
2821 if (graphicView!=NULL) {
2822 graphicView->redraw();
2830 bool RS_Modification::explodeTextIntoLetters() {
2831 if (container==NULL) {
2832 RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2833 " for addinge entities",
2834 RS_Debug::D_WARNING);
2838 RS_PtrList<RS_Entity> addList;
2839 addList.setAutoDelete(false);
2841 if (document!=NULL && handleUndo) {
2842 document->startUndoCycle();
2845 for (RS_Entity* e=container->firstEntity();
2847 e=container->nextEntity()) {
2848 if (e!=NULL && e->isSelected()) {
2849 if (e->rtti()==RS2::EntityText) {
2850 // add letters of text:
2851 RS_Text* text = (RS_Text*)e;
2852 explodeTextIntoLetters(text, addList);
2854 e->setSelected(false);
2859 deselectOriginals(true);
2860 addNewEntities(addList);
2862 if (document!=NULL && handleUndo) {
2863 document->endUndoCycle();
2866 if (graphicView!=NULL) {
2867 graphicView->redraw();
2875 bool RS_Modification::explodeTextIntoLetters(RS_Text* text, RS_PtrList<RS_Entity>& addList) {
2881 // iterate though lines:
2882 for (RS_Entity* e2 = text->firstEntity(); e2!=NULL;
2883 e2 = text->nextEntity()) {
2891 if (e2->rtti()==RS2::EntityContainer) {
2893 RS_EntityContainer* line = (RS_EntityContainer*)e2;
2895 // iterate though letters:
2896 for (RS_Entity* e3 = line->firstEntity(); e3!=NULL;
2897 e3 = line->nextEntity()) {
2903 // super / sub texts:
2904 if (e3->rtti()==RS2::EntityText) {
2905 explodeTextIntoLetters((RS_Text*)e3, addList);
2909 else if (e3->rtti()==RS2::EntityInsert) {
2911 RS_Insert* letter = (RS_Insert*)e3;
2913 RS_Text* tl = new RS_Text(
2915 RS_TextData(letter->getInsertionPoint(),
2918 RS2::VAlignBottom, RS2::HAlignLeft,
2919 RS2::LeftToRight, RS2::Exact,
2926 tl->setLayer(text->getLayer());
2927 tl->setPen(text->getPen());
2942 * Moves all reference points of selected entities with the given data.
2944 bool RS_Modification::moveRef(RS_MoveRefData& data) {
2945 if (container==NULL) {
2946 RS_DEBUG->print("RS_Modification::moveRef: no valid container",
2947 RS_Debug::D_WARNING);
2951 RS_PtrList<RS_Entity> addList;
2952 addList.setAutoDelete(false);
2954 if (document!=NULL && handleUndo) {
2955 document->startUndoCycle();
2958 // Create new entites
2959 for (RS_Entity* e=container->firstEntity();
2961 e=container->nextEntity()) {
2962 if (e!=NULL && e->isSelected()) {
2963 RS_Entity* ec = e->clone();
2965 ec->moveRef(data.ref, data.offset);
2966 // since 2.0.4.0: keep it selected
2967 ec->setSelected(true);
2972 deselectOriginals(true);
2973 addNewEntities(addList);
2975 if (document!=NULL && handleUndo) {
2976 document->endUndoCycle();
2979 if (graphicView!=NULL) {
2980 graphicView->redraw();