]> Shamusworld >> Repos - architektonas/blob - src/base/rs_modification.cpp.bak
Scrubbed out all references to RS2::qtToRsButton(). Gone!
[architektonas] / src / base / rs_modification.cpp.bak
1 /****************************************************************************
2 ** $Id: rs_modification.cpp 2419 2005-07-01 16:47:27Z andrew $
3 **
4 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
5 **
6 ** This file is part of the qcadlib Library project.
7 **
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.
12 **
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.
16 **
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.
19 **
20 ** See http://www.ribbonsoft.com for further details.
21 **
22 ** Contact info@ribbonsoft.com if any conditions of this licensing are
23 ** not clear to you.
24 **
25 **********************************************************************/
26
27 #include "rs_modification.h"
28
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"
36 #include "rs_text.h"
37
38
39
40 /**
41  * Default constructor.
42  *
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.
49  */
50 RS_Modification::RS_Modification(RS_EntityContainer& container,
51                                  RS_GraphicView* graphicView,
52                                  bool handleUndo) {
53     this->container = &container;
54     this->graphicView = graphicView;
55     this->handleUndo = handleUndo;
56     graphic = container.getGraphic();
57     document = container.getDocument();
58 }
59
60
61
62 /**
63  * Deletes all selected entities.
64  */
65 void RS_Modification::remove
66 () {
67     if (container==NULL) {
68         RS_DEBUG->print("RS_Modification::remove: no valid container",
69                         RS_Debug::D_WARNING);
70         return;
71     }
72
73     if (document!=NULL) {
74         document->startUndoCycle();
75     }
76
77     // not safe (?)
78     for (RS_Entity* e=container->firstEntity(); e!=NULL;
79             e=container->nextEntity()) {
80
81         if (e!=NULL && e->isSelected()) {
82             e->setSelected(false);
83             e->changeUndoState();
84             if (document!=NULL) {
85                 document->addUndoable(e);
86             }
87         }
88     }
89
90     if (document!=NULL) {
91         document->endUndoCycle();
92     }
93
94     graphicView->redraw();
95 }
96
97
98
99 /**
100  * Changes the attributes of all selected 
101  */
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);
106         return false;
107     }
108
109     RS_PtrList<RS_Entity> addList;
110     addList.setAutoDelete(false);
111
112     if (document!=NULL) {
113         document->startUndoCycle();
114     }
115
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);
123
124             RS_Pen pen = ec->getPen(false);
125
126             if (data.changeLayer==true) {
127                 ec->setLayer(data.layer);
128             }
129
130             if (data.changeColor==true) {
131                 pen.setColor(data.pen.getColor());
132             }
133             if (data.changeLineType==true) {
134                 pen.setLineType(data.pen.getLineType());
135             }
136             if (data.changeWidth==true) {
137                 pen.setWidth(data.pen.getWidth());
138             }
139
140             ec->setPen(pen);
141
142             //if (data.useCurrentLayer) {
143             //    ec->setLayerToActive();
144             //}
145             //if (data.useCurrentAttributes) {
146             //    ec->setPenToActive();
147             //}
148             //if (ec->rtti()==RS2::EntityInsert) {
149             //    ((RS_Insert*)ec)->update();
150             //}
151             ec->update();
152             addList.append(ec);
153         }
154     }
155
156     deselectOriginals(true);
157     addNewEntities(addList);
158
159     if (document!=NULL) {
160         document->endUndoCycle();
161     }
162
163     if (graphicView!=NULL) {
164         graphicView->redraw();
165     }
166
167     return true;
168 }
169
170
171 /**
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.
175  *
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
179  */
180 void RS_Modification::copy(const Vector& ref, const bool cut) {
181
182     if (container==NULL) {
183         RS_DEBUG->print("RS_Modification::copy: no valid container",
184                         RS_Debug::D_WARNING);
185         return;
186     }
187
188     RS_CLIPBOARD->clear();
189     if (graphic!=NULL) {
190         RS_CLIPBOARD->getGraphic()->setUnit(graphic->getUnit());
191     } else {
192         RS_CLIPBOARD->getGraphic()->setUnit(RS2::None);
193     }
194
195     // start undo cycle for the container if we're cutting
196     if (cut && document!=NULL) {
197         document->startUndoCycle();
198     }
199
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);
205
206         if (e!=NULL && e->isSelected()) {
207             copyEntity(e, ref, cut);
208         }
209     }
210
211     if (cut && document!=NULL) {
212         document->endUndoCycle();
213     }
214 }
215
216
217
218 /**
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.
222  *
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
226  */
227 void RS_Modification::copyEntity(RS_Entity* e, const Vector& ref,
228                                  const bool cut) {
229
230     if (e!=NULL && e->isSelected()) {
231         // delete entity in graphic view:
232         if (cut) {
233             if (graphicView!=NULL) {
234                 graphicView->deleteEntity(e);
235             }
236             e->setSelected(false);
237         } else {
238             if (graphicView!=NULL) {
239                 graphicView->deleteEntity(e);
240             }
241             e->setSelected(false);
242             if (graphicView!=NULL) {
243                 graphicView->drawEntity(e);
244             }
245         }
246
247         // add entity to clipboard:
248         RS_Entity* c = e->clone();
249         c->move(-ref);
250         RS_CLIPBOARD->addEntity(c);
251
252         copyLayers(e);
253         copyBlocks(e);
254
255         // set layer to the layer clone:
256         RS_Layer* l = e->getLayer();
257         if (l!=NULL) {
258             c->setLayer(l->getName());
259         }
260
261         // make sure all sub entities point to layers of the clipboard
262         if (c->isContainer()) {
263             RS_EntityContainer* ec = (RS_EntityContainer*)c;
264
265             for (RS_Entity* e2 = ec->firstEntity(RS2::ResolveAll); e2!=NULL;
266                     e2 = ec->nextEntity(RS2::ResolveAll)) {
267
268                 //RS_Entity* e2 = ec->entityAt(i);
269                 RS_Layer* l2 = e2->getLayer();
270
271                 if (l2!=NULL) {
272                     e2->setLayer(l2->getName());
273                 }
274             }
275         }
276
277         if (cut) {
278             e->changeUndoState();
279             if (document!=NULL) {
280                 document->addUndoable(e);
281             }
282         }
283     }
284
285 }
286
287
288
289 /**
290  * Copies all layers of the given entity to the clipboard.
291  */
292 void RS_Modification::copyLayers(RS_Entity* e) {
293
294     if (e==NULL) {
295         return;
296     }
297
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();
302         if (l!=NULL) {
303             if (!RS_CLIPBOARD->hasLayer(l->getName())) {
304                 RS_CLIPBOARD->addLayer(l->clone());
305             }
306         }
307     }
308
309     // special handling of inserts:
310     else {
311         // insert: add layer(s) of subentities:
312         RS_Block* b = ((RS_Insert*)e)->getBlockForInsert();
313         if (b!=NULL) {
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);
318                 copyLayers(e2);
319             }
320         }
321     }
322 }
323
324
325
326 /**
327  * Copies all blocks of the given entity to the clipboard.
328  */
329 void RS_Modification::copyBlocks(RS_Entity* e) {
330
331     if (e==NULL) {
332         return;
333     }
334
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();
338         if (b!=NULL) {
339             // add block of an insert:
340             if (!RS_CLIPBOARD->hasBlock(b->getName())) {
341                 RS_CLIPBOARD->addBlock((RS_Block*)b->clone());
342             }
343
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);
348                 copyBlocks(e2);
349             }
350         }
351     }
352 }
353
354
355
356 /**
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.
360  *
361  * @param data Paste data.
362  * @param source The source from where to paste. NULL means the source
363  *      is the clipboard.
364  */
365 void RS_Modification::paste(const RS_PasteData& data, RS_Graphic* source) {
366
367     if (graphic==NULL) {
368         RS_DEBUG->print(RS_Debug::D_WARNING,
369                         "RS_Modification::paste: Graphic is NULL");
370         return;
371     }
372
373     double factor = 1.0;
374
375     if (source==NULL) {
376         source = RS_CLIPBOARD->getGraphic();
377
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);
382     }
383
384     if (document!=NULL) {
385         document->startUndoCycle();
386     }
387
388
389     // insert layers:
390     if (graphic!=NULL) {
391         RS_Layer* layer = graphic->getActiveLayer();
392         for(uint i=0; i<source->countLayers(); ++i) {
393             RS_Layer* l = source->layerAt(i);
394             if (l!=NULL) {
395                 if (graphic->findLayer(l->getName())==NULL) {
396                     graphic->addLayer(l->clone());
397                 }
398             }
399         }
400         graphic->activateLayer(layer);
401     }
402
403     // insert blocks:
404     if (graphic!=NULL) {
405         for(uint i=0; i<source->countBlocks(); ++i) {
406             RS_Block* b = source->blockAt(i);
407             if (b!=NULL) {
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));
419                         } else {
420                             Vector ip = ((RS_Insert*)e)->getInsertionPoint();
421                             ip.scale(bc->getBasePoint(),
422                                      Vector(factor, factor));
423                             ((RS_Insert*)e)->setInsertionPoint(ip);
424                             e->update();
425                         }
426                     }
427
428                     graphic->addBlock(bc);
429                 }
430             }
431         }
432     }
433
434     // add entities to this host (graphic or a new block)
435     RS_EntityContainer* host = container;
436     RS_String blockName;
437
438     // create new block:
439     if (graphic!=NULL) {
440         if (data.asInsert==true) {
441             RS_BlockList* blkList = graphic->getBlockList();
442             if (blkList!=NULL) {
443                 blockName = blkList->newName(data.blockName);
444
445                 RS_Block* blk =
446                     new RS_Block(graphic,
447                                  RS_BlockData(blockName,
448                                               Vector(0.0,0.0), false));
449                 graphic->addBlock(blk);
450
451                 host = blk;
452             }
453         }
454     }
455
456     // insert entities:
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();
460             e!=NULL;
461             e=((RS_EntityContainer*)source)->nextEntity()) {
462
463         if (e!=NULL) {
464
465             RS_String layerName = "0";
466             RS_Layer* layer = e->getLayer();
467             if (layer!=NULL) {
468                 layerName = layer->getName();
469             }
470             RS_Entity* e2 = e->clone();
471             e2->reparent(host);
472             if (data.asInsert==false) {
473                 e2->move(data.insertionPoint);
474             }
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);
480                 e2->update();
481             } else {
482                 e2->scale(data.insertionPoint, Vector(factor, factor));
483             }
484             host->addEntity(e2);
485             e2->setLayer(layerName);
486
487             // make sure all sub entities point to layers of the container
488             if (e2->isContainer()) {
489                 RS_EntityContainer* ec = (RS_EntityContainer*)e2;
490
491                 for (RS_Entity* e3 = ec->firstEntity(RS2::ResolveAll); e3!=NULL;
492                         e3 = ec->nextEntity(RS2::ResolveAll)) {
493
494                     //RS_Entity* e3 = ec->entityAt(i);
495                     RS_Layer* l2 = e3->getLayer();
496                     if (l2!=NULL) {
497                         e3->setLayer(l2->getName());
498                     }
499                 }
500             }
501
502             if (document!=NULL && data.asInsert==false) {
503                 document->addUndoable(e2);
504             }
505         }
506     }
507
508     if (data.asInsert==true) {
509         RS_Insert* ins =
510             new RS_Insert(container,
511                           RS_InsertData(
512                               blockName,
513                               data.insertionPoint,
514                               Vector(data.factor, data.factor),
515                               data.angle,
516                               1,1,Vector(0.0,0.0)));
517         container->addEntity(ins);
518         ins->setLayerToActive();
519         ins->setPenToActive();
520
521         if (document!=NULL) {
522             document->addUndoable(ins);
523         }
524     }
525
526     if (document!=NULL) {
527         document->endUndoCycle();
528     }
529 }
530
531
532 /**
533  * Splits a polyline into two leaving out a gap.
534  *
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.
546  *
547  * @todo Support arcs in polylines, check for wrong parameters
548  *
549  * @return true
550  */
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 {
556
557     if (container==NULL) {
558         RS_DEBUG->print("RS_Modification::splitPolyline: no valid container",
559                         RS_Debug::D_WARNING);
560         return false;
561     }
562
563     RS_Entity* firstEntity = polyline.firstEntity();
564     Vector firstPoint(false);
565     if (firstEntity->rtti()==RS2::EntityLine) {
566         firstPoint = ((RS_Line*)firstEntity)->getStartpoint();
567     }
568     RS_Polyline* pl1 =
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;
574     RS_Arc* arc = NULL;
575
576     if (polyline1!=NULL) {
577         *polyline1 = pl1;
578     }
579     if (polyline2!=NULL) {
580         *polyline2 = pl2;
581     }
582
583     for (RS_Entity* e = polyline.firstEntity();
584             e != NULL;
585             e = polyline.nextEntity()) {
586
587         if (e->rtti()==RS2::EntityLine) {
588             line = (RS_Line*)e;
589             arc = NULL;
590         } else if (e->rtti()==RS2::EntityArc) {
591             arc = (RS_Arc*)e;
592             line = NULL;
593         } else {
594             line = NULL;
595             arc = NULL;
596         }
597
598         if (line!=NULL /*|| arc!=NULL*/) {
599
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);
606                 pl = pl2;
607                 pl->setStartpoint(dist1<dist2 ? v2 : v1);
608                 pl->addVertex(line->getEndpoint(), 0.0);
609             } else if (e==&e1 || e==&e2) {
610                 // Trim entities:
611                 Vector v = (e==&e1 ? v1 : v2);
612                 if (pl==pl1) {
613                     // Trim endpoint of entity to first vector
614                     pl->addVertex(v, 0.0);
615                     pl = NULL;
616                 } else {
617                     // Trim startpoint of entity to second vector
618                     pl = pl2;
619                     pl->setStartpoint(v);
620                     pl->addVertex(line->getEndpoint(), 0.0);
621                 }
622             } else {
623                 // Add entities to polylines
624                 if (line!=NULL && pl!=NULL) {
625                     pl->addVertex(line->getEndpoint(), 0.0);
626                 }
627             }
628         }
629     }
630
631     container->addEntity(pl1);
632     container->addEntity(pl2);
633     //container->removeEntity(&polyline);
634     polyline.changeUndoState();
635
636     return true;
637 }
638
639
640
641 /**
642  * Adds a node to the given polyline. The new node is placed between
643  * the start and end point of the given segment. 
644  *
645  * @param node The position of the new node.
646  *
647  * @return Pointer to the new polyline or NULL.
648  */
649 /*
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");
654
655     if (container==NULL) {
656         RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
657                         RS_Debug::D_WARNING);
658         return NULL;
659     }
660
661     if (segment.getParent()!=&polyline) {
662         RS_DEBUG->print("RS_Modification::addPolylineNode: "
663                         "segment not part of the polyline",
664                         RS_Debug::D_WARNING);
665         return NULL;
666     }
667
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());
673
674     // copy polyline and add new node:
675     bool first = true;
676     RS_Entity* lastEntity = polyline.lastEntity();
677     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
678             e=polyline.nextEntity()) {
679
680         if (e->isAtomic()) {
681             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
682             double bulge = 0.0;
683             if (ae->rtti()==RS2::EntityArc) {
684                 RS_DEBUG->print("RS_Modification::addPolylineNode: arc segment");
685                 bulge = ((RS_Arc*)ae)->getBulge();
686             } else {
687                 RS_DEBUG->print("RS_Modification::addPolylineNode: line segment");
688                 bulge = 0.0;
689             }
690
691             if (first) {
692                 RS_DEBUG->print("RS_Modification::addPolylineNode: first segment: %f/%f",
693                                 ae->getStartpoint().x, ae->getStartpoint().y);
694
695                 newPolyline->setNextBulge(bulge);
696                 newPolyline->addVertex(ae->getStartpoint());
697                 first = false;
698             }
699
700             // segment to split:
701             if (ae==&segment) {
702                 RS_DEBUG->print("RS_Modification::addPolylineNode: split segment found");
703
704                 RS_DEBUG->print("RS_Modification::addPolylineNode: node: %f/%f",
705                                 node.x, node.y);
706
707                 newPolyline->setNextBulge(0.0);
708                 newPolyline->addVertex(node);
709
710                 RS_DEBUG->print("RS_Modification::addPolylineNode: after node: %f/%f",
711                                 ae->getEndpoint().x, ae->getEndpoint().y);
712
713                 if (ae!=lastEntity || polyline.isClosed()==false) {
714                     newPolyline->setNextBulge(0.0);
715                     newPolyline->addVertex(ae->getEndpoint());
716                 }
717             } else {
718                 RS_DEBUG->print("RS_Modification::addPolylineNode: normal vertex found: %f/%f",
719                                 ae->getEndpoint().x, ae->getEndpoint().y);
720
721                 if (ae!=lastEntity || polyline.isClosed()==false) {
722                     newPolyline->setNextBulge(bulge);
723                     newPolyline->addVertex(ae->getEndpoint());
724                 }
725             }
726         } else {
727             RS_DEBUG->print("RS_Modification::addPolylineNode: "
728                             "Polyline contains non-atomic entities",
729                             RS_Debug::D_WARNING);
730         }
731     }
732
733     newPolyline->setNextBulge(polyline.getClosingBulge());
734     newPolyline->endPolyline();
735
736     // add new polyline:
737     container->addEntity(newPolyline);
738     if (graphicView!=NULL) {
739         graphicView->deleteEntity(&polyline);
740         graphicView->drawEntity(newPolyline);
741     }
742
743     if (document!=NULL && handleUndo) {
744         document->startUndoCycle();
745
746         polyline.setUndoState(true);
747         document->addUndoable(&polyline);
748         document->addUndoable(newPolyline);
749
750         document->endUndoCycle();
751     }
752
753     return newPolyline;
754 }
755 */
756
757
758
759 /**
760  * Deletes a node from a polyline. 
761  *
762  * @param node The node to delete.
763  *
764  * @return Pointer to the new polyline or NULL.
765  */
766 /*
767 RS_Polyline* RS_Modification::deletePolylineNode(RS_Polyline& polyline,
768         const Vector& node) {
769
770     RS_DEBUG->print("RS_Modification::deletePolylineNode");
771
772     if (container==NULL) {
773         RS_DEBUG->print("RS_Modification::addPolylineNode: no valid container",
774                         RS_Debug::D_WARNING);
775         return NULL;
776     }
777
778     if (node.valid==false) {
779         RS_DEBUG->print("RS_Modification::deletePolylineNode: "
780                         "node not valid",
781                         RS_Debug::D_WARNING);
782         return NULL;
783     }
784
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) {
792
793                 if (graphicView!=NULL) {
794                     graphicView->deleteEntity(&polyline);
795                 }
796
797                 if (document!=NULL && handleUndo) {
798                     document->startUndoCycle();
799                     polyline.setUndoState(true);
800                     document->addUndoable(&polyline);
801                     document->endUndoCycle();
802                 }
803             }
804         }
805         return NULL;
806     }
807
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());
813
814     // copy polyline and drop deleted node:
815     bool first = true;
816     bool lastDropped = false;
817     RS_Entity* lastEntity = polyline.lastEntity();
818     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
819             e=polyline.nextEntity()) {
820
821         if (e->isAtomic()) {
822             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
823             double bulge = 0.0;
824             if (ae->rtti()==RS2::EntityArc) {
825                 RS_DEBUG->print("RS_Modification::deletePolylineNode: arc segment");
826                 bulge = ((RS_Arc*)ae)->getBulge();
827             } else {
828                 RS_DEBUG->print("RS_Modification::deletePolylineNode: line segment");
829                 bulge = 0.0;
830             }
831
832             // last entity is closing entity and will be added below with endPolyline()
833             if (e==lastEntity && polyline.isClosed()) {
834                 continue;
835             }
836
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);
841
842                 newPolyline->setNextBulge(bulge);
843                 newPolyline->addVertex(ae->getStartpoint());
844                 first = false;
845             }
846
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);
851                 if (lastDropped) {
852                     //bulge = 0.0;
853                 }
854                 newPolyline->setNextBulge(bulge);
855                 newPolyline->addVertex(ae->getEndpoint());
856                 lastDropped = false;
857             }
858
859             // drop deleted node:
860             else {
861                 RS_DEBUG->print("RS_Modification::deletePolylineNode: deleting vertex: %f/%f",
862                                 ae->getEndpoint().x, ae->getEndpoint().y);
863                 lastDropped = true;
864             }
865         } else {
866             RS_DEBUG->print("RS_Modification::deletePolylineNode: "
867                             "Polyline contains non-atomic entities",
868                             RS_Debug::D_WARNING);
869         }
870     }
871
872     RS_DEBUG->print("RS_Modification::deletePolylineNode: ending polyline");
873     newPolyline->setNextBulge(polyline.getClosingBulge());
874     newPolyline->endPolyline();
875
876     //if (newPolyline->count()==1) {
877     //}
878
879     // add new polyline:
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);
885     }
886
887     RS_DEBUG->print("RS_Modification::deletePolylineNode: handling undo");
888     if (document!=NULL && handleUndo) {
889         document->startUndoCycle();
890
891         polyline.setUndoState(true);
892         document->addUndoable(&polyline);
893         document->addUndoable(newPolyline);
894
895         document->endUndoCycle();
896     }
897
898     return newPolyline;
899 }
900 */
901
902
903
904 /**
905  * Deletes all nodes between the two given nodes (exclusive).
906  *
907  * @param node1 First limiting node. 
908  * @param node2 Second limiting node. 
909  *
910  * @return Pointer to the new polyline or NULL.
911  */
912 /*
913 RS_Polyline* RS_Modification::deletePolylineNodesBetween(RS_Polyline& polyline,
914         RS_AtomicEntity& segment, const Vector& node1, const Vector& node2) {
915
916     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween");
917
918     if (container==NULL) {
919         RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
920                         RS_Debug::D_WARNING);
921         return NULL;
922     }
923
924     if (node1.valid==false || node2.valid==false) {
925         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
926                         "node not valid",
927                         RS_Debug::D_WARNING);
928         return NULL;
929     }
930
931     if (node1.distanceTo(node2)<1.0e-6) {
932         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
933                         "nodes are identical",
934                         RS_Debug::D_WARNING);
935         return NULL;
936     }
937
938     // check if there's nothing to delete:
939     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
940             e=polyline.nextEntity()) {
941
942         if (e->isAtomic()) {
943             RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
944
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)) {
949
950                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
951                                 "nothing to delete",
952                                 RS_Debug::D_WARNING);
953                 return NULL;
954             }
955         }
956     }
957
958
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;
964     }
965
966
967     // check which part of the polyline has to be deleted:
968     bool deleteStart = false;
969     if (polyline.isClosed()) {
970         bool found = false;
971         double length1 = 0.0;
972         double length2 = 0.0;
973         RS_Entity* e=polyline.firstEntity();
974
975         if (startpointInvolved) {
976             if (e->isAtomic()) {
977                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
978                 length1+=ae->getLength();
979                         }
980             e = polyline.nextEntity();
981         }
982         for (; e!=NULL; e=polyline.nextEntity()) {
983
984             if (e->isAtomic()) {
985                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
986
987                 if (node1.distanceTo(ae->getStartpoint())<1.0e-6 ||
988                         node2.distanceTo(ae->getStartpoint())<1.0e-6) {
989
990                     found = !found;
991                 }
992
993                 if (found) {
994                     length2+=ae->getLength();
995                 } else {
996                     length1+=ae->getLength();
997                 }
998             }
999         }
1000         if (length1<length2) {
1001             deleteStart = true;
1002         } else {
1003             deleteStart = false;
1004         }
1005     }
1006
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());
1012
1013     if (startpointInvolved && deleteStart && polyline.isClosed()) {
1014         newPolyline->setNextBulge(0.0);
1015         newPolyline->addVertex(polyline.getStartpoint());
1016     }
1017
1018     // copy polyline and drop deleted nodes:
1019     bool first = true;
1020     bool removing = deleteStart;
1021     bool done = false;
1022     bool nextIsStraight = false;
1023     RS_Entity* lastEntity = polyline.lastEntity();
1024     int i=0;
1025     double bulge = 0.0;
1026     for (RS_Entity* e=polyline.firstEntity(); e!=NULL;
1027             e=polyline.nextEntity()) {
1028
1029         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: entity: %d", i++);
1030         RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: removing: %d", (int)removing);
1031
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();
1037             } else {
1038                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: line segment");
1039                 bulge = 0.0;
1040             }
1041
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");
1046                 continue;
1047             }
1048
1049             // first vertex (startpoint)
1050             if (first) {
1051                 if (!removing) {
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());
1056                     first = false;
1057                 }
1058             }
1059
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);
1067                 removing = false;
1068                 done = true;
1069                                 if (first==false) {
1070                         nextIsStraight = true;
1071                                 }
1072             }
1073
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) {
1080                     bulge = 0.0;
1081                     nextIsStraight = false;
1082                 }
1083                 newPolyline->setNextBulge(bulge);
1084                 newPolyline->addVertex(ae->getEndpoint());
1085             }
1086
1087             // drop deleted node:
1088             else {
1089                 RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1090                                 "deleting vertex: %f/%f",
1091                                 ae->getEndpoint().x, ae->getEndpoint().y);
1092             }
1093
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);
1101                 removing = true;
1102             }
1103
1104             if (done) {
1105                 done=false;
1106             }
1107         } else {
1108             RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: "
1109                             "Polyline contains non-atomic entities",
1110                             RS_Debug::D_WARNING);
1111         }
1112     }
1113
1114     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: ending polyline");
1115     newPolyline->setNextBulge(polyline.getClosingBulge());
1116     newPolyline->endPolyline();
1117
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);
1124     }
1125
1126     RS_DEBUG->print("RS_Modification::deletePolylineNodesBetween: handling undo");
1127     if (document!=NULL && handleUndo) {
1128         document->startUndoCycle();
1129
1130         polyline.setUndoState(true);
1131         document->addUndoable(&polyline);
1132         document->addUndoable(newPolyline);
1133
1134         document->endUndoCycle();
1135     }
1136
1137     return newPolyline;
1138 }
1139 */
1140
1141
1142
1143 /**
1144  * Trims two segments of a polyline all nodes between the two trim segments
1145  * are removed.
1146  *
1147  * @param polyline The polyline entity.
1148  * @param segment1 First segment to trim.
1149  * @param segment2 Second segment to trim.
1150  *
1151  * @return Pointer to the new polyline or NULL.
1152  */
1153 /*
1154 RS_Polyline* RS_Modification::polylineTrim(RS_Polyline& polyline,
1155         RS_AtomicEntity& segment1,
1156         RS_AtomicEntity& segment2) {
1157
1158     RS_DEBUG->print("RS_Modification::polylineTrim");
1159
1160     if (container==NULL) {
1161         RS_DEBUG->print("RS_Modification::addPolylineNodesBetween: no valid container",
1162                         RS_Debug::D_WARNING);
1163         return NULL;
1164     }
1165
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);
1170         return NULL;
1171     }
1172
1173     if (&segment1==&segment2) {
1174         RS_DEBUG->print("RS_Modification::polylineTrim: "
1175                         "segments are identical",
1176                         RS_Debug::D_WARNING);
1177         return NULL;
1178     }
1179
1180     VectorSolutions sol;
1181     sol = RS_Information::getIntersection(&segment1, &segment2, false);
1182
1183     if (sol.getNumber()==0) {
1184         RS_DEBUG->print("RS_Modification::polylineTrim: "
1185                         "segments cannot be trimmed",
1186                         RS_Debug::D_WARNING);
1187         return NULL;
1188     }
1189
1190     // check which segment comes first in the polyline:
1191     RS_AtomicEntity* firstSegment;
1192     if (polyline.findEntity(&segment1) > polyline.findEntity(&segment2)) {
1193         firstSegment = &segment2;
1194     } else {
1195         firstSegment = &segment1;
1196     }
1197
1198     // find out if we need to trim towards the open part of the polyline
1199     bool reverseTrim;
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);
1204
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());
1210
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:
1214         bool first = true;
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()) {
1220
1221             if (e->isAtomic()) {
1222                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1223                 double bulge = 0.0;
1224                 if (ae->rtti()==RS2::EntityArc) {
1225                     RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1226                     bulge = ((RS_Arc*)ae)->getBulge();
1227                 } else {
1228                     RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1229                     bulge = 0.0;
1230                 }
1231
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");
1236                     continue;
1237                 }
1238
1239                 // first vertex (startpoint)
1240                 if (first) {
1241                     RS_DEBUG->print("RS_Modification::polylineTrim: first node: %f/%f",
1242                                     ae->getStartpoint().x, ae->getStartpoint().y);
1243
1244                     newPolyline->setNextBulge(bulge);
1245                     newPolyline->addVertex(ae->getStartpoint());
1246                     first = false;
1247                 }
1248
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));
1256                     removing = true;
1257                     nextIsStraight = true;
1258                 }
1259
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);
1264                     removing = false;
1265                 }
1266
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;
1274                     } else {
1275                         newPolyline->setNextBulge(bulge);
1276                     }
1277                     newPolyline->addVertex(ae->getEndpoint());
1278                 }
1279             } else {
1280                 RS_DEBUG->print("RS_Modification::polylineTrim: "
1281                                 "Polyline contains non-atomic entities",
1282                                 RS_Debug::D_WARNING);
1283             }
1284         }
1285     }
1286
1287     // reverse trimming: remove nodes at the ends and keep those in between
1288     else {
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()) {
1296
1297             if (e->isAtomic()) {
1298                 RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1299                 double bulge = 0.0;
1300                 if (ae->rtti()==RS2::EntityArc) {
1301                     RS_DEBUG->print("RS_Modification::polylineTrim: arc segment");
1302                     bulge = ((RS_Arc*)ae)->getBulge();
1303                 } else {
1304                     RS_DEBUG->print("RS_Modification::polylineTrim: line segment");
1305                     bulge = 0.0;
1306                 }
1307
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");
1312                     continue;
1313                 }
1314
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));
1323                     removing = false;
1324                     nextIsStraight = true;
1325                 }
1326
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));
1334                     removing = true;
1335                 }
1336
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;
1344                     } else {
1345                         newPolyline->setNextBulge(bulge);
1346                     }
1347                     newPolyline->addVertex(ae->getEndpoint());
1348                 }
1349             } else {
1350                 RS_DEBUG->print("RS_Modification::polylineTrim: "
1351                                 "Polyline contains non-atomic entities",
1352                                 RS_Debug::D_WARNING);
1353             }
1354         }
1355     }
1356
1357     RS_DEBUG->print("RS_Modification::polylineTrim: ending polyline");
1358     newPolyline->setNextBulge(polyline.getClosingBulge());
1359     newPolyline->endPolyline();
1360
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);
1367     }
1368
1369     RS_DEBUG->print("RS_Modification::polylineTrim: handling undo");
1370     if (document!=NULL && handleUndo) {
1371         document->startUndoCycle();
1372
1373         polyline.setUndoState(true);
1374         document->addUndoable(&polyline);
1375         document->addUndoable(newPolyline);
1376
1377         document->endUndoCycle();
1378     }
1379
1380     return newPolyline;
1381 }
1382 */
1383
1384
1385
1386 /**
1387  * Moves all selected entities with the given data for the move
1388  * modification.
1389  */
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);
1394         return false;
1395     }
1396
1397     RS_PtrList<RS_Entity> addList;
1398     addList.setAutoDelete(false);
1399
1400     if (document!=NULL && handleUndo) {
1401         document->startUndoCycle();
1402     }
1403
1404     // Create new entites
1405     for (int num=1;
1406             num<=data.number || (data.number==0 && num<=1);
1407             num++) {
1408         // too slow:
1409         //for (uint i=0; i<container->count(); ++i) {
1410         //RS_Entity* e = container->entityAt(i);
1411         for (RS_Entity* e=container->firstEntity();
1412                 e!=NULL;
1413                 e=container->nextEntity()) {
1414             if (e!=NULL && e->isSelected()) {
1415                 RS_Entity* ec = e->clone();
1416
1417                 ec->move(data.offset*num);
1418                 if (data.useCurrentLayer) {
1419                     ec->setLayerToActive();
1420                 }
1421                 if (data.useCurrentAttributes) {
1422                     ec->setPenToActive();
1423                 }
1424                 if (ec->rtti()==RS2::EntityInsert) {
1425                     ((RS_Insert*)ec)->update();
1426                 }
1427                 // since 2.0.4.0: keep selection
1428                 ec->setSelected(true);
1429                 addList.append(ec);
1430             }
1431         }
1432     }
1433
1434     deselectOriginals(data.number==0);
1435     addNewEntities(addList);
1436
1437     if (document!=NULL && handleUndo) {
1438         document->endUndoCycle();
1439     }
1440
1441     if (graphicView!=NULL) {
1442         graphicView->redraw();
1443     }
1444     return true;
1445 }
1446
1447
1448
1449
1450 /**
1451  * Rotates all selected entities with the given data for the rotation.
1452  */
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);
1457         return false;
1458     }
1459
1460     RS_PtrList<RS_Entity> addList;
1461     addList.setAutoDelete(false);
1462
1463     if (document!=NULL && handleUndo) {
1464         document->startUndoCycle();
1465     }
1466
1467     // Create new entites
1468     for (int num=1;
1469             num<=data.number || (data.number==0 && num<=1);
1470             num++) {
1471         for (RS_Entity* e=container->firstEntity();
1472                 e!=NULL;
1473                 e=container->nextEntity()) {
1474             //for (uint i=0; i<container->count(); ++i) {
1475             //RS_Entity* e = container->entityAt(i);
1476
1477             if (e!=NULL && e->isSelected()) {
1478                 RS_Entity* ec = e->clone();
1479                 ec->setSelected(false);
1480
1481                 ec->rotate(data.center, data.angle*num);
1482                 if (data.useCurrentLayer) {
1483                     ec->setLayerToActive();
1484                 }
1485                 if (data.useCurrentAttributes) {
1486                     ec->setPenToActive();
1487                 }
1488                 if (ec->rtti()==RS2::EntityInsert) {
1489                     ((RS_Insert*)ec)->update();
1490                 }
1491                 addList.append(ec);
1492             }
1493         }
1494     }
1495
1496     deselectOriginals(data.number==0);
1497     addNewEntities(addList);
1498
1499     if (document!=NULL && handleUndo) {
1500         document->endUndoCycle();
1501     }
1502     if (graphicView!=NULL) {
1503         graphicView->redraw();
1504     }
1505
1506     return true;
1507 }
1508
1509
1510
1511 /**
1512  * Moves all selected entities with the given data for the scale
1513  * modification.
1514  */
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);
1519         return false;
1520     }
1521
1522     RS_PtrList<RS_Entity> addList;
1523     addList.setAutoDelete(false);
1524
1525     if (document!=NULL && handleUndo) {
1526         document->startUndoCycle();
1527     }
1528
1529     // Create new entites
1530     for (int num=1;
1531             num<=data.number || (data.number==0 && num<=1);
1532             num++) {
1533         for (RS_Entity* e=container->firstEntity();
1534                 e!=NULL;
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);
1541
1542                 ec->scale(data.referencePoint, RS_Math::pow(data.factor, num));
1543                 if (data.useCurrentLayer) {
1544                     ec->setLayerToActive();
1545                 }
1546                 if (data.useCurrentAttributes) {
1547                     ec->setPenToActive();
1548                 }
1549                 if (ec->rtti()==RS2::EntityInsert) {
1550                     ((RS_Insert*)ec)->update();
1551                 }
1552                 addList.append(ec);
1553             }
1554         }
1555     }
1556
1557     deselectOriginals(data.number==0);
1558     addNewEntities(addList);
1559
1560     if (document!=NULL && handleUndo) {
1561         document->endUndoCycle();
1562     }
1563
1564     if (graphicView!=NULL) {
1565         graphicView->redraw();
1566     }
1567     return true;
1568 }
1569
1570
1571
1572 /**
1573  * Mirror all selected entities with the given data for the mirror
1574  * modification.
1575  */
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);
1580         return false;
1581     }
1582
1583     RS_PtrList<RS_Entity> addList;
1584     addList.setAutoDelete(false);
1585
1586     if (document!=NULL && handleUndo) {
1587         document->startUndoCycle();
1588     }
1589
1590     // Create new entites
1591     for (int num=1;
1592             num<=(int)data.copy || (data.copy==false && num<=1);
1593             num++) {
1594         for (RS_Entity* e=container->firstEntity();
1595                 e!=NULL;
1596                 e=container->nextEntity()) {
1597             //for (uint i=0; i<container->count(); ++i) {
1598             //RS_Entity* e = container->entityAt(i);
1599
1600             if (e!=NULL && e->isSelected()) {
1601                 RS_Entity* ec = e->clone();
1602                 ec->setSelected(false);
1603
1604                 ec->mirror(data.axisPoint1, data.axisPoint2);
1605                 if (data.useCurrentLayer) {
1606                     ec->setLayerToActive();
1607                 }
1608                 if (data.useCurrentAttributes) {
1609                     ec->setPenToActive();
1610                 }
1611                 if (ec->rtti()==RS2::EntityInsert) {
1612                     ((RS_Insert*)ec)->update();
1613                 }
1614                 addList.append(ec);
1615             }
1616         }
1617     }
1618
1619     deselectOriginals(data.copy==false);
1620     addNewEntities(addList);
1621
1622     if (document!=NULL && handleUndo) {
1623         document->endUndoCycle();
1624     }
1625
1626     if (graphicView!=NULL) {
1627         graphicView->redraw();
1628     }
1629     return true;
1630 }
1631
1632
1633
1634 /**
1635  * Rotates entities around two centers with the given parameters.
1636  */
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);
1641         return false;
1642     }
1643
1644     RS_PtrList<RS_Entity> addList;
1645     addList.setAutoDelete(false);
1646
1647     if (document!=NULL && handleUndo) {
1648         document->startUndoCycle();
1649     }
1650
1651     // Create new entites
1652     for (int num=1;
1653             num<=data.number || (data.number==0 && num<=1);
1654             num++) {
1655
1656         for (RS_Entity* e=container->firstEntity();
1657                 e!=NULL;
1658                 e=container->nextEntity()) {
1659             //for (uint i=0; i<container->count(); ++i) {
1660             //RS_Entity* e = container->entityAt(i);
1661
1662             if (e!=NULL && e->isSelected()) {
1663                 RS_Entity* ec = e->clone();
1664                 ec->setSelected(false);
1665
1666                 ec->rotate(data.center1, data.angle1*num);
1667                 Vector center2 = data.center2;
1668                 center2.rotate(data.center1, data.angle1*num);
1669
1670                 ec->rotate(center2, data.angle2*num);
1671                 if (data.useCurrentLayer) {
1672                     ec->setLayerToActive();
1673                 }
1674                 if (data.useCurrentAttributes) {
1675                     ec->setPenToActive();
1676                 }
1677                 if (ec->rtti()==RS2::EntityInsert) {
1678                     ((RS_Insert*)ec)->update();
1679                 }
1680                 addList.append(ec);
1681             }
1682         }
1683     }
1684
1685     deselectOriginals(data.number==0);
1686     addNewEntities(addList);
1687
1688     if (document!=NULL && handleUndo) {
1689         document->endUndoCycle();
1690     }
1691
1692     if (graphicView!=NULL) {
1693         graphicView->redraw();
1694     }
1695     return true;
1696 }
1697
1698
1699
1700 /**
1701  * Moves and rotates entities with the given parameters.
1702  */
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);
1707         return false;
1708     }
1709
1710     RS_PtrList<RS_Entity> addList;
1711     addList.setAutoDelete(false);
1712
1713     if (document!=NULL && handleUndo) {
1714         document->startUndoCycle();
1715     }
1716
1717     // Create new entites
1718     for (int num=1;
1719             num<=data.number || (data.number==0 && num<=1);
1720             num++) {
1721         for (RS_Entity* e=container->firstEntity();
1722                 e!=NULL;
1723                 e=container->nextEntity()) {
1724             //for (uint i=0; i<container->count(); ++i) {
1725             //RS_Entity* e = container->entityAt(i);
1726
1727             if (e!=NULL && e->isSelected()) {
1728                 RS_Entity* ec = e->clone();
1729                 ec->setSelected(false);
1730
1731                 ec->move(data.offset*num);
1732                 ec->rotate(data.referencePoint + data.offset*num,
1733                            data.angle*num);
1734                 if (data.useCurrentLayer) {
1735                     ec->setLayerToActive();
1736                 }
1737                 if (data.useCurrentAttributes) {
1738                     ec->setPenToActive();
1739                 }
1740                 if (ec->rtti()==RS2::EntityInsert) {
1741                     ((RS_Insert*)ec)->update();
1742                 }
1743                 addList.append(ec);
1744             }
1745         }
1746     }
1747
1748     deselectOriginals(data.number==0);
1749     addNewEntities(addList);
1750
1751     if (document!=NULL && handleUndo) {
1752         document->endUndoCycle();
1753     }
1754     if (graphicView!=NULL) {
1755         graphicView->redraw();
1756     }
1757
1758     return true;
1759 }
1760
1761
1762
1763 /**
1764  * Deselects all selected entities and removes them if remove is true;
1765  *
1766  * @param remove true: Remove entites.
1767  */
1768 void RS_Modification::deselectOriginals(bool remove
1769                                        ) {
1770     for (RS_Entity* e=container->firstEntity();
1771             e!=NULL;
1772             e=container->nextEntity()) {
1773
1774         //for (uint i=0; i<container->count(); ++i) {
1775         //RS_Entity* e = container->entityAt(i);
1776
1777         if (e!=NULL) {
1778             bool selected = false;
1779
1780             /*
1781                   if (e->isAtomic()) {
1782                       RS_AtomicEntity* ae = (RS_AtomicEntity*)e;
1783                       if (ae->isStartpointSelected() ||
1784                               ae->isEndpointSelected()) {
1785
1786                           selected = true;
1787                       }
1788                   }
1789             */
1790
1791             if (e->isSelected()) {
1792                 selected = true;
1793             }
1794
1795             if (selected) {
1796                 e->setSelected(false);
1797                 if (remove
1798                    ) {
1799                     //if (graphicView!=NULL) {
1800                     //    graphicView->deleteEntity(e);
1801                     //}
1802                     e->changeUndoState();
1803                     if (document!=NULL && handleUndo) {
1804                         document->addUndoable(e);
1805                     }
1806                 } else {
1807                     //if (graphicView!=NULL) {
1808                     //    graphicView->drawEntity(e);
1809                     //}
1810                 }
1811             }
1812         }
1813     }
1814 }
1815
1816
1817
1818 /**
1819  * Adds the given entities to the container and draws the entities if 
1820  * there's a graphic view available.
1821  *
1822  * @param addList Entities to add.
1823  */
1824 void RS_Modification::addNewEntities(RS_PtrList<RS_Entity>& addList) {
1825     for (RS_Entity* e=addList.first();
1826             e!=NULL;
1827             e=addList.next()) {
1828         if (e!=NULL) {
1829             container->addEntity(e);
1830             if (document!=NULL && handleUndo) {
1831                 document->addUndoable(e);
1832             }
1833             //if (graphicView!=NULL) {
1834             //    graphicView->drawEntity(e);
1835             //}
1836         }
1837     }
1838 }
1839
1840
1841
1842 /**
1843  * Trims or extends the given trimEntity to the intersection point of the
1844  * trimEntity and the limitEntity.
1845  *
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.
1853  */
1854 bool RS_Modification::trim(const Vector& trimCoord,
1855                            RS_AtomicEntity* trimEntity,
1856                            const Vector& limitCoord,
1857                            RS_Entity* limitEntity,
1858                            bool both) {
1859
1860     if (trimEntity==NULL || limitEntity==NULL) {
1861         RS_DEBUG->print(RS_Debug::D_WARNING,
1862                         "RS_Modification::trim: At least one entity is NULL");
1863         return false;
1864     }
1865
1866     if (both && !limitEntity->isAtomic()) {
1867         RS_DEBUG->print(RS_Debug::D_WARNING,
1868                         "RS_Modification::trim: limitEntity is not atomic");
1869     }
1870
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;
1877
1878         sol.alloc(128);
1879         int i=0;
1880
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);
1885
1886             if (e!=NULL) {
1887
1888                 VectorSolutions s2 = RS_Information::getIntersection(trimEntity,
1889                                         e, false);
1890
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));
1896                             }
1897                         }
1898                     }
1899                     //break;
1900                 }
1901             }
1902         }
1903     }
1904
1905     if (sol.hasValid()==false) {
1906         return false;
1907     }
1908
1909     RS_AtomicEntity* trimmed1 = NULL;
1910     RS_AtomicEntity* trimmed2 = NULL;
1911
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(),
1918                      c->getRadius(),
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);
1922     } else {
1923         trimmed1 = (RS_AtomicEntity*)trimEntity->clone();
1924         trimmed1->setHighlighted(false);
1925     }
1926     if (graphicView!=NULL) {
1927         graphicView->deleteEntity(trimEntity);
1928     }
1929
1930     // remove limit entity from view:
1931     if (both) {
1932         trimmed2 = (RS_AtomicEntity*)limitEntity->clone();
1933         trimmed2->setHighlighted(false);
1934         if (graphicView!=NULL) {
1935             graphicView->deleteEntity(limitEntity);
1936         }
1937     }
1938
1939     // trim trim entity
1940     int ind = 0;
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);
1950
1951     //RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1952     RS2::Ending ending = trimmed1->getTrimPoint(trimCoord, is);
1953
1954     switch (ending) {
1955     case RS2::EndingStart:
1956         trimmed1->trimStartpoint(is);
1957         if (trimEntity->rtti()==RS2::EntityCircle) {
1958             trimmed1->trimEndpoint(is2);
1959         }
1960         break;
1961     case RS2::EndingEnd:
1962         trimmed1->trimEndpoint(is);
1963         if (trimEntity->rtti()==RS2::EntityCircle) {
1964             trimmed1->trimStartpoint(is2);
1965         }
1966         break;
1967     default:
1968         break;
1969     }
1970
1971     // trim limit entity:
1972     if (both) {
1973         Vector is = sol.getClosest(limitCoord);
1974
1975         RS2::Ending ending = trimmed2->getTrimPoint(limitCoord, is);
1976
1977         switch (ending) {
1978         case RS2::EndingStart:
1979             trimmed2->trimStartpoint(is);
1980             break;
1981         case RS2::EndingEnd:
1982             trimmed2->trimEndpoint(is);
1983             break;
1984         default:
1985             break;
1986         }
1987     }
1988
1989     // add new trimmed trim entity:
1990     container->addEntity(trimmed1);
1991     if (graphicView!=NULL) {
1992         graphicView->drawEntity(trimmed1);
1993     }
1994
1995     // add new trimmed limit entity:
1996     if (both) {
1997         container->addEntity(trimmed2);
1998         if (graphicView!=NULL) {
1999             graphicView->drawEntity(trimmed2);
2000         }
2001     }
2002
2003     if (document!=NULL && handleUndo) {
2004         document->startUndoCycle();
2005         document->addUndoable(trimmed1);
2006         trimEntity->setUndoState(true);
2007         document->addUndoable(trimEntity);
2008         if (both) {
2009             document->addUndoable(trimmed2);
2010             limitEntity->setUndoState(true);
2011             document->addUndoable(limitEntity);
2012         }
2013         document->endUndoCycle();
2014     }
2015
2016     return true;
2017 }
2018
2019
2020
2021 /**
2022  * Trims or extends the given trimEntity by the given amount.
2023  *
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.
2028  */
2029 bool RS_Modification::trimAmount(const Vector& trimCoord,
2030                                  RS_AtomicEntity* trimEntity,
2031                                  double dist) {
2032
2033     if (trimEntity==NULL) {
2034         RS_DEBUG->print(RS_Debug::D_WARNING,
2035                         "RS_Modification::trimAmount: Entity is NULL");
2036         return false;
2037     }
2038
2039     RS_AtomicEntity* trimmed = NULL;
2040
2041     // remove trim entity:
2042     trimmed = (RS_AtomicEntity*)trimEntity->clone();
2043     if (graphicView!=NULL) {
2044         graphicView->deleteEntity(trimEntity);
2045     }
2046
2047     // trim trim entity
2048     Vector is = trimmed->getNearestDist(-dist, trimCoord);
2049     if (trimCoord.distanceTo(trimmed->getStartpoint()) <
2050             trimCoord.distanceTo(trimmed->getEndpoint())) {
2051         trimmed->trimStartpoint(is);
2052     } else {
2053         trimmed->trimEndpoint(is);
2054     }
2055
2056     // add new trimmed trim entity:
2057     container->addEntity(trimmed);
2058
2059     if (graphicView!=NULL) {
2060         graphicView->drawEntity(trimmed);
2061     }
2062
2063     if (document!=NULL && handleUndo) {
2064         document->startUndoCycle();
2065         document->addUndoable(trimmed);
2066         trimEntity->setUndoState(true);
2067         document->addUndoable(trimEntity);
2068         document->endUndoCycle();
2069     }
2070
2071     return true;
2072 }
2073
2074
2075
2076 /**
2077  * Cuts the given entity at the given point.
2078  */
2079 bool RS_Modification::cut(const Vector& cutCoord,
2080                           RS_AtomicEntity* cutEntity) {
2081
2082     if (cutEntity==NULL) {
2083         RS_DEBUG->print(RS_Debug::D_WARNING,
2084                         "RS_Modification::cut: Entity is NULL");
2085         return false;
2086     }
2087
2088     if (!cutCoord.valid) {
2089         RS_DEBUG->print(RS_Debug::D_WARNING,
2090                         "RS_Modification::cut: Point invalid.");
2091         return false;
2092     }
2093
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");
2099         return false;
2100     }
2101
2102     // delete cut entity on the screen:
2103     if (graphicView!=NULL) {
2104         graphicView->deleteEntity(cutEntity);
2105     }
2106
2107     RS_AtomicEntity* cut1 = NULL;
2108     RS_AtomicEntity* cut2 = NULL;
2109
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(),
2115                                      c->getRadius(),
2116                                      0.0,0.0, false));
2117         cut1->setPen(cutEntity->getPen());
2118         cut1->setLayer(cutEntity->getLayer());
2119         cut2 = NULL;
2120
2121         cut1->trimEndpoint(cutCoord);
2122         cut1->trimStartpoint(cutCoord);
2123     } else {
2124         cut1 = (RS_AtomicEntity*)cutEntity->clone();
2125         cut2 = (RS_AtomicEntity*)cutEntity->clone();
2126
2127         cut1->trimEndpoint(cutCoord);
2128         cut2->trimStartpoint(cutCoord);
2129     }
2130
2131     // add new cut entity:
2132     container->addEntity(cut1);
2133     if (cut2!=NULL) {
2134         container->addEntity(cut2);
2135     }
2136
2137     if (graphicView!=NULL) {
2138         graphicView->drawEntity(cut1);
2139         if (cut2!=NULL) {
2140             graphicView->drawEntity(cut2);
2141         }
2142     }
2143
2144     if (document!=NULL && handleUndo) {
2145         document->startUndoCycle();
2146         document->addUndoable(cut1);
2147         if (cut2!=NULL) {
2148             document->addUndoable(cut2);
2149         }
2150         cutEntity->setUndoState(true);
2151         document->addUndoable(cutEntity);
2152         document->endUndoCycle();
2153     }
2154
2155     return true;
2156 }
2157
2158
2159
2160 /**
2161  * Stretching.
2162  */
2163 bool RS_Modification::stretch(const Vector& firstCorner,
2164                               const Vector& secondCorner,
2165                               const Vector& offset) {
2166
2167     if (!offset.valid) {
2168         RS_DEBUG->print(RS_Debug::D_WARNING,
2169                         "RS_Modification::stretch: Offset invalid");
2170         return false;
2171     }
2172
2173     RS_PtrList<RS_Entity> addList;
2174     addList.setAutoDelete(false);
2175
2176     if (document!=NULL && handleUndo) {
2177         document->startUndoCycle();
2178     }
2179
2180     // Create new entites
2181     for (RS_Entity* e=container->firstEntity();
2182             e!=NULL;
2183             e=container->nextEntity()) {
2184         //for (int i=0; i<container->count(); ++i) {
2185         //    RS_Entity* e = container->entityAt(i);
2186
2187         if (e!=NULL &&
2188                 e->isVisible() &&
2189                 !e->isLocked() &&
2190                 (e->isInWindow(firstCorner, secondCorner) ||
2191                  e->hasEndpointsWithinWindow(firstCorner, secondCorner))) {
2192
2193             RS_Entity* ec = e->clone();
2194             ec->stretch(firstCorner, secondCorner, offset);
2195             addList.append(ec);
2196             e->setSelected(true);
2197         }
2198     }
2199
2200     deselectOriginals(true);
2201     addNewEntities(addList);
2202
2203     if (document!=NULL && handleUndo) {
2204         document->endUndoCycle();
2205     }
2206
2207     if (graphicView!=NULL) {
2208         graphicView->redraw();
2209     }
2210     return true;
2211 }
2212
2213
2214
2215 /**
2216  * Bevels a corner.
2217  *
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.
2223  */
2224 bool RS_Modification::bevel(const Vector& coord1, RS_AtomicEntity* entity1,
2225                             const Vector& coord2, RS_AtomicEntity* entity2,
2226                             RS_BevelData& data) {
2227
2228     RS_DEBUG->print("RS_Modification::bevel");
2229     
2230     if (entity1==NULL || entity2==NULL) {
2231         RS_DEBUG->print(RS_Debug::D_WARNING,
2232                         "RS_Modification::bevel: At least one entity is NULL");
2233         return false;
2234     }
2235
2236     RS_EntityContainer* baseContainer = container;
2237     bool isPolyline = false;
2238     bool isClosedPolyline = false;
2239
2240     if (document!=NULL && handleUndo) {
2241         document->startUndoCycle();
2242     }
2243
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");
2250             return false;
2251         }
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);
2259
2260             document->addUndoable(entity1->getParent());
2261             entity1->getParent()->setUndoState(true);
2262
2263             baseContainer = cl;
2264         }
2265
2266         entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2267         entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2268
2269         //baseContainer = entity1->getParent();
2270         isPolyline = true;
2271                 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2272     }
2273         
2274     RS_DEBUG->print("RS_Modification::bevel: getting intersection");
2275
2276     VectorSolutions sol =
2277         RS_Information::getIntersection(entity1, entity2, false);
2278
2279     if (sol.getNumber()==0) {
2280         return false;
2281     }
2282
2283     RS_AtomicEntity* trimmed1 = NULL;
2284     RS_AtomicEntity* trimmed2 = NULL;
2285
2286     //if (data.trim || isPolyline) {
2287         if (isPolyline) {
2288             trimmed1 = entity1;
2289             trimmed2 = entity2;
2290         } else {
2291             trimmed1 = (RS_AtomicEntity*)entity1->clone();
2292             trimmed2 = (RS_AtomicEntity*)entity2->clone();
2293         }
2294
2295         // remove trim entity (on screen):
2296         if (data.trim==true || isPolyline) {
2297             if (graphicView!=NULL) {
2298                 if (isPolyline) {
2299                     graphicView->deleteEntity(baseContainer);
2300                 } else {
2301                     graphicView->deleteEntity(entity1);
2302                     graphicView->deleteEntity(entity2);
2303                 }
2304             }
2305         }
2306
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);
2312         switch (ending1) {
2313         case RS2::EndingStart:
2314             trimmed1->trimStartpoint(is);
2315             start1 = true;
2316             break;
2317         case RS2::EndingEnd:
2318             trimmed1->trimEndpoint(is);
2319             start1 = false;
2320             break;
2321         default:
2322             break;
2323         }
2324
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);
2329         switch (ending2) {
2330         case RS2::EndingStart:
2331             trimmed2->trimStartpoint(is);
2332             start2 = true;
2333             break;
2334         case RS2::EndingEnd:
2335             trimmed2->trimEndpoint(is);
2336             start2 = false;
2337             break;
2338         default:
2339             break;
2340         }
2341     //}
2342
2343
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);
2348
2349     // final trim:
2350     RS_DEBUG->print("RS_Modification::bevel: final trim");
2351     if (data.trim==true) {
2352         switch (ending1) {
2353         case RS2::EndingStart:
2354             trimmed1->trimStartpoint(bp1);
2355             break;
2356         case RS2::EndingEnd:
2357             trimmed1->trimEndpoint(bp1);
2358             break;
2359         default:
2360             break;
2361         }
2362
2363         switch (ending2) {
2364         case RS2::EndingStart:
2365             trimmed2->trimStartpoint(bp2);
2366             break;
2367         case RS2::EndingEnd:
2368             trimmed2->trimEndpoint(bp2);
2369             break;
2370         default:
2371             break;
2372         }
2373
2374         // add new trimmed entities:
2375         if (isPolyline==false) {
2376             container->addEntity(trimmed1);
2377             container->addEntity(trimmed2);
2378         }
2379         if (graphicView!=NULL) {
2380             if (!isPolyline) {
2381                 graphicView->drawEntity(trimmed1);
2382                 graphicView->drawEntity(trimmed2);
2383             }
2384         }
2385     }
2386
2387
2388     // add bevel line:
2389     RS_DEBUG->print("RS_Modification::bevel: add bevel line");
2390     RS_Line* bevel = new RS_Line(baseContainer, RS_LineData(bp1, bp2));
2391
2392     if (isPolyline==false) {
2393         baseContainer->addEntity(bevel);
2394     } else {
2395         int idx1 = baseContainer->findEntity(trimmed1);
2396         int idx2 = baseContainer->findEntity(trimmed2);
2397
2398         bevel->setSelected(baseContainer->isSelected());
2399         bevel->setLayer(baseContainer->getLayer());
2400         bevel->setPen(baseContainer->getPen());
2401                 
2402                 bool insertAfter1 = false;
2403                 if (!isClosedPolyline) {
2404                         insertAfter1 = (idx1<idx2);
2405                 }
2406                 else {
2407                         insertAfter1 = ((idx1<idx2 && idx1!=0) || 
2408                                 (idx2==0 && idx1==(int)baseContainer->count()-1));
2409                 }
2410
2411         // insert bevel at the right position:
2412         //if ((idx1<idx2 && idx1!=0) || 
2413                 //      (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2414                 if (insertAfter1) {
2415             if (trimmed1->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2416                 bevel->reverse();
2417             }
2418             baseContainer->insertEntity(idx1+1, bevel);
2419         } else {
2420             if (trimmed2->getEndpoint().distanceTo(bevel->getStartpoint())>1.0e-4) {
2421                 bevel->reverse();
2422             }
2423             baseContainer->insertEntity(idx2+1, bevel);
2424         }
2425     }
2426
2427     if (isPolyline) {
2428         ((RS_Polyline*)baseContainer)->updateEndpoints();
2429     }
2430
2431     if (graphicView!=NULL) {
2432         if (isPolyline) {
2433             graphicView->drawEntity(baseContainer);
2434         } else {
2435             graphicView->drawEntity(bevel);
2436         }
2437     }
2438     
2439     RS_DEBUG->print("RS_Modification::bevel: handling undo");
2440
2441     if (document!=NULL && handleUndo) {
2442         //document->startUndoCycle();
2443
2444         if (isPolyline==false && data.trim==true) {
2445             document->addUndoable(trimmed1);
2446             entity1->setUndoState(true);
2447             document->addUndoable(entity1);
2448
2449             document->addUndoable(trimmed2);
2450             entity2->setUndoState(true);
2451             document->addUndoable(entity2);
2452         }
2453
2454         if (isPolyline==false) {
2455             document->addUndoable(bevel);
2456         }
2457
2458         document->endUndoCycle();
2459     }
2460
2461     if (data.trim==false) {
2462         RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements");
2463         delete trimmed1;
2464         delete trimmed2;
2465         RS_DEBUG->print("RS_Modification::bevel: delete trimmed elements: ok");
2466     }
2467
2468     return true;
2469
2470 }
2471
2472
2473
2474 /**
2475  * Rounds a corner.
2476  *
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.
2481  */
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) {
2488
2489     if (entity1==NULL || entity2==NULL) {
2490         RS_DEBUG->print(RS_Debug::D_WARNING,
2491                         "RS_Modification::round: At least one entity is NULL");
2492         return false;
2493     }
2494
2495     RS_EntityContainer* baseContainer = container;
2496     bool isPolyline = false;
2497     bool isClosedPolyline = false;
2498
2499     if (document!=NULL && handleUndo) {
2500         document->startUndoCycle();
2501     }
2502
2503     // find out whether we're rounding within a polyline:
2504     if (entity1->getParent()!=NULL && 
2505                 entity1->getParent()->rtti()==RS2::EntityPolyline) {
2506
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();
2513             }
2514             return false;
2515         }
2516
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);
2523
2524             document->addUndoable(entity1->getParent());
2525             entity1->getParent()->setUndoState(true);
2526
2527             baseContainer = cl;
2528         }
2529
2530         entity1 = (RS_AtomicEntity*)baseContainer->entityAt(entity1->getParent()->findEntity(entity1));
2531         entity2 = (RS_AtomicEntity*)baseContainer->entityAt(entity2->getParent()->findEntity(entity2));
2532
2533         isPolyline = true;
2534                 isClosedPolyline = ((RS_Polyline*)entity1)->isClosed();
2535     }
2536
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);
2541
2542     VectorSolutions sol2 =
2543         RS_Information::getIntersection(entity1, entity2, false);
2544
2545     VectorSolutions sol =
2546         RS_Information::getIntersection(par1, par2, false);
2547
2548     if (sol.getNumber()==0) {
2549         if (document!=NULL && handleUndo) {
2550             document->endUndoCycle();
2551         }
2552         return false;
2553     }
2554
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);
2562
2563     RS_Arc* arc = new RS_Arc(baseContainer,
2564                              RS_ArcData(is,
2565                                         data.radius,
2566                                         ang1, ang2,
2567                                         reversed));
2568
2569
2570     RS_AtomicEntity* trimmed1 = NULL;
2571     RS_AtomicEntity* trimmed2 = NULL;
2572
2573     if (data.trim || isPolyline) {
2574         if (isPolyline) {
2575             trimmed1 = entity1;
2576             trimmed2 = entity2;
2577         } else {
2578             trimmed1 = (RS_AtomicEntity*)entity1->clone();
2579             trimmed2 = (RS_AtomicEntity*)entity2->clone();
2580         }
2581
2582         // remove trim entity:
2583         if (graphicView!=NULL) {
2584             if (isPolyline) {
2585                 graphicView->deleteEntity(baseContainer);
2586             } else {
2587                 graphicView->deleteEntity(entity1);
2588                 graphicView->deleteEntity(entity2);
2589             }
2590         }
2591
2592         // trim entities to intersection
2593         Vector is2 = sol2.getClosest(coord2);
2594         RS2::Ending ending1 = trimmed1->getTrimPoint(coord1, is2);
2595         switch (ending1) {
2596         case RS2::EndingStart:
2597             trimmed1->trimStartpoint(p1);
2598             break;
2599         case RS2::EndingEnd:
2600             trimmed1->trimEndpoint(p1);
2601             break;
2602         default:
2603             break;
2604         }
2605
2606         is2 = sol2.getClosest(coord1);
2607         RS2::Ending ending2 = trimmed2->getTrimPoint(coord2, is2);
2608         switch (ending2) {
2609         case RS2::EndingStart:
2610             trimmed2->trimStartpoint(p2);
2611             break;
2612         case RS2::EndingEnd:
2613             trimmed2->trimEndpoint(p2);
2614             break;
2615         default:
2616             break;
2617         }
2618
2619         // add new trimmed entities:
2620         if (isPolyline==false) {
2621             container->addEntity(trimmed1);
2622             container->addEntity(trimmed2);
2623         }
2624         if (graphicView!=NULL) {
2625             if (!isPolyline) {
2626                 graphicView->drawEntity(trimmed1);
2627                 graphicView->drawEntity(trimmed2);
2628             }
2629         }
2630     }
2631
2632     // add rounding:
2633     if (isPolyline==false) {
2634         baseContainer->addEntity(arc);
2635     } else {
2636         // find out which base entity is before the rounding:
2637         int idx1 = baseContainer->findEntity(trimmed1);
2638         int idx2 = baseContainer->findEntity(trimmed2);
2639
2640         arc->setSelected(baseContainer->isSelected());
2641         arc->setLayer(baseContainer->getLayer());
2642         arc->setPen(baseContainer->getPen());
2643
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));
2649
2650                 bool insertAfter1 = false;
2651                 if (!isClosedPolyline) {
2652                         insertAfter1 = (idx1<idx2);
2653                 }
2654                 else {
2655                         insertAfter1 = ((idx1<idx2 && idx1!=0) || 
2656                                 (idx2==0 && idx1==(int)baseContainer->count()-1));
2657                 }
2658
2659         // insert rounding at the right position:
2660         //if ((idx1<idx2 && idx1!=0) || 
2661                 //      (idx2==0 && idx1==(int)baseContainer->count()-1)) {
2662         //if (idx1<idx2) {
2663         if (insertAfter1) {
2664             if (trimmed1->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2665                 arc->reverse();
2666             }
2667             baseContainer->insertEntity(idx1+1, arc);
2668         } else {
2669             if (trimmed2->getEndpoint().distanceTo(arc->getStartpoint())>1.0e-4) {
2670                 arc->reverse();
2671             }
2672             baseContainer->insertEntity(idx2+1, arc);
2673         }
2674     }
2675
2676     if (isPolyline) {
2677         ((RS_Polyline*)baseContainer)->updateEndpoints();
2678     }
2679
2680     if (graphicView!=NULL) {
2681         if (isPolyline) {
2682             graphicView->drawEntity(baseContainer);
2683         } else {
2684             graphicView->drawEntity(arc);
2685         }
2686     }
2687
2688     if (document!=NULL && handleUndo) {
2689         if (isPolyline==false && data.trim==true) {
2690             document->addUndoable(trimmed1);
2691             entity1->setUndoState(true);
2692             document->addUndoable(entity1);
2693
2694             document->addUndoable(trimmed2);
2695             entity2->setUndoState(true);
2696             document->addUndoable(entity2);
2697         }
2698
2699         if (isPolyline==false) {
2700             document->addUndoable(arc);
2701         }
2702
2703         document->endUndoCycle();
2704     }
2705
2706     delete par1;
2707     delete par2;
2708
2709     return true;
2710 }
2711
2712
2713
2714 /**
2715  * Removes the selected entity containers and adds the entities in them as
2716  * new single entities.
2717  */
2718 bool RS_Modification::explode() {
2719
2720     if (container==NULL) {
2721         RS_DEBUG->print("RS_Modification::explode: no valid container"
2722                         " for addinge entities",
2723                         RS_Debug::D_WARNING);
2724         return false;
2725     }
2726
2727     RS_PtrList<RS_Entity> addList;
2728     addList.setAutoDelete(false);
2729
2730     if (document!=NULL && handleUndo) {
2731         document->startUndoCycle();
2732     }
2733
2734     for (RS_Entity* e=container->firstEntity();
2735             e!=NULL;
2736             e=container->nextEntity()) {
2737         //for (uint i=0; i<container->count(); ++i) {
2738         //RS_Entity* e = container->entityAt(i);
2739
2740         if (e!=NULL && e->isSelected()) {
2741             if (e->isContainer()) {
2742
2743                 // add entities from container:
2744                 RS_EntityContainer* ec = (RS_EntityContainer*)e;
2745                 //ec->setSelected(false);
2746
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;
2751                 bool resolvePen;
2752                 bool resolveLayer;
2753
2754                 switch (ec->rtti()) {
2755                 case RS2::EntityText:
2756                 case RS2::EntityHatch:
2757                 case RS2::EntityPolyline:
2758                     rl = RS2::ResolveAll;
2759                     resolveLayer = true;
2760                     resolvePen = false;
2761                     break;
2762
2763                 case RS2::EntityInsert:
2764                     resolvePen = false;
2765                     resolveLayer = false;
2766                     rl = RS2::ResolveNone;
2767                     break;
2768
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;
2777                     resolvePen = false;
2778                     break;
2779
2780                 default:
2781                     rl = RS2::ResolveAll;
2782                     resolveLayer = true;
2783                     resolvePen = false;
2784                     break;
2785                 }
2786
2787                 for (RS_Entity* e2 = ec->firstEntity(rl); e2!=NULL;
2788                         e2 = ec->nextEntity(rl)) {
2789
2790                     if (e2!=NULL) {
2791                         RS_Entity* clone = e2->clone();
2792                         clone->setSelected(false);
2793                         clone->reparent(container);
2794
2795                         if (resolveLayer) {
2796                             clone->setLayer(ec->getLayer());
2797                         } else {
2798                             clone->setLayer(e2->getLayer());
2799                         }
2800
2801                         clone->setPen(ec->getPen(resolvePen));
2802
2803                         addList.append(clone);
2804
2805                         clone->update();
2806                     }
2807                 }
2808             } else {
2809                 e->setSelected(false);
2810             }
2811         }
2812     }
2813
2814     deselectOriginals(true);
2815     addNewEntities(addList);
2816
2817     if (document!=NULL && handleUndo) {
2818         document->endUndoCycle();
2819     }
2820
2821     if (graphicView!=NULL) {
2822         graphicView->redraw();
2823     }
2824
2825     return true;
2826 }
2827
2828
2829
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);
2835         return false;
2836     }
2837
2838     RS_PtrList<RS_Entity> addList;
2839     addList.setAutoDelete(false);
2840
2841     if (document!=NULL && handleUndo) {
2842         document->startUndoCycle();
2843     }
2844
2845     for (RS_Entity* e=container->firstEntity();
2846             e!=NULL;
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);
2853             } else {
2854                 e->setSelected(false);
2855             }
2856         }
2857     }
2858
2859     deselectOriginals(true);
2860     addNewEntities(addList);
2861
2862     if (document!=NULL && handleUndo) {
2863         document->endUndoCycle();
2864     }
2865
2866     if (graphicView!=NULL) {
2867         graphicView->redraw();
2868     }
2869
2870     return true;
2871 }
2872
2873
2874
2875 bool RS_Modification::explodeTextIntoLetters(RS_Text* text, RS_PtrList<RS_Entity>& addList) {
2876
2877     if (text==NULL) {
2878         return false;
2879     }
2880
2881     // iterate though lines:
2882     for (RS_Entity* e2 = text->firstEntity(); e2!=NULL;
2883             e2 = text->nextEntity()) {
2884
2885         if (e2==NULL) {
2886             break;
2887         }
2888
2889
2890         // text lines:
2891         if (e2->rtti()==RS2::EntityContainer) {
2892
2893             RS_EntityContainer* line = (RS_EntityContainer*)e2;
2894
2895             // iterate though letters:
2896             for (RS_Entity* e3 = line->firstEntity(); e3!=NULL;
2897                     e3 = line->nextEntity()) {
2898
2899                 if (e3==NULL) {
2900                     break;
2901                 }
2902
2903                 // super / sub texts:
2904                 if (e3->rtti()==RS2::EntityText) {
2905                     explodeTextIntoLetters((RS_Text*)e3, addList);
2906                 }
2907
2908                 // normal letters:
2909                 else if (e3->rtti()==RS2::EntityInsert) {
2910
2911                     RS_Insert* letter = (RS_Insert*)e3;
2912
2913                     RS_Text* tl = new RS_Text(
2914                                       container,
2915                                       RS_TextData(letter->getInsertionPoint(),
2916                                                   text->getHeight(),
2917                                                   100.0,
2918                                                   RS2::VAlignBottom, RS2::HAlignLeft,
2919                                                   RS2::LeftToRight, RS2::Exact,
2920                                                   1.0,
2921                                                   letter->getName(),
2922                                                   text->getStyle(),
2923                                                   letter->getAngle(),
2924                                                   RS2::Update));
2925
2926                     tl->setLayer(text->getLayer());
2927                     tl->setPen(text->getPen());
2928
2929                     addList.append(tl);
2930                     tl->update();
2931                 }
2932             }
2933         }
2934     }
2935
2936     return true;
2937 }
2938
2939
2940
2941 /**
2942  * Moves all reference points of selected entities with the given data.
2943  */
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);
2948         return false;
2949     }
2950
2951     RS_PtrList<RS_Entity> addList;
2952     addList.setAutoDelete(false);
2953
2954     if (document!=NULL && handleUndo) {
2955         document->startUndoCycle();
2956     }
2957
2958     // Create new entites
2959     for (RS_Entity* e=container->firstEntity();
2960             e!=NULL;
2961             e=container->nextEntity()) {
2962         if (e!=NULL && e->isSelected()) {
2963             RS_Entity* ec = e->clone();
2964
2965             ec->moveRef(data.ref, data.offset);
2966             // since 2.0.4.0: keep it selected
2967             ec->setSelected(true);
2968             addList.append(ec);
2969         }
2970     }
2971
2972     deselectOriginals(true);
2973     addNewEntities(addList);
2974
2975     if (document!=NULL && handleUndo) {
2976         document->endUndoCycle();
2977     }
2978
2979     if (graphicView!=NULL) {
2980         graphicView->redraw();
2981     }
2982     return true;
2983 }
2984
2985 // EOF