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, const bool cut)
210 if (e && e->isSelected())
212 // delete entity in graphic view:
215 #warning "!!! Old rendering path needs upgrading !!!"
218 graphicView->deleteEntity(e);
221 e->setSelected(false);
225 #warning "!!! Old rendering path needs upgrading !!!"
228 graphicView->deleteEntity(e);
231 e->setSelected(false);
233 #warning "!!! Old rendering path needs upgrading !!!"
236 graphicView->drawEntity(e);
240 // add entity to clipboard:
241 RS_Entity * c = e->clone();
243 RS_CLIPBOARD->addEntity(c);
248 // set layer to the layer clone:
249 RS_Layer * l = e->getLayer();
252 c->setLayer(l->getName());
254 // make sure all sub entities point to layers of the clipboard
255 if (c->isContainer())
257 RS_EntityContainer * ec = (RS_EntityContainer *)c;
259 for(RS_Entity * e2=ec->firstEntity(RS2::ResolveAll); e2!=NULL;
260 e2=ec->nextEntity(RS2::ResolveAll))
262 //RS_Entity* e2 = ec->entityAt(i);
263 RS_Layer * l2 = e2->getLayer();
266 e2->setLayer(l2->getName());
272 e->changeUndoState();
275 document->addUndoable(e);
283 * Copies all layers of the given entity to the clipboard.
285 void RS_Modification::copyLayers(RS_Entity* e) {
291 // add layer(s) of the entity if it's not an insert
292 // (inserts are on layer '0'):
293 if (e->rtti()!=RS2::EntityInsert) {
294 RS_Layer* l = e->getLayer();
296 if (!RS_CLIPBOARD->hasLayer(l->getName())) {
297 RS_CLIPBOARD->addLayer(l->clone());
302 // special handling of inserts:
304 // insert: add layer(s) of subentities:
305 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
307 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
308 e2=b->nextEntity()) {
309 //for (uint i=0; i<b->count(); ++i) {
310 //RS_Entity* e2 = b->entityAt(i);
320 * Copies all blocks of the given entity to the clipboard.
322 void RS_Modification::copyBlocks(RS_Entity* e) {
328 // add block of the entity if it's an insert
329 if (e->rtti()==RS2::EntityInsert) {
330 RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
332 // add block of an insert:
333 if (!RS_CLIPBOARD->hasBlock(b->getName())) {
334 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
337 for (RS_Entity* e2=b->firstEntity(); e2!=NULL;
338 e2=b->nextEntity()) {
339 //for (uint i=0; i<b->count(); ++i) {
340 //RS_Entity* e2 = b->entityAt(i);
350 * Pastes all entities from the clipboard into the container.
351 * Layers and blocks that are needed are also copied if the container is
352 * or is part of an Drawing.
354 * @param data Paste data.
355 * @param source The source from where to paste. NULL means the source
358 void RS_Modification::paste(const RS_PasteData& data, Drawing* source) {
361 RS_DEBUG->print(RS_Debug::D_WARNING,
362 "RS_Modification::paste: Graphic is NULL");
369 source = RS_CLIPBOARD->getGraphic();
371 // graphics from the clipboard need to be scaled. from the part lib not:
372 RS2::Unit sourceUnit = source->getUnit();
373 RS2::Unit targetUnit = graphic->getUnit();
374 factor = RS_Units::convert(1.0, sourceUnit, targetUnit);
377 if (document!=NULL) {
378 document->startUndoCycle();
384 RS_Layer* layer = graphic->getActiveLayer();
385 for(uint i=0; i<source->countLayers(); ++i) {
386 RS_Layer* l = source->layerAt(i);
388 if (graphic->findLayer(l->getName())==NULL) {
389 graphic->addLayer(l->clone());
393 graphic->activateLayer(layer);
398 for(uint i=0; i<source->countBlocks(); ++i) {
399 RS_Block* b = source->blockAt(i);
401 if (graphic->findBlock(b->getName())==NULL) {
402 RS_Block* bc = (RS_Block*)b->clone();
403 bc->reparent(container);
404 //bc->scale(bc->getBasePoint(), Vector(factor, factor));
405 // scale block but don't scale inserts in block
406 // (they already scale with their block)
407 for(uint i2=0; i2<bc->count(); ++i2) {
408 RS_Entity* e = bc->entityAt(i2);
409 if (e!=NULL && e->rtti()!=RS2::EntityInsert) {
410 e->scale(bc->getBasePoint(),
411 Vector(factor, factor));
413 Vector ip = ((RS_Insert*)e)->getInsertionPoint();
414 ip.scale(bc->getBasePoint(),
415 Vector(factor, factor));
416 ((RS_Insert*)e)->setInsertionPoint(ip);
421 graphic->addBlock(bc);
427 // add entities to this host (graphic or a new block)
428 RS_EntityContainer* host = container;
433 if (data.asInsert==true) {
434 RS_BlockList* blkList = graphic->getBlockList();
436 blockName = blkList->newName(data.blockName);
439 new RS_Block(graphic,
440 RS_BlockData(blockName,
441 Vector(0.0,0.0), false));
442 graphic->addBlock(blk);
450 //for (uint i=0; i<((RS_EntityContainer*)source)->count(); ++i) {
451 //RS_Entity* e = source->entityAt(i);
452 for (RS_Entity* e=((RS_EntityContainer*)source)->firstEntity();
454 e=((RS_EntityContainer*)source)->nextEntity()) {
458 QString layerName = "0";
459 RS_Layer* layer = e->getLayer();
461 layerName = layer->getName();
463 RS_Entity* e2 = e->clone();
465 if (data.asInsert==false) {
466 e2->move(data.insertionPoint);
468 // don't adjust insert factor - block was already adjusted to unit
469 if (e2->rtti()==RS2::EntityInsert) {
470 Vector ip = ((RS_Insert*)e2)->getInsertionPoint();
471 ip.scale(data.insertionPoint, Vector(factor, factor));
472 ((RS_Insert*)e2)->setInsertionPoint(ip);
475 e2->scale(data.insertionPoint, Vector(factor, factor));
478 e2->setLayer(layerName);
480 // make sure all sub entities point to layers of the container
481 if (e2->isContainer()) {
482 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
484 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
485 e3 = ec->nextEntity(RS2::ResolveAll)) {
487 //RS_Entity* e3 = ec->entityAt(i);
488 RS_Layer* l2 = e3->getLayer();
490 e3->setLayer(l2->getName());
495 if (document!=NULL && data.asInsert==false) {
496 document->addUndoable(e2);
501 if (data.asInsert==true) {
503 new RS_Insert(container,
507 Vector(data.factor, data.factor),
509 1,1,Vector(0.0,0.0)));
510 container->addEntity(ins);
511 ins->setLayerToActive();
512 ins->setPenToActive();
514 if (document!=NULL) {
515 document->addUndoable(ins);
519 if (document!=NULL) {
520 document->endUndoCycle();
526 * Splits a polyline into two leaving out a gap.
528 * @param polyline The original polyline
529 * @param e1 1st entity on which the first cutting point is.
530 * @param v1 1st cutting point.
531 * @param e2 2nd entity on which the first cutting point is.
532 * @param v2 2nd cutting point.
533 * @param polyline1 Pointer to a polyline pointer which will hold the
534 * 1st resulting new polyline. Pass NULL if you don't
535 * need those pointers.
536 * @param polyline2 Pointer to a polyline pointer which will hold the
537 * 2nd resulting new polyline. Pass NULL if you don't
538 * need those pointers.
540 * @todo Support arcs in polylines, check for wrong parameters
544 bool RS_Modification::splitPolyline(RS_Polyline& polyline,
545 RS_Entity& e1, Vector v1,
546 RS_Entity& e2, Vector v2,
547 RS_Polyline** polyline1,
548 RS_Polyline** polyline2) const {
550 if (container==NULL) {
551 RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
552 RS_Debug::D_WARNING);
556 RS_Entity* firstEntity = polyline.firstEntity();
557 Vector firstPoint(false);
558 if (firstEntity->rtti()==RS2::EntityLine) {
559 firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
562 new RS_Polyline(container,
563 RS_PolylineData(firstPoint, Vector(0.0,0.0), 0));
564 RS_Polyline* pl2 = new RS_Polyline(container);
565 RS_Polyline* pl = pl1; // Current polyline
566 RS_Line* line = NULL;
569 if (polyline1!=NULL) {
572 if (polyline2!=NULL) {
576 for (RS_Entity* e = polyline.firstEntity();
578 e = polyline.nextEntity()) {
580 if (e->rtti()==RS2::EntityLine) {
583 } else if (e->rtti()==RS2::EntityArc) {
591 if (line!=NULL /*|| arc!=NULL*/) {
593 if (e==&e1 && e==&e2) {
594 // Trim within a single entity:
595 Vector sp = line->getStartpoint();
596 double dist1 = (v1-sp).magnitude();
597 double dist2 = (v2-sp).magnitude();
598 pl->addVertex(dist1<dist2 ? v1 : v2, 0.0);
600 pl->setStartpoint(dist1<dist2 ? v2 : v1);
601 pl->addVertex(line->getEndpoint(), 0.0);
602 } else if (e==&e1 || e==&e2) {
604 Vector v = (e==&e1 ? v1 : v2);
606 // Trim endpoint of entity to first vector
607 pl->addVertex(v, 0.0);
610 // Trim startpoint of entity to second vector
612 pl->setStartpoint(v);
613 pl->addVertex(line->getEndpoint(), 0.0);
616 // Add entities to polylines
617 if (line!=NULL && pl!=NULL) {
618 pl->addVertex(line->getEndpoint(), 0.0);
624 container->addEntity(pl1);
625 container->addEntity(pl2);
626 //container->removeEntity(&polyline);
627 polyline.changeUndoState();
635 * Adds a node to the given polyline. The new node is placed between
636 * the start and end point of the given segment.
638 * @param node The position of the new node.
640 * @return Pointer to the new polyline or NULL.
643 RS_Polyline* RS_Modification::addPolylineNode(RS_Polyline& polyline,
644 const RS_AtomicEntity& segment,
645 const Vector& node) {
646 RS_DEBUG->print("RS_Modification::addPolylineNode");
648 if (container==NULL) {
649 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
650 RS_Debug::D_WARNING);
654 if (segment.getParent()!=&polyline) {
655 RS_DEBUG->print("RS_Modification::addPolylineNode: "
656 "segment not part of the polyline",
657 RS_Debug::D_WARNING);
661 RS_Polyline* newPolyline = new RS_Polyline(container);
662 newPolyline->setClosed(polyline.isClosed());
663 newPolyline->setSelected(polyline.isSelected());
664 newPolyline->setLayer(polyline.getLayer());
665 newPolyline->setPen(polyline.getPen());
667 // copy polyline and add new node:
669 RS_Entity* lastEntity = polyline.lastEntity();
670 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
671 e=polyline.nextEntity()) {
674 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
676 if (ae->rtti()==RS2::EntityArc) {
677 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
678 bulge = ((RS_Arc*)ae)->getBulge();
680 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
685 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
686 ae->getStartpoint().x, ae->getStartpoint().y);
688 newPolyline->setNextBulge(bulge);
689 newPolyline->addVertex(ae->getStartpoint());
695 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
697 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
700 newPolyline->setNextBulge(0.0);
701 newPolyline->addVertex(node);
703 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
704 ae->getEndpoint().x, ae->getEndpoint().y);
706 if (ae!=lastEntity || polyline.isClosed()==false) {
707 newPolyline->setNextBulge(0.0);
708 newPolyline->addVertex(ae->getEndpoint());
711 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
712 ae->getEndpoint().x, ae->getEndpoint().y);
714 if (ae!=lastEntity || polyline.isClosed()==false) {
715 newPolyline->setNextBulge(bulge);
716 newPolyline->addVertex(ae->getEndpoint());
720 RS_DEBUG->print("RS_Modification::addPolylineNode: "
721 "Polyline contains non-atomic entities",
722 RS_Debug::D_WARNING);
726 newPolyline->setNextBulge(polyline.getClosingBulge());
727 newPolyline->endPolyline();
730 container->addEntity(newPolyline);
731 if (graphicView!=NULL) {
732 graphicView->deleteEntity(&polyline);
733 graphicView->drawEntity(newPolyline);
736 if (document!=NULL && handleUndo) {
737 document->startUndoCycle();
739 polyline.setUndoState(true);
740 document->addUndoable(&polyline);
741 document->addUndoable(newPolyline);
743 document->endUndoCycle();
753 * Deletes a node from a polyline.
755 * @param node The node to delete.
757 * @return Pointer to the new polyline or NULL.
760 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
761 const Vector& node) {
763 RS_DEBUG->print("RS_Modification::deletePolylineNode");
765 if (container==NULL) {
766 RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
767 RS_Debug::D_WARNING);
771 if (node.valid==false) {
772 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
774 RS_Debug::D_WARNING);
778 // check if the polyline is no longer there after deleting the node:
779 if (polyline.count()==1) {
780 RS_Entity* e = polyline.firstEntity();
781 if (e!=NULL && e->isAtomic()) {
782 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
783 if (node.distanceTo(ae->getStartpoint())<1.0e-6 ||
784 node.distanceTo(ae->getEndpoint())<1.0e-6) {
786 if (graphicView!=NULL) {
787 graphicView->deleteEntity(&polyline);
790 if (document!=NULL && handleUndo) {
791 document->startUndoCycle();
792 polyline.setUndoState(true);
793 document->addUndoable(&polyline);
794 document->endUndoCycle();
801 RS_Polyline* newPolyline = new RS_Polyline(container);
802 newPolyline->setClosed(polyline.isClosed());
803 newPolyline->setSelected(polyline.isSelected());
804 newPolyline->setLayer(polyline.getLayer());
805 newPolyline->setPen(polyline.getPen());
807 // copy polyline and drop deleted node:
809 bool lastDropped = false;
810 RS_Entity* lastEntity = polyline.lastEntity();
811 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
812 e=polyline.nextEntity()) {
815 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
817 if (ae->rtti()==RS2::EntityArc) {
818 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
819 bulge = ((RS_Arc*)ae)->getBulge();
821 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
825 // last entity is closing entity and will be added below with endPolyline()
826 if (e==lastEntity && polyline.isClosed()) {
830 // first vertex (startpoint)
831 if (first && node.distanceTo(ae->getStartpoint())>1.0e-6) {
832 RS_DEBUG->print("RS_Modification::deletePolylineNode: first node: %f/%f",
833 ae->getStartpoint().x, ae->getStartpoint().y);
835 newPolyline->setNextBulge(bulge);
836 newPolyline->addVertex(ae->getStartpoint());
840 // normal node (not deleted):
841 if (first==false && node.distanceTo(ae->getEndpoint())>1.0e-6) {
842 RS_DEBUG->print("RS_Modification::deletePolylineNode: normal vertex found: %f/%f",
843 ae->getEndpoint().x, ae->getEndpoint().y);
847 newPolyline->setNextBulge(bulge);
848 newPolyline->addVertex(ae->getEndpoint());
852 // drop deleted node:
854 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
855 ae->getEndpoint().x, ae->getEndpoint().y);
859 RS_DEBUG->print("RS_Modification::deletePolylineNode: "
860 "Polyline contains non-atomic entities",
861 RS_Debug::D_WARNING);
865 RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
866 newPolyline->setNextBulge(polyline.getClosingBulge());
867 newPolyline->endPolyline();
869 //if (newPolyline->count()==1) {
873 RS_DEBUG->print("RS_Modification::deletePolylineNode: adding new polyline");
874 container->addEntity(newPolyline);
875 if (graphicView!=NULL) {
876 graphicView->deleteEntity(&polyline);
877 graphicView->drawEntity(newPolyline);
880 RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
881 if (document!=NULL && handleUndo) {
882 document->startUndoCycle();
884 polyline.setUndoState(true);
885 document->addUndoable(&polyline);
886 document->addUndoable(newPolyline);
888 document->endUndoCycle();
898 * Deletes all nodes between the two given nodes (exclusive).
900 * @param node1 First limiting node.
901 * @param node2 Second limiting node.
903 * @return Pointer to the new polyline or NULL.
906 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
907 RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
909 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
911 if (container==NULL) {
912 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
913 RS_Debug::D_WARNING);
917 if (node1.valid==false || node2.valid==false) {
918 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
920 RS_Debug::D_WARNING);
924 if (node1.distanceTo(node2)<1.0e-6) {
925 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
926 "nodes are identical",
927 RS_Debug::D_WARNING);
931 // check if there's nothing to delete:
932 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
933 e=polyline.nextEntity()) {
936 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
938 if ((node1.distanceTo(ae->getStartpoint())<1.0e-6 &&
939 node2.distanceTo(ae->getEndpoint())<1.0e-6) ||
940 (node2.distanceTo(ae->getStartpoint())<1.0e-6 &&
941 node1.distanceTo(ae->getEndpoint())<1.0e-6)) {
943 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
945 RS_Debug::D_WARNING);
952 // check if the start point is involved:
953 bool startpointInvolved = false;
954 if (node1.distanceTo(polyline.getStartpoint())<1.0e-6 ||
955 node2.distanceTo(polyline.getStartpoint())<1.0e-6) {
956 startpointInvolved = true;
960 // check which part of the polyline has to be deleted:
961 bool deleteStart = false;
962 if (polyline.isClosed()) {
964 double length1 = 0.0;
965 double length2 = 0.0;
966 RS_Entity* e=polyline.firstEntity();
968 if (startpointInvolved) {
970 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
971 length1+=ae->getLength();
973 e = polyline.nextEntity();
975 for (; e!=NULL; e=polyline.nextEntity()) {
978 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
980 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
981 node2.distanceTo(ae->getStartpoint())<1.0e-6) {
987 length2+=ae->getLength();
989 length1+=ae->getLength();
993 if (length1<length2) {
1000 RS_Polyline* newPolyline = new RS_Polyline(container);
1001 newPolyline->setClosed(polyline.isClosed());
1002 newPolyline->setSelected(polyline.isSelected());
1003 newPolyline->setLayer(polyline.getLayer());
1004 newPolyline->setPen(polyline.getPen());
1006 if (startpointInvolved && deleteStart && polyline.isClosed()) {
1007 newPolyline->setNextBulge(0.0);
1008 newPolyline->addVertex(polyline.getStartpoint());
1011 // copy polyline and drop deleted nodes:
1013 bool removing = deleteStart;
1015 bool nextIsStraight = false;
1016 RS_Entity* lastEntity = polyline.lastEntity();
1019 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1020 e=polyline.nextEntity()) {
1022 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1023 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1025 if (e->isAtomic()) {
1026 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1027 if (ae->rtti()==RS2::EntityArc) {
1028 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: arc segment");
1029 bulge = ((RS_Arc*)ae)->getBulge();
1031 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1035 // last entity is closing entity and will be added below with endPolyline()
1036 if (e==lastEntity && polyline.isClosed()) {
1037 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1038 "dropping last vertex of closed polyline");
1042 // first vertex (startpoint)
1045 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: first node: %f/%f",
1046 ae->getStartpoint().x, ae->getStartpoint().y);
1047 newPolyline->setNextBulge(bulge);
1048 newPolyline->addVertex(ae->getStartpoint());
1053 // stop removing nodes:
1054 if (removing==true &&
1055 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1056 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1057 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1058 "stop removing at: %f/%f",
1059 ae->getEndpoint().x, ae->getEndpoint().y);
1063 nextIsStraight = true;
1067 // normal node (not deleted):
1068 if (removing==false && (done==false || deleteStart==false)) {
1069 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1070 "normal vertex found: %f/%f",
1071 ae->getEndpoint().x, ae->getEndpoint().y);
1072 if (nextIsStraight) {
1074 nextIsStraight = false;
1076 newPolyline->setNextBulge(bulge);
1077 newPolyline->addVertex(ae->getEndpoint());
1080 // drop deleted node:
1082 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1083 "deleting vertex: %f/%f",
1084 ae->getEndpoint().x, ae->getEndpoint().y);
1087 // start to remove nodes from now on:
1088 if (done==false && removing==false &&
1089 (node1.distanceTo(ae->getEndpoint())<1.0e-6 ||
1090 node2.distanceTo(ae->getEndpoint())<1.0e-6)) {
1091 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1092 "start removing at: %f/%f",
1093 ae->getEndpoint().x, ae->getEndpoint().y);
1101 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1102 "Polyline contains non-atomic entities",
1103 RS_Debug::D_WARNING);
1107 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1108 newPolyline->setNextBulge(polyline.getClosingBulge());
1109 newPolyline->endPolyline();
1111 // add new polyline:
1112 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: adding new polyline");
1113 container->addEntity(newPolyline);
1114 if (graphicView!=NULL) {
1115 graphicView->deleteEntity(&polyline);
1116 graphicView->drawEntity(newPolyline);
1119 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1120 if (document!=NULL && handleUndo) {
1121 document->startUndoCycle();
1123 polyline.setUndoState(true);
1124 document->addUndoable(&polyline);
1125 document->addUndoable(newPolyline);
1127 document->endUndoCycle();
1137 * Trims two segments of a polyline all nodes between the two trim segments
1140 * @param polyline The polyline entity.
1141 * @param segment1 First segment to trim.
1142 * @param segment2 Second segment to trim.
1144 * @return Pointer to the new polyline or NULL.
1147 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1148 RS_AtomicEntity& segment1,
1149 RS_AtomicEntity& segment2) {
1151 RS_DEBUG->print("RS_Modification::polylineTrim");
1153 if (container==NULL) {
1154 RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1155 RS_Debug::D_WARNING);
1159 if (segment1.getParent()!=&polyline || segment2.getParent()!=&polyline) {
1160 RS_DEBUG->print("RS_Modification::polylineTrim: "
1161 "segments not in polyline",
1162 RS_Debug::D_WARNING);
1166 if (&segment1==&segment2) {
1167 RS_DEBUG->print("RS_Modification::polylineTrim: "
1168 "segments are identical",
1169 RS_Debug::D_WARNING);
1173 VectorSolutions sol;
1174 sol = RS_Information::getIntersection(&segment1, &segment2, false);
1176 if (sol.getNumber()==0) {
1177 RS_DEBUG->print("RS_Modification::polylineTrim: "
1178 "segments cannot be trimmed",
1179 RS_Debug::D_WARNING);
1183 // check which segment comes first in the polyline:
1184 RS_AtomicEntity* firstSegment;
1185 if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1186 firstSegment = &segment2;
1188 firstSegment = &segment1;
1191 // find out if we need to trim towards the open part of the polyline
1193 reverseTrim = !RS_Math::isSameDirection(firstSegment->getDirection1(),
1194 firstSegment->getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1195 //reverseTrim = reverseTrim || !RS_Math::isSameDirection(segment2.getDirection1(),
1196 // segment2.getStartpoint().angleTo(sol.get(0)), M_PI/2.0);
1198 RS_Polyline* newPolyline = new RS_Polyline(container);
1199 newPolyline->setClosed(polyline.isClosed());
1200 newPolyline->setSelected(polyline.isSelected());
1201 newPolyline->setLayer(polyline.getLayer());
1202 newPolyline->setPen(polyline.getPen());
1204 // normal trimming: start removing nodes at trim segment. ends stay the same
1205 if (reverseTrim==false) {
1206 // copy polyline, trim segments and drop between nodes:
1208 bool removing = false;
1209 bool nextIsStraight = false;
1210 RS_Entity* lastEntity = polyline.lastEntity();
1211 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1212 e=polyline.nextEntity()) {
1214 if (e->isAtomic()) {
1215 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1217 if (ae->rtti()==RS2::EntityArc) {
1218 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1219 bulge = ((RS_Arc*)ae)->getBulge();
1221 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1225 // last entity is closing entity and will be added below with endPolyline()
1226 if (e==lastEntity && polyline.isClosed()) {
1227 RS_DEBUG->print("RS_Modification::polylineTrim: "
1228 "dropping last vertex of closed polyline");
1232 // first vertex (startpoint)
1234 RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1235 ae->getStartpoint().x, ae->getStartpoint().y);
1237 newPolyline->setNextBulge(bulge);
1238 newPolyline->addVertex(ae->getStartpoint());
1242 // trim and start removing nodes:
1243 if (removing==false && (ae==&segment1 || ae==&segment2)) {
1244 RS_DEBUG->print("RS_Modification::polylineTrim: "
1245 "start removing at trim point %f/%f",
1246 sol.get(0).x, sol.get(0).y);
1247 newPolyline->setNextBulge(0.0);
1248 newPolyline->addVertex(sol.get(0));
1250 nextIsStraight = true;
1253 // stop removing nodes:
1254 else if (removing==true && (ae==&segment1 || ae==&segment2)) {
1255 RS_DEBUG->print("RS_Modification::polylineTrim: stop removing at: %f/%f",
1256 ae->getEndpoint().x, ae->getEndpoint().y);
1260 // normal node (not deleted):
1261 if (removing==false) {
1262 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1263 ae->getEndpoint().x, ae->getEndpoint().y);
1264 if (nextIsStraight) {
1265 newPolyline->setNextBulge(0.0);
1266 nextIsStraight = false;
1268 newPolyline->setNextBulge(bulge);
1270 newPolyline->addVertex(ae->getEndpoint());
1273 RS_DEBUG->print("RS_Modification::polylineTrim: "
1274 "Polyline contains non-atomic entities",
1275 RS_Debug::D_WARNING);
1280 // reverse trimming: remove nodes at the ends and keep those in between
1282 // copy polyline, trim segments and drop between nodes:
1283 //bool first = true;
1284 bool removing = true;
1285 bool nextIsStraight = false;
1286 RS_Entity* lastEntity = polyline.lastEntity();
1287 for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1288 e=polyline.nextEntity()) {
1290 if (e->isAtomic()) {
1291 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1293 if (ae->rtti()==RS2::EntityArc) {
1294 RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1295 bulge = ((RS_Arc*)ae)->getBulge();
1297 RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1301 // last entity is closing entity and will be added below with endPolyline()
1302 if (e==lastEntity && polyline.isClosed()) {
1303 RS_DEBUG->print("RS_Modification::polylineTrim: "
1304 "dropping last vertex of closed polyline");
1308 // trim and stop removing nodes:
1309 if (removing==true && (ae==&segment1 || ae==&segment2)) {
1310 RS_DEBUG->print("RS_Modification::polylineTrim: "
1311 "stop removing at trim point %f/%f",
1312 sol.get(0).x, sol.get(0).y);
1313 newPolyline->setNextBulge(0.0);
1314 // start of new polyline:
1315 newPolyline->addVertex(sol.get(0));
1317 nextIsStraight = true;
1320 // start removing nodes again:
1321 else if (removing==false && (ae==&segment1 || ae==&segment2)) {
1322 RS_DEBUG->print("RS_Modification::polylineTrim: start removing at: %f/%f",
1323 ae->getEndpoint().x, ae->getEndpoint().y);
1324 newPolyline->setNextBulge(0.0);
1325 // start of new polyline:
1326 newPolyline->addVertex(sol.get(0));
1330 // normal node (not deleted):
1331 if (removing==false) {
1332 RS_DEBUG->print("RS_Modification::polylineTrim: normal vertex found: %f/%f",
1333 ae->getEndpoint().x, ae->getEndpoint().y);
1334 if (nextIsStraight) {
1335 newPolyline->setNextBulge(0.0);
1336 nextIsStraight = false;
1338 newPolyline->setNextBulge(bulge);
1340 newPolyline->addVertex(ae->getEndpoint());
1343 RS_DEBUG->print("RS_Modification::polylineTrim: "
1344 "Polyline contains non-atomic entities",
1345 RS_Debug::D_WARNING);
1350 RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1351 newPolyline->setNextBulge(polyline.getClosingBulge());
1352 newPolyline->endPolyline();
1354 // add new polyline:
1355 RS_DEBUG->print("RS_Modification::polylineTrim: adding new polyline");
1356 container->addEntity(newPolyline);
1357 if (graphicView!=NULL) {
1358 graphicView->deleteEntity(&polyline);
1359 graphicView->drawEntity(newPolyline);
1362 RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1363 if (document!=NULL && handleUndo) {
1364 document->startUndoCycle();
1366 polyline.setUndoState(true);
1367 document->addUndoable(&polyline);
1368 document->addUndoable(newPolyline);
1370 document->endUndoCycle();
1378 * Moves all selected entities with the given data for the move
1381 bool RS_Modification::move(RS_MoveData & data)
1383 if (container == NULL)
1385 RS_DEBUG->print("RS_Modification::move: no valid container", RS_Debug::D_WARNING);
1389 // Q3PtrList<RS_Entity> addList;
1390 // addList.setAutoDelete(false);
1391 QList<RS_Entity *> addList;
1393 if (document != NULL && handleUndo)
1394 document->startUndoCycle();
1396 // Create new entites
1397 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1400 //for (uint i=0; i<container->count(); ++i) {
1401 //RS_Entity* e = container->entityAt(i);
1402 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1404 if (e != NULL && e->isSelected())
1406 RS_Entity * ec = e->clone();
1407 ec->move(data.offset * num);
1409 if (data.useCurrentLayer)
1410 ec->setLayerToActive();
1412 if (data.useCurrentAttributes)
1413 ec->setPenToActive();
1415 if (ec->rtti() == RS2::EntityInsert)
1416 ((RS_Insert *)ec)->update();
1418 // since 2.0.4.0: keep selection
1419 ec->setSelected(true);
1425 deselectOriginals(data.number==0);
1426 addNewEntities(addList);
1428 if (document != NULL && handleUndo)
1429 document->endUndoCycle();
1431 if (graphicView != NULL)
1432 graphicView->redraw();
1438 * Rotates all selected entities with the given data for the rotation.
1440 bool RS_Modification::rotate(RS_RotateData & data)
1442 if (container == NULL)
1444 RS_DEBUG->print("RS_Modification::rotate: no valid container",
1445 RS_Debug::D_WARNING);
1449 // Q3PtrList<RS_Entity> addList;
1450 // addList.setAutoDelete(false);
1451 QList<RS_Entity *> addList;
1453 if (document!=NULL && handleUndo)
1454 document->startUndoCycle();
1456 // Create new entites
1457 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1459 for (RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1461 //for (uint i=0; i<container->count(); ++i) {
1462 //RS_Entity* e = container->entityAt(i);
1464 if (e != NULL && e->isSelected())
1466 RS_Entity * ec = e->clone();
1467 ec->setSelected(false);
1468 ec->rotate(data.center, data.angle*num);
1470 if (data.useCurrentLayer)
1471 ec->setLayerToActive();
1473 if (data.useCurrentAttributes)
1474 ec->setPenToActive();
1476 if (ec->rtti() == RS2::EntityInsert)
1477 ((RS_Insert *)ec)->update();
1484 deselectOriginals(data.number == 0);
1485 addNewEntities(addList);
1487 if (document != NULL && handleUndo)
1488 document->endUndoCycle();
1490 if (graphicView != NULL)
1491 graphicView->redraw();
1497 * Moves all selected entities with the given data for the scale
1500 bool RS_Modification::scale(RS_ScaleData & data)
1502 if (container == NULL)
1504 RS_DEBUG->print("RS_Modification::scale: no valid container", RS_Debug::D_WARNING);
1508 // Q3PtrList<RS_Entity> addList;
1509 // addList.setAutoDelete(false);
1510 QList<RS_Entity *> addList;
1512 if (document!=NULL && handleUndo)
1513 document->startUndoCycle();
1515 // Create new entites
1516 for(int num=1; num<=data.number || (data.number==0 && num<=1); num++)
1518 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1520 //for (uint i=0; i<container->count(); ++i) {
1521 //RS_Entity* e = container->entityAt(i);
1522 if (e != NULL && e->isSelected())
1524 RS_Entity * ec = e->clone();
1525 ec->setSelected(false);
1526 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1528 if (data.useCurrentLayer)
1529 ec->setLayerToActive();
1531 if (data.useCurrentAttributes)
1532 ec->setPenToActive();
1534 if (ec->rtti()==RS2::EntityInsert)
1535 ((RS_Insert*)ec)->update();
1542 deselectOriginals(data.number == 0);
1543 addNewEntities(addList);
1545 if (document != NULL && handleUndo)
1546 document->endUndoCycle();
1548 if (graphicView != NULL)
1549 graphicView->redraw();
1555 * Mirror all selected entities with the given data for the mirror
1558 bool RS_Modification::mirror(RS_MirrorData & data)
1560 if (container==NULL) {
1561 RS_DEBUG->print("RS_Modification::mirror: no valid container",
1562 RS_Debug::D_WARNING);
1566 // Q3PtrList<RS_Entity> addList;
1567 // addList.setAutoDelete(false);
1568 QList<RS_Entity *> addList;
1570 if (document!=NULL && handleUndo) {
1571 document->startUndoCycle();
1574 // Create new entites
1576 num<=(int)data.copy || (data.copy==false && num<=1);
1578 for (RS_Entity* e=container->firstEntity();
1580 e=container->nextEntity()) {
1581 //for (uint i=0; i<container->count(); ++i) {
1582 //RS_Entity* e = container->entityAt(i);
1584 if (e!=NULL && e->isSelected()) {
1585 RS_Entity* ec = e->clone();
1586 ec->setSelected(false);
1588 ec->mirror(data.axisPoint1, data.axisPoint2);
1589 if (data.useCurrentLayer) {
1590 ec->setLayerToActive();
1592 if (data.useCurrentAttributes) {
1593 ec->setPenToActive();
1595 if (ec->rtti()==RS2::EntityInsert) {
1596 ((RS_Insert*)ec)->update();
1603 deselectOriginals(data.copy==false);
1604 addNewEntities(addList);
1606 if (document!=NULL && handleUndo) {
1607 document->endUndoCycle();
1610 if (graphicView!=NULL) {
1611 graphicView->redraw();
1617 * Rotates entities around two centers with the given parameters.
1619 bool RS_Modification::rotate2(RS_Rotate2Data & data)
1621 if (container==NULL) {
1622 RS_DEBUG->print("RS_Modification::rotate2: no valid container",
1623 RS_Debug::D_WARNING);
1627 // Q3PtrList<RS_Entity> addList;
1628 // addList.setAutoDelete(false);
1629 QList<RS_Entity *> addList;
1631 if (document!=NULL && handleUndo) {
1632 document->startUndoCycle();
1635 // Create new entites
1637 num<=data.number || (data.number==0 && num<=1);
1640 for (RS_Entity* e=container->firstEntity();
1642 e=container->nextEntity()) {
1643 //for (uint i=0; i<container->count(); ++i) {
1644 //RS_Entity* e = container->entityAt(i);
1646 if (e!=NULL && e->isSelected()) {
1647 RS_Entity* ec = e->clone();
1648 ec->setSelected(false);
1650 ec->rotate(data.center1, data.angle1*num);
1651 Vector center2 = data.center2;
1652 center2.rotate(data.center1, data.angle1*num);
1654 ec->rotate(center2, data.angle2*num);
1655 if (data.useCurrentLayer) {
1656 ec->setLayerToActive();
1658 if (data.useCurrentAttributes) {
1659 ec->setPenToActive();
1661 if (ec->rtti()==RS2::EntityInsert) {
1662 ((RS_Insert*)ec)->update();
1669 deselectOriginals(data.number==0);
1670 addNewEntities(addList);
1672 if (document!=NULL && handleUndo) {
1673 document->endUndoCycle();
1676 if (graphicView!=NULL) {
1677 graphicView->redraw();
1683 * Moves and rotates entities with the given parameters.
1685 bool RS_Modification::moveRotate(RS_MoveRotateData & data)
1687 if (container==NULL) {
1688 RS_DEBUG->print("RS_Modification::moveRotate: no valid container",
1689 RS_Debug::D_WARNING);
1693 // Q3PtrList<RS_Entity> addList;
1694 // addList.setAutoDelete(false);
1695 QList<RS_Entity *> addList;
1697 if (document!=NULL && handleUndo) {
1698 document->startUndoCycle();
1701 // Create new entites
1703 num<=data.number || (data.number==0 && num<=1);
1705 for (RS_Entity* e=container->firstEntity();
1707 e=container->nextEntity()) {
1708 //for (uint i=0; i<container->count(); ++i) {
1709 //RS_Entity* e = container->entityAt(i);
1711 if (e!=NULL && e->isSelected()) {
1712 RS_Entity* ec = e->clone();
1713 ec->setSelected(false);
1715 ec->move(data.offset*num);
1716 ec->rotate(data.referencePoint + data.offset*num,
1718 if (data.useCurrentLayer) {
1719 ec->setLayerToActive();
1721 if (data.useCurrentAttributes) {
1722 ec->setPenToActive();
1724 if (ec->rtti()==RS2::EntityInsert) {
1725 ((RS_Insert*)ec)->update();
1732 deselectOriginals(data.number==0);
1733 addNewEntities(addList);
1735 if (document!=NULL && handleUndo) {
1736 document->endUndoCycle();
1738 if (graphicView!=NULL) {
1739 graphicView->redraw();
1746 * Deselects all selected entities and removes them if remove is true;
1748 * @param remove true: Remove entites.
1750 void RS_Modification::deselectOriginals(bool remove)
1752 for(RS_Entity* e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1754 //for (uint i=0; i<container->count(); ++i) {
1755 //RS_Entity* e = container->entityAt(i);
1759 bool selected = false;
1761 if (e->isAtomic()) {
1762 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1763 if (ae->isStartpointSelected() ||
1764 ae->isEndpointSelected()) {
1771 if (e->isSelected())
1776 e->setSelected(false);
1780 //if (graphicView!=NULL) {
1781 // graphicView->deleteEntity(e);
1783 e->changeUndoState();
1785 if (document != NULL && handleUndo)
1786 document->addUndoable(e);
1790 //if (graphicView!=NULL) {
1791 // graphicView->drawEntity(e);
1800 * Adds the given entities to the container and draws the entities if
1801 * there's a graphic view available.
1803 * @param addList Entities to add.
1805 //void RS_Modification::addNewEntities(Q3PtrList<RS_Entity> & addList)
1806 void RS_Modification::addNewEntities(QList<RS_Entity *> & addList)
1808 // for(RS_Entity * e=addList.first(); e!=NULL; e=addList.next())
1809 for(int i=0; i<addList.size(); i++)
1811 RS_Entity * e = addList[i];
1815 container->addEntity(e);
1817 if (document != NULL && handleUndo)
1818 document->addUndoable(e);
1819 //if (graphicView!=NULL) {
1820 // graphicView->drawEntity(e);
1827 * Trims or extends the given trimEntity to the intersection point of the
1828 * trimEntity and the limitEntity.
1830 * @param trimCoord Coordinate which defines which endpoint of the
1831 * trim entity to trim.
1832 * @param trimEntity Entity which will be trimmed.
1833 * @param limitCoord Coordinate which defines the intersection to which the
1834 * trim entity will be trimmed.
1835 * @param limitEntity Entity to which the trim entity will be trimmed.
1836 * @param both true: Trim both entities. false: trim trimEntity only.
1838 bool RS_Modification::trim(const Vector& trimCoord, RS_AtomicEntity* trimEntity,
1839 const Vector& limitCoord, RS_Entity* limitEntity, bool both)
1841 if (trimEntity==NULL || limitEntity==NULL)
1843 RS_DEBUG->print(RS_Debug::D_WARNING,
1844 "RS_Modification::trim: At least one entity is NULL");
1848 if (both && !limitEntity->isAtomic())
1850 RS_DEBUG->print(RS_Debug::D_WARNING,
1851 "RS_Modification::trim: limitEntity is not atomic");
1854 VectorSolutions sol;
1856 if (limitEntity->isAtomic())
1858 // intersection(s) of the two entities:
1859 sol = RS_Information::getIntersection(trimEntity, limitEntity, false);
1860 } else if (limitEntity->isContainer()) {
1861 RS_EntityContainer* ec = (RS_EntityContainer*)limitEntity;
1866 for (RS_Entity* e=ec->firstEntity(RS2::ResolveAll); e!=NULL;
1867 e=ec->nextEntity(RS2::ResolveAll)) {
1868 //for (int i=0; i<container->count(); ++i) {
1869 // RS_Entity* e = container->entityAt(i);
1873 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1876 if (s2.hasValid()) {
1877 for (int k=0; k<s2.getNumber(); ++k) {
1878 if (i<128 && s2.get(k).valid) {
1879 if (e->isPointOnEntity(s2.get(k), 1.0e-4)) {
1880 sol.set(i++, s2.get(k));
1890 if (!sol.hasValid())
1893 RS_AtomicEntity * trimmed1 = NULL;
1894 RS_AtomicEntity * trimmed2 = NULL;
1896 // remove trim entity from view:
1897 if (trimEntity->rtti() == RS2::EntityCircle)
1899 // convert a circle into a trimmable arc
1900 RS_Circle * c = (RS_Circle *)trimEntity;
1901 double am = c->getCenter().angleTo(trimCoord);
1902 RS_ArcData d(c->getCenter(), c->getRadius(),
1903 RS_Math::correctAngle(am - M_PI / 2),
1904 RS_Math::correctAngle(am + M_PI / 2), false);
1905 trimmed1 = new RS_Arc(trimEntity->getParent(), d);
1909 trimmed1 = (RS_AtomicEntity *)trimEntity->clone();
1910 trimmed1->setHighlighted(false);
1913 #warning "!!! Old rendering path needs upgrading !!!"
1916 graphicView->deleteEntity(trimEntity);
1919 // remove limit entity from view:
1922 trimmed2 = (RS_AtomicEntity *)limitEntity->clone();
1923 trimmed2->setHighlighted(false);
1925 #warning "!!! Old rendering path needs upgrading !!!"
1928 graphicView->deleteEntity(limitEntity);
1934 Vector is = sol.getClosest(limitCoord, NULL, &ind);
1935 //sol.getClosest(limitCoord, NULL, &ind);
1936 RS_DEBUG->print("RS_Modification::trim: limitCoord: %f/%f", limitCoord.x, limitCoord.y);
1937 RS_DEBUG->print("RS_Modification::trim: sol.get(0): %f/%f", sol.get(0).x, sol.get(0).y);
1938 RS_DEBUG->print("RS_Modification::trim: sol.get(1): %f/%f", sol.get(1).x, sol.get(1).y);
1939 RS_DEBUG->print("RS_Modification::trim: ind: %d", ind);
1940 Vector is2 = sol.get(ind==0 ? 1 : 0);
1941 //Vector is2 = sol.get(ind);
1942 RS_DEBUG->print("RS_Modification::trim: is2: %f/%f", is2.x, is2.y);
1944 //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1945 RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1948 case RS2::EndingStart:
1949 trimmed1->trimStartpoint(is);
1950 if (trimEntity->rtti()==RS2::EntityCircle) {
1951 trimmed1->trimEndpoint(is2);
1954 case RS2::EndingEnd:
1955 trimmed1->trimEndpoint(is);
1956 if (trimEntity->rtti()==RS2::EntityCircle) {
1957 trimmed1->trimStartpoint(is2);
1964 // trim limit entity:
1966 Vector is = sol.getClosest(limitCoord);
1968 RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1971 case RS2::EndingStart:
1972 trimmed2->trimStartpoint(is);
1974 case RS2::EndingEnd:
1975 trimmed2->trimEndpoint(is);
1982 // add new trimmed trim entity:
1983 container->addEntity(trimmed1);
1984 if (graphicView!=NULL) {
1985 graphicView->drawEntity(trimmed1);
1988 // add new trimmed limit entity:
1990 container->addEntity(trimmed2);
1991 if (graphicView!=NULL) {
1992 graphicView->drawEntity(trimmed2);
1996 if (document!=NULL && handleUndo) {
1997 document->startUndoCycle();
1998 document->addUndoable(trimmed1);
1999 trimEntity->setUndoState(true);
2000 document->addUndoable(trimEntity);
2002 document->addUndoable(trimmed2);
2003 limitEntity->setUndoState(true);
2004 document->addUndoable(limitEntity);
2006 document->endUndoCycle();
2015 * Trims or extends the given trimEntity by the given amount.
2017 * @param trimCoord Coordinate which defines which endpoint of the
2018 * trim entity to trim.
2019 * @param trimEntity Entity which will be trimmed.
2020 * @param dist Amount to trim by.
2022 bool RS_Modification::trimAmount(const Vector & trimCoord,
2023 RS_AtomicEntity * trimEntity, double dist)
2027 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Modification::trimAmount: Entity is NULL");
2031 RS_AtomicEntity * trimmed = NULL;
2033 // remove trim entity:
2034 trimmed = (RS_AtomicEntity*)trimEntity->clone();
2036 #warning "!!! Old rendering path needs upgrading !!!"
2039 graphicView->deleteEntity(trimEntity);
2043 Vector is = trimmed->getNearestDist(-dist, trimCoord);
2044 if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2045 trimCoord.distanceTo(trimmed->getEndpoint()))
2047 trimmed->trimStartpoint(is);
2051 trimmed->trimEndpoint(is);
2054 // add new trimmed trim entity:
2055 container->addEntity(trimmed);
2057 #warning "!!! Old rendering path needs upgrading !!!"
2060 graphicView->drawEntity(trimmed);
2063 if (document && handleUndo)
2065 document->startUndoCycle();
2066 document->addUndoable(trimmed);
2067 trimEntity->setUndoState(true);
2068 document->addUndoable(trimEntity);
2069 document->endUndoCycle();
2078 * Cuts the given entity at the given point.
2080 bool RS_Modification::cut(const Vector& cutCoord,
2081 RS_AtomicEntity* cutEntity) {
2083 if (cutEntity==NULL) {
2084 RS_DEBUG->print(RS_Debug::D_WARNING,
2085 "RS_Modification::cut: Entity is NULL");
2089 if (!cutCoord.valid) {
2090 RS_DEBUG->print(RS_Debug::D_WARNING,
2091 "RS_Modification::cut: Point invalid.");
2095 // cut point is at endpoint of entity:
2096 if (cutCoord.distanceTo(cutEntity->getStartpoint())<1.0e-6 ||
2097 cutCoord.distanceTo(cutEntity->getEndpoint())<1.0e-6) {
2098 RS_DEBUG->print(RS_Debug::D_WARNING,
2099 "RS_Modification::cut: Cutting point on endpoint");
2103 #warning "!!! Old rendering path needs upgrading !!!"
2105 // delete cut entity on the screen:
2107 graphicView->deleteEntity(cutEntity);
2110 RS_AtomicEntity * cut1 = NULL;
2111 RS_AtomicEntity * cut2 = NULL;
2113 // create new two halves:
2114 if (cutEntity->rtti() == RS2::EntityCircle)
2116 RS_Circle * c = (RS_Circle *)cutEntity;
2117 cut1 = new RS_Arc(cutEntity->getParent(),
2118 RS_ArcData(c->getCenter(),
2121 cut1->setPen(cutEntity->getPen());
2122 cut1->setLayer(cutEntity->getLayer());
2125 cut1->trimEndpoint(cutCoord);
2126 cut1->trimStartpoint(cutCoord);
2130 cut1 = (RS_AtomicEntity*)cutEntity->clone();
2131 cut2 = (RS_AtomicEntity*)cutEntity->clone();
2133 cut1->trimEndpoint(cutCoord);
2134 cut2->trimStartpoint(cutCoord);
2137 // add new cut entity:
2138 container->addEntity(cut1);
2140 container->addEntity(cut2);
2143 if (graphicView!=NULL) {
2144 graphicView->drawEntity(cut1);
2146 graphicView->drawEntity(cut2);
2150 if (document!=NULL && handleUndo) {
2151 document->startUndoCycle();
2152 document->addUndoable(cut1);
2154 document->addUndoable(cut2);
2156 cutEntity->setUndoState(true);
2157 document->addUndoable(cutEntity);
2158 document->endUndoCycle();
2167 bool RS_Modification::stretch(const Vector& firstCorner, const Vector& secondCorner,
2168 const Vector& offset)
2172 RS_DEBUG->print(RS_Debug::D_WARNING,
2173 "RS_Modification::stretch: Offset invalid");
2177 // Q3PtrList<RS_Entity> addList;
2178 // addList.setAutoDelete(false);
2179 QList<RS_Entity *> addList;
2181 if (document!=NULL && handleUndo) {
2182 document->startUndoCycle();
2185 // Create new entites
2186 for (RS_Entity* e=container->firstEntity();
2188 e=container->nextEntity()) {
2189 //for (int i=0; i<container->count(); ++i) {
2190 // RS_Entity* e = container->entityAt(i);
2195 (e->isInWindow(firstCorner, secondCorner) ||
2196 e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2198 RS_Entity* ec = e->clone();
2199 ec->stretch(firstCorner, secondCorner, offset);
2201 e->setSelected(true);
2205 deselectOriginals(true);
2206 addNewEntities(addList);
2208 if (document!=NULL && handleUndo) {
2209 document->endUndoCycle();
2212 if (graphicView!=NULL) {
2213 graphicView->redraw();
2223 * @param coord1 Mouse coordinate to specify direction from intersection.
2224 * @param entity1 First entity of the corner.
2225 * @param coord2 Mouse coordinate to specify direction from intersection.
2226 * @param entity2 Second entity of the corner.
2227 * @param data Lengths and trim flag.
2229 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2230 const Vector& coord2, RS_AtomicEntity* entity2,
2231 RS_BevelData& data) {
2233 RS_DEBUG->print("RS_Modification::bevel");
2235 if (entity1==NULL || entity2==NULL) {
2236 RS_DEBUG->print(RS_Debug::D_WARNING,
2237 "RS_Modification::bevel: At least one entity is NULL");
2241 RS_EntityContainer* baseContainer = container;
2242 bool isPolyline = false;
2243 bool isClosedPolyline = false;
2245 if (document!=NULL && handleUndo) {
2246 document->startUndoCycle();
2249 // find out whether we're bevelling within a polyline:
2250 if (entity1->getParent()!=NULL && entity1->getParent()->rtti()==RS2::EntityPolyline) {
2251 RS_DEBUG->print("RS_Modification::bevel: trimming polyline segments");
2252 if (entity1->getParent()!=entity2->getParent()) {
2253 RS_DEBUG->print(RS_Debug::D_WARNING,
2254 "RS_Modification::bevel: entities not in the same polyline");
2257 // clone polyline for undo
2258 if (document!=NULL && handleUndo) {
2259 RS_EntityContainer* cl =
2260 (RS_EntityContainer*)entity1->getParent()->clone();
2261 container->addEntity(cl);
2262 //cl->setUndoState(true);
2263 document->addUndoable(cl);
2265 document->addUndoable(entity1->getParent());
2266 entity1->getParent()->setUndoState(true);
2271 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2272 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2274 //baseContainer = entity1->getParent();
2276 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2279 RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2281 VectorSolutions sol =
2282 RS_Information::getIntersection(entity1, entity2, false);
2284 if (sol.getNumber()==0) {
2288 RS_AtomicEntity* trimmed1 = NULL;
2289 RS_AtomicEntity* trimmed2 = NULL;
2291 //if (data.trim || isPolyline) {
2296 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2297 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2300 #warning "!!! Old rendering path needs upgrading !!!"
2302 // remove trim entity (on screen):
2303 if (data.trim || isPolyline)
2309 graphicView->deleteEntity(baseContainer);
2313 graphicView->deleteEntity(entity1);
2314 graphicView->deleteEntity(entity2);
2320 // trim entities to intersection
2321 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 01");
2322 bool start1 = false;
2323 Vector is = sol.getClosest(coord2);
2324 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is);
2326 case RS2::EndingStart:
2327 trimmed1->trimStartpoint(is);
2330 case RS2::EndingEnd:
2331 trimmed1->trimEndpoint(is);
2338 RS_DEBUG->print("RS_Modification::bevel: trim entities to intersection 02");
2339 bool start2 = false;
2340 is = sol.getClosest(coord1);
2341 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is);
2343 case RS2::EndingStart:
2344 trimmed2->trimStartpoint(is);
2347 case RS2::EndingEnd:
2348 trimmed2->trimEndpoint(is);
2357 // find definitive bevel points
2358 RS_DEBUG->print("RS_Modification::bevel: find definitive bevel points");
2359 Vector bp1 = trimmed1->getNearestDist(data.length1, start1);
2360 Vector bp2 = trimmed2->getNearestDist(data.length2, start2);
2363 RS_DEBUG->print("RS_Modification::bevel: final trim");
2364 if (data.trim==true) {
2366 case RS2::EndingStart:
2367 trimmed1->trimStartpoint(bp1);
2369 case RS2::EndingEnd:
2370 trimmed1->trimEndpoint(bp1);
2377 case RS2::EndingStart:
2378 trimmed2->trimStartpoint(bp2);
2380 case RS2::EndingEnd:
2381 trimmed2->trimEndpoint(bp2);
2387 // add new trimmed entities:
2388 if (isPolyline==false) {
2389 container->addEntity(trimmed1);
2390 container->addEntity(trimmed2);
2392 if (graphicView!=NULL) {
2394 graphicView->drawEntity(trimmed1);
2395 graphicView->drawEntity(trimmed2);
2402 RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2403 RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2405 if (isPolyline==false) {
2406 baseContainer->addEntity(bevel);
2408 int idx1 = baseContainer->findEntity(trimmed1);
2409 int idx2 = baseContainer->findEntity(trimmed2);
2411 bevel->setSelected(baseContainer->isSelected());
2412 bevel->setLayer(baseContainer->getLayer());
2413 bevel->setPen(baseContainer->getPen());
2415 bool insertAfter1 = false;
2416 if (!isClosedPolyline) {
2417 insertAfter1 = (idx1<idx2);
2420 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2421 (idx2==0 && idx1==(int)baseContainer->count()-1));
2424 // insert bevel at the right position:
2425 //if ((idx1<idx2 && idx1!=0) ||
2426 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2428 if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2431 baseContainer->insertEntity(idx1+1, bevel);
2433 if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2436 baseContainer->insertEntity(idx2+1, bevel);
2441 ((RS_Polyline*)baseContainer)->updateEndpoints();
2444 if (graphicView!=NULL) {
2446 graphicView->drawEntity(baseContainer);
2448 graphicView->drawEntity(bevel);
2452 RS_DEBUG->print("RS_Modification::bevel: handling undo");
2454 if (document!=NULL && handleUndo) {
2455 //document->startUndoCycle();
2457 if (isPolyline==false && data.trim==true) {
2458 document->addUndoable(trimmed1);
2459 entity1->setUndoState(true);
2460 document->addUndoable(entity1);
2462 document->addUndoable(trimmed2);
2463 entity2->setUndoState(true);
2464 document->addUndoable(entity2);
2467 if (isPolyline==false) {
2468 document->addUndoable(bevel);
2471 document->endUndoCycle();
2474 if (data.trim==false) {
2475 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2478 RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2490 * @param coord Mouse coordinate to specify the rounding.
2491 * @param entity1 First entity of the corner.
2492 * @param entity2 Second entity of the corner.
2493 * @param data Radius and trim flag.
2495 bool RS_Modification::round(const Vector& coord,
2496 const Vector& coord1,
2497 RS_AtomicEntity* entity1,
2498 const Vector& coord2,
2499 RS_AtomicEntity* entity2,
2500 RS_RoundData& data) {
2502 if (entity1==NULL || entity2==NULL) {
2503 RS_DEBUG->print(RS_Debug::D_WARNING,
2504 "RS_Modification::round: At least one entity is NULL");
2508 RS_EntityContainer* baseContainer = container;
2509 bool isPolyline = false;
2510 bool isClosedPolyline = false;
2512 if (document!=NULL && handleUndo) {
2513 document->startUndoCycle();
2516 // find out whether we're rounding within a polyline:
2517 if (entity1->getParent()!=NULL &&
2518 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2520 if (entity1->getParent()!=entity2->getParent()) {
2521 RS_DEBUG->print(RS_Debug::D_WARNING,
2522 "RS_Modification::round: entities not in "
2523 "the same polyline");
2524 if (document!=NULL && handleUndo) {
2525 document->endUndoCycle();
2530 // clone polyline for undo
2531 if (document!=NULL && handleUndo) {
2532 RS_EntityContainer* cl =
2533 (RS_EntityContainer*)entity1->getParent()->clone();
2534 container->addEntity(cl);
2535 document->addUndoable(cl);
2537 document->addUndoable(entity1->getParent());
2538 entity1->getParent()->setUndoState(true);
2543 entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2544 entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2547 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2550 // create 2 tmp parallels
2551 RS_Creation creation(NULL, NULL);
2552 RS_Entity* par1 = creation.createParallel(coord, data.radius, 1, entity1);
2553 RS_Entity* par2 = creation.createParallel(coord, data.radius, 1, entity2);
2555 VectorSolutions sol2 =
2556 RS_Information::getIntersection(entity1, entity2, false);
2558 VectorSolutions sol =
2559 RS_Information::getIntersection(par1, par2, false);
2561 if (sol.getNumber()==0) {
2562 if (document!=NULL && handleUndo) {
2563 document->endUndoCycle();
2568 // there might be two intersections: choose the closest:
2569 Vector is = sol.getClosest(coord);
2570 Vector p1 = entity1->getNearestPointOnEntity(is, false);
2571 Vector p2 = entity2->getNearestPointOnEntity(is, false);
2572 double ang1 = is.angleTo(p1);
2573 double ang2 = is.angleTo(p2);
2574 bool reversed = (RS_Math::getAngleDifference(ang1, ang2)>M_PI);
2576 RS_Arc* arc = new RS_Arc(baseContainer,
2583 RS_AtomicEntity* trimmed1 = NULL;
2584 RS_AtomicEntity* trimmed2 = NULL;
2586 if (data.trim || isPolyline) {
2591 trimmed1 = (RS_AtomicEntity*)entity1->clone();
2592 trimmed2 = (RS_AtomicEntity*)entity2->clone();
2595 #warning "!!! Old rendering path needs upgrading !!!"
2597 // remove trim entity:
2598 if (graphicView!=NULL)
2602 graphicView->deleteEntity(baseContainer);
2606 graphicView->deleteEntity(entity1);
2607 graphicView->deleteEntity(entity2);
2612 // trim entities to intersection
2613 Vector is2 = sol2.getClosest(coord2);
2614 RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2616 case RS2::EndingStart:
2617 trimmed1->trimStartpoint(p1);
2619 case RS2::EndingEnd:
2620 trimmed1->trimEndpoint(p1);
2626 is2 = sol2.getClosest(coord1);
2627 RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2629 case RS2::EndingStart:
2630 trimmed2->trimStartpoint(p2);
2632 case RS2::EndingEnd:
2633 trimmed2->trimEndpoint(p2);
2639 // add new trimmed entities:
2640 if (isPolyline==false) {
2641 container->addEntity(trimmed1);
2642 container->addEntity(trimmed2);
2644 if (graphicView!=NULL) {
2646 graphicView->drawEntity(trimmed1);
2647 graphicView->drawEntity(trimmed2);
2653 if (isPolyline==false) {
2654 baseContainer->addEntity(arc);
2656 // find out which base entity is before the rounding:
2657 int idx1 = baseContainer->findEntity(trimmed1);
2658 int idx2 = baseContainer->findEntity(trimmed2);
2660 arc->setSelected(baseContainer->isSelected());
2661 arc->setLayer(baseContainer->getLayer());
2662 arc->setPen(baseContainer->getPen());
2664 RS_DEBUG->print("RS_Modification::round: idx1<idx2: %d", (int)(idx1<idx2));
2665 RS_DEBUG->print("RS_Modification::round: idx1!=0: %d", (int)(idx1!=0));
2666 RS_DEBUG->print("RS_Modification::round: idx2==0: %d", (int)(idx2==0));
2667 RS_DEBUG->print("RS_Modification::round: idx1==(int)baseContainer->count()-1: %d",
2668 (int)(idx1==(int)baseContainer->count()-1));
2670 bool insertAfter1 = false;
2671 if (!isClosedPolyline) {
2672 insertAfter1 = (idx1<idx2);
2675 insertAfter1 = ((idx1<idx2 && idx1!=0) ||
2676 (idx2==0 && idx1==(int)baseContainer->count()-1));
2679 // insert rounding at the right position:
2680 //if ((idx1<idx2 && idx1!=0) ||
2681 // (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2684 if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2687 baseContainer->insertEntity(idx1+1, arc);
2689 if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2692 baseContainer->insertEntity(idx2+1, arc);
2697 ((RS_Polyline*)baseContainer)->updateEndpoints();
2700 if (graphicView!=NULL) {
2702 graphicView->drawEntity(baseContainer);
2704 graphicView->drawEntity(arc);
2708 if (document!=NULL && handleUndo) {
2709 if (isPolyline==false && data.trim==true) {
2710 document->addUndoable(trimmed1);
2711 entity1->setUndoState(true);
2712 document->addUndoable(entity1);
2714 document->addUndoable(trimmed2);
2715 entity2->setUndoState(true);
2716 document->addUndoable(entity2);
2719 if (isPolyline==false) {
2720 document->addUndoable(arc);
2723 document->endUndoCycle();
2733 * Removes the selected entity containers and adds the entities in them as
2734 * new single entities.
2736 bool RS_Modification::explode()
2738 if (container == NULL)
2740 RS_DEBUG->print("RS_Modification::explode: no valid container for addinge entities",
2741 RS_Debug::D_WARNING);
2745 // Q3PtrList<RS_Entity> addList;
2746 // addList.setAutoDelete(false);
2747 QList<RS_Entity *> addList;
2749 if (document!=NULL && handleUndo) {
2750 document->startUndoCycle();
2753 for (RS_Entity* e=container->firstEntity();
2755 e=container->nextEntity()) {
2756 //for (uint i=0; i<container->count(); ++i) {
2757 //RS_Entity* e = container->entityAt(i);
2759 if (e!=NULL && e->isSelected()) {
2760 if (e->isContainer()) {
2762 // add entities from container:
2763 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2764 //ec->setSelected(false);
2766 // iterate and explode container:
2767 //for (uint i2=0; i2<ec->count(); ++i2) {
2768 // RS_Entity* e2 = ec->entityAt(i2);
2769 RS2::ResolveLevel rl;
2773 switch (ec->rtti()) {
2774 case RS2::EntityText:
2775 case RS2::EntityHatch:
2776 case RS2::EntityPolyline:
2777 rl = RS2::ResolveAll;
2778 resolveLayer = true;
2782 case RS2::EntityInsert:
2784 resolveLayer = false;
2785 rl = RS2::ResolveNone;
2788 case RS2::EntityDimAligned:
2789 case RS2::EntityDimLinear:
2790 case RS2::EntityDimRadial:
2791 case RS2::EntityDimDiametric:
2792 case RS2::EntityDimAngular:
2793 case RS2::EntityDimLeader:
2794 rl = RS2::ResolveNone;
2795 resolveLayer = true;
2800 rl = RS2::ResolveAll;
2801 resolveLayer = true;
2806 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2807 e2 = ec->nextEntity(rl)) {
2810 RS_Entity* clone = e2->clone();
2811 clone->setSelected(false);
2812 clone->reparent(container);
2815 clone->setLayer(ec->getLayer());
2817 clone->setLayer(e2->getLayer());
2820 clone->setPen(ec->getPen(resolvePen));
2822 addList.append(clone);
2828 e->setSelected(false);
2833 deselectOriginals(true);
2834 addNewEntities(addList);
2836 if (document!=NULL && handleUndo) {
2837 document->endUndoCycle();
2840 if (graphicView!=NULL) {
2841 graphicView->redraw();
2847 bool RS_Modification::explodeTextIntoLetters()
2849 if (container == NULL)
2851 RS_DEBUG->print("RS_Modification::explodeTextIntoLetters: no valid container"
2852 " for addinge entities", RS_Debug::D_WARNING);
2856 // Q3PtrList<RS_Entity> addList;
2857 // addList.setAutoDelete(false);
2858 QList<RS_Entity *> addList;
2860 if (document!=NULL && handleUndo) {
2861 document->startUndoCycle();
2864 for (RS_Entity* e=container->firstEntity();
2866 e=container->nextEntity()) {
2867 if (e!=NULL && e->isSelected()) {
2868 if (e->rtti()==RS2::EntityText) {
2869 // add letters of text:
2870 RS_Text* text = (RS_Text*)e;
2871 explodeTextIntoLetters(text, addList);
2873 e->setSelected(false);
2878 deselectOriginals(true);
2879 addNewEntities(addList);
2881 if (document!=NULL && handleUndo) {
2882 document->endUndoCycle();
2885 if (graphicView!=NULL) {
2886 graphicView->redraw();
2892 //bool RS_Modification::explodeTextIntoLetters(RS_Text* text, Q3PtrList<RS_Entity>& addList)
2893 bool RS_Modification::explodeTextIntoLetters(RS_Text * text, QList<RS_Entity *> & addList)
2898 // iterate though lines:
2899 for(RS_Entity * e2=text->firstEntity(); e2!=NULL; e2=text->nextEntity())
2905 if (e2->rtti() == RS2::EntityContainer)
2907 RS_EntityContainer * line = (RS_EntityContainer *)e2;
2909 // iterate though letters:
2910 for(RS_Entity * e3=line->firstEntity(); e3!=NULL; e3=line->nextEntity())
2915 // super / sub texts:
2916 if (e3->rtti() == RS2::EntityText)
2917 explodeTextIntoLetters((RS_Text *)e3, addList);
2919 else if (e3->rtti() == RS2::EntityInsert)
2921 RS_Insert * letter = (RS_Insert *)e3;
2923 RS_Text * tl = new RS_Text(container, RS_TextData(letter->getInsertionPoint(),
2924 text->getHeight(), 100.0, RS2::VAlignBottom, RS2::HAlignLeft,
2925 RS2::LeftToRight, RS2::Exact, 1.0, letter->getName(), text->getStyle(),
2926 letter->getAngle(), RS2::Update));
2928 tl->setLayer(text->getLayer());
2929 tl->setPen(text->getPen());
2942 * Moves all reference points of selected entities with the given data.
2944 bool RS_Modification::moveRef(RS_MoveRefData& data)
2946 if (container == NULL)
2948 RS_DEBUG->print("RS_Modification::moveRef: no valid container", RS_Debug::D_WARNING);
2952 // Q3PtrList<RS_Entity> addList;
2953 // addList.setAutoDelete(false);
2954 QList<RS_Entity *> addList;
2956 if (document != NULL && handleUndo)
2957 document->startUndoCycle();
2959 // Create new entites
2960 for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
2962 if (e != NULL && e->isSelected())
2964 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();
2978 if (graphicView != NULL)
2979 graphicView->redraw();