]> Shamusworld >> Repos - architektonas/blob - src/base/rs_creation.cpp
Major refactoring of actions: Moved implementation from header files
[architektonas] / src / base / rs_creation.cpp
1 // rs_creation.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/28/2010  Added this text. :-)
13 //
14
15 #include "rs_creation.h"
16
17 #include "rs_constructionline.h"
18 #include "drawing.h"
19 #include "rs_graphicview.h"
20 #include "rs_image.h"
21 #include "rs_information.h"
22 #include "rs_insert.h"
23 #include "rs_modification.h"
24 #include "rs_units.h"
25
26 /**
27  * Default constructor.
28  *
29  * @param container The container to which we will add
30  *        entities. Usually that's an Drawing entity but
31  *        it can also be a polyline, text, ...
32  */
33 RS_Creation::RS_Creation(RS_EntityContainer * container, RS_GraphicView * graphicView,
34         bool handleUndo)
35 {
36         this->container = container;
37         this->graphicView = graphicView;
38         this->handleUndo = handleUndo;
39
40         if (container != NULL)
41         {
42                 graphic = container->getGraphic();
43                 document = container->getDocument();
44         }
45         else
46         {
47                 graphic = NULL;
48                 document = NULL;
49         }
50 }
51
52 /**
53  * Creates a point entity.
54  *
55  * E.g.:<br>
56  * <code>
57  * creation.createPoint(Vector(10.0, 15.0));
58  * </code>
59  *
60  * @param p position
61  */
62 /*void RS_Creation::createPoint(const Vector& p) {
63     entityContainer->addEntity(new RS_Point(entityContainer, p));
64 }*/
65
66 /**
67  * Creates a line with two points given.
68  *
69  * E.g.:<br>
70  * <code>
71  * creation.createLine2P(Vector(10.0, 10.0), Vector(100.0, 200.0));
72  * </code>
73  *
74  * @param p1 start point
75  * @param p2 end point
76  */
77 /*void RS_Creation::createLine2P(const Vector& p1, const Vector& p2) {
78     entityContainer->addEntity(new RS_Line(entityContainer,
79                                            RS_LineData(p1, p2)));
80 }*/
81
82 /**
83  * Creates a rectangle with two edge points given.
84  *
85  * E.g.:<br>
86  * <code>
87  * creation.createRectangle(Vector(5.0, 2.0), Vector(7.5, 3.0));
88  * </code>
89  *
90  * @param p1 edge one
91  * @param p2 edge two
92  */
93 /*void RS_Creation::createRectangle(const Vector& e1, const Vector& e2) {
94     Vector e21(e2.x, e1.y);
95     Vector e12(e1.x, e2.y);
96     entityContainer->addEntity(new RS_Line(entityContainer,
97                                            RS_LineData(e1, e12)));
98     entityContainer->addEntity(new RS_Line(entityContainer,
99                                            RS_LineData(e12, e2)));
100     entityContainer->addEntity(new RS_Line(entityContainer,
101                                            RS_LineData(e2, e21)));
102     entityContainer->addEntity(new RS_Line(entityContainer,
103                                            RS_LineData(e21, e1)));
104 }*/
105
106 /**
107  * Creates a polyline from the given array of entities.
108  * No checking if the entities actually fit together.
109  * Currently this is like a group.
110  *
111  * E.g.:<br>
112  * <code>
113  * RS_Polyline *pl = creation.createPolyline(Vector(25.0, 55.0));<br>
114  * pl->addVertex(Vector(50.0, 75.0));<br>
115  * </code>
116  *
117  * @param entities array of entities
118  * @param startPoint Start point of the polyline
119  */
120 /*RS_Polyline* RS_Creation::createPolyline(const Vector& startPoint) {
121     RS_Polyline* pl = new RS_Polyline(entityContainer,
122                 RS_PolylineData(startPoint, Vector(0.0,0.0), 0));
123     entityContainer->addEntity(pl);
124     return pl;
125 }*/
126
127 /**
128  * Creates an entity parallel to the given entity e through the given
129  * 'coord'.
130  *
131  * @param coord Coordinate to define the distance / side (typically a
132  *              mouse coordinate).
133  * @param number Number of parallels.
134  * @param e Original entity.
135  *
136  * @return Pointer to the first created parallel or NULL if no
137  *    parallel has been created.
138  */
139 RS_Entity * RS_Creation::createParallelThrough(const Vector & coord, int number, RS_Entity * e)
140 {
141         if (e == NULL)
142                 return NULL;
143
144         double dist;
145
146         if (e->rtti() == RS2::EntityLine)
147         {
148                 RS_Line * l = (RS_Line *)e;
149                 RS_ConstructionLine cl(NULL, RS_ConstructionLineData(l->getStartpoint(),
150                         l->getEndpoint()));
151                 dist = cl.getDistanceToPoint(coord);
152         }
153         else
154         {
155                 dist = e->getDistanceToPoint(coord);
156         }
157
158         if (dist < RS_MAXDOUBLE)
159                 return createParallel(coord, dist, number, e);
160         else
161                 return NULL;
162 }
163
164 /**
165  * Creates an entity parallel to the given entity e.
166  * Out of the 2 possible parallels, the one closest to
167  * the given coordinate is returned.
168  * Lines, Arcs and Circles can have parallels.
169  *
170  * @param coord Coordinate to define which parallel we want (typically a
171  *              mouse coordinate).
172  * @param distance Distance of the parallel.
173  * @param number Number of parallels.
174  * @param e Original entity.
175  *
176  * @return Pointer to the first created parallel or NULL if no
177  *    parallel has been created.
178  */
179 RS_Entity* RS_Creation::createParallel(const Vector& coord,
180                                        double distance, int number,
181                                        RS_Entity* e) {
182     if (e==NULL) {
183         return NULL;
184     }
185
186     switch (e->rtti()) {
187     case RS2::EntityLine:
188         return createParallelLine(coord, distance, number, (RS_Line*)e);
189         break;
190
191     case RS2::EntityArc:
192         return createParallelArc(coord, distance, number, (RS_Arc*)e);
193         break;
194
195     case RS2::EntityCircle:
196         return createParallelCircle(coord, distance, number, (RS_Circle*)e);
197         break;
198
199     default:
200         break;
201     }
202
203     return NULL;
204 }
205
206
207
208 /**
209  * Creates a line parallel to the given line e.
210  * Out of the 2 possible parallels, the one closest to
211  * the given coordinate is returned.
212  *
213  * @param coord Coordinate to define which parallel we want (typically a
214  *              mouse coordinate).
215  * @param distance Distance of the parallel.
216  * @param number Number of parallels.
217  * @param e Original entity.
218  *
219  * @return Pointer to the first created parallel or NULL if no
220  *    parallel has been created.
221  */
222 RS_Line* RS_Creation::createParallelLine(const Vector& coord,
223         double distance, int number,
224         RS_Line* e) {
225
226     if (e==NULL) {
227         return NULL;
228     }
229
230     double ang = e->getAngle1() + M_PI/2.0;
231     Vector p1, p2;
232     RS_LineData parallelData;
233     RS_Line* ret = NULL;
234
235     if (document!=NULL && handleUndo) {
236         document->startUndoCycle();
237     }
238
239     for (int num=1; num<=number; ++num) {
240
241         // calculate 1st parallel:
242         p1.setPolar(distance*num, ang);
243         p1 += e->getStartpoint();
244         p2.setPolar(distance*num, ang);
245         p2 += e->getEndpoint();
246         RS_Line parallel1(NULL, RS_LineData(p1, p2));
247
248         // calculate 2nd parallel:
249         p1.setPolar(distance*num, ang+M_PI);
250         p1 += e->getStartpoint();
251         p2.setPolar(distance*num, ang+M_PI);
252         p2 += e->getEndpoint();
253         RS_Line parallel2(NULL, RS_LineData(p1, p2));
254
255         double dist1 = parallel1.getDistanceToPoint(coord);
256         double dist2 = parallel2.getDistanceToPoint(coord);
257         double minDist = std::min(dist1, dist2);
258
259         if (minDist<RS_MAXDOUBLE) {
260             if (dist1<dist2) {
261                 parallelData = parallel1.getData();
262             } else {
263                 parallelData = parallel2.getData();
264             }
265
266
267             RS_Line* newLine = new RS_Line(container, parallelData);
268             newLine->setLayerToActive();
269             newLine->setPenToActive();
270             if (ret==NULL) {
271                 ret = newLine;
272             }
273             if (container!=NULL) {
274                 container->addEntity(newLine);
275             }
276             if (document!=NULL && handleUndo) {
277                 document->addUndoable(newLine);
278                 //document->endUndoCycle();
279             }
280             if (graphicView!=NULL) {
281                 graphicView->drawEntity(newLine);
282             }
283         }
284     }
285
286     if (document!=NULL && handleUndo) {
287         document->endUndoCycle();
288     }
289
290     return ret;
291 }
292
293
294
295 /**
296  * Creates a arc parallel to the given arc e.
297  * Out of the 2 possible parallels, the one closest to
298  * the given coordinate is returned.
299  *
300  * @param coord Coordinate to define which parallel we want (typically a
301  *              mouse coordinate).
302  * @param distance Distance of the parallel.
303  * @param number Number of parallels.
304  * @param e Original entity.
305  *
306  * @return Pointer to the first created parallel or NULL if no
307  *    parallel has been created.
308  */
309 RS_Arc* RS_Creation::createParallelArc(const Vector& coord,
310                                        double distance, int number,
311                                        RS_Arc* e) {
312
313     if (e==NULL) {
314         return NULL;
315     }
316
317     RS_ArcData parallelData;
318     RS_Arc* ret = NULL;
319
320     bool inside = (e->getCenter().distanceTo(coord) < e->getRadius());
321
322     if (inside) {
323         distance *= -1;
324     }
325
326     for (int num=1; num<=number; ++num) {
327
328         // calculate parallel:
329         bool ok = true;
330         RS_Arc parallel1(NULL, e->getData());
331         parallel1.setRadius(e->getRadius() + distance*num);
332         if (parallel1.getRadius()<0.0) {
333             parallel1.setRadius(RS_MAXDOUBLE);
334             ok = false;
335         }
336
337         // calculate 2nd parallel:
338         //RS_Arc parallel2(NULL, e->getData());
339         //parallel2.setRadius(e->getRadius()+distance*num);
340
341         //double dist1 = parallel1.getDistanceToPoint(coord);
342         //double dist2 = parallel2.getDistanceToPoint(coord);
343         //double minDist = min(dist1, dist2);
344
345         //if (minDist<RS_MAXDOUBLE) {
346         if (ok==true) {
347             //if (dist1<dist2) {
348             parallelData = parallel1.getData();
349             //} else {
350             //    parallelData = parallel2.getData();
351             //}
352
353             if (document!=NULL && handleUndo) {
354                 document->startUndoCycle();
355             }
356
357             RS_Arc* newArc = new RS_Arc(container, parallelData);
358             newArc->setLayerToActive();
359             newArc->setPenToActive();
360             if (ret==NULL) {
361                 ret = newArc;
362             }
363             if (container!=NULL) {
364                 container->addEntity(newArc);
365             }
366             if (document!=NULL && handleUndo) {
367                 document->addUndoable(newArc);
368                 document->endUndoCycle();
369             }
370             if (graphicView!=NULL) {
371                 graphicView->drawEntity(newArc);
372             }
373         }
374     }
375
376     return ret;
377 }
378
379
380
381 /**
382  * Creates a circle parallel to the given circle e.
383  * Out of the 2 possible parallels, the one closest to
384  * the given coordinate is returned.
385  *
386  * @param coord Coordinate to define which parallel we want (typically a
387  *              mouse coordinate).
388  * @param distance Distance of the parallel.
389  * @param number Number of parallels.
390  * @param e Original entity.
391  *
392  * @return Pointer to the first created parallel or NULL if no
393  *    parallel has been created.
394  */
395 RS_Circle* RS_Creation::createParallelCircle(const Vector& coord,
396         double distance, int number,
397         RS_Circle* e) {
398
399     if (e==NULL) {
400         return NULL;
401     }
402
403     RS_CircleData parallelData;
404     RS_Circle* ret = NULL;
405
406     bool inside = (e->getCenter().distanceTo(coord) < e->getRadius());
407
408     if (inside) {
409         distance *= -1;
410     }
411
412     for (int num=1; num<=number; ++num) {
413
414         // calculate parallel:
415         bool ok = true;
416         RS_Circle parallel1(NULL, e->getData());
417         parallel1.setRadius(e->getRadius() + distance*num);
418         if (parallel1.getRadius()<0.0) {
419             parallel1.setRadius(RS_MAXDOUBLE);
420             ok = false;
421         }
422
423         // calculate 2nd parallel:
424         //RS_Circle parallel2(NULL, e->getData());
425         //parallel2.setRadius(e->getRadius()+distance*num);
426
427         //double dist1 = parallel1.getDistanceToPoint(coord);
428         //double dist2 = parallel2.getDistanceToPoint(coord);
429         //double minDist = min(dist1, dist2);
430
431         //if (minDist<RS_MAXDOUBLE) {
432         if (ok==true) {
433             //if (dist1<dist2) {
434             parallelData = parallel1.getData();
435             //} else {
436             //    parallelData = parallel2.getData();
437             //}
438
439             if (document!=NULL && handleUndo) {
440                 document->startUndoCycle();
441             }
442
443             RS_Circle* newCircle = new RS_Circle(container, parallelData);
444             newCircle->setLayerToActive();
445             newCircle->setPenToActive();
446             if (ret==NULL) {
447                 ret = newCircle;
448             }
449             if (container!=NULL) {
450                 container->addEntity(newCircle);
451             }
452             if (document!=NULL && handleUndo) {
453                 document->addUndoable(newCircle);
454                 document->endUndoCycle();
455             }
456             if (graphicView!=NULL) {
457                 graphicView->drawEntity(newCircle);
458             }
459         }
460     }
461     return ret;
462 }
463
464
465
466 /**
467  * Creates a bisecting line of the angle between the entities
468  * e1 and e2. Out of the 4 possible bisectors, the one closest to
469  * the given coordinate is returned.
470  *
471  * @param coord Coordinate to define which bisector we want (typically a
472  *              mouse coordinate).
473  * @param length Length of the bisecting line.
474  * @param num Number of bisectors
475  * @param l1 First line.
476  * @param l2 Second line.
477  *
478  * @return Pointer to the first bisector created or NULL if no bisectors
479  *   were created.
480  */
481 RS_Line* RS_Creation::createBisector(const Vector& coord1,
482                                      const Vector& coord2,
483                                      double length,
484                                      int num,
485                                      RS_Line* l1,
486                                      RS_Line* l2) {
487
488     VectorSolutions sol;
489
490     // check given entities:
491     if (l1==NULL || l2==NULL ||
492             l1->rtti()!=RS2::EntityLine || l2->rtti()!=RS2::EntityLine) {
493         return NULL;
494     }
495
496     // intersection between entities:
497     sol = RS_Information::getIntersection(l1, l2, false);
498     Vector inters = sol.get(0);
499     if (inters.valid==false) {
500         return NULL;
501     }
502
503     double angle1 = inters.angleTo(l1->getNearestPointOnEntity(coord1));
504     double angle2 = inters.angleTo(l2->getNearestPointOnEntity(coord2));
505     double angleDiff = RS_Math::getAngleDifference(angle1, angle2);
506     if (angleDiff>M_PI) {
507         angleDiff = angleDiff - 2*M_PI;
508     }
509     RS_Line* ret = NULL;
510
511     if (document!=NULL && handleUndo) {
512         document->startUndoCycle();
513     }
514
515     for (int n=1; n<=num; ++n) {
516
517         double angle = angle1 +
518                        (angleDiff / (num+1) * n);
519
520         RS_LineData d;
521         Vector v;
522
523         Vector c;
524         v.setPolar(length, angle);
525         d = RS_LineData(inters, inters + v);
526
527         RS_Line* newLine = new RS_Line(container, d);
528         if (container!=NULL) {
529             newLine->setLayerToActive();
530             newLine->setPenToActive();
531             container->addEntity(newLine);
532         }
533         if (document!=NULL && handleUndo) {
534             document->addUndoable(newLine);
535         }
536         if (graphicView!=NULL) {
537             graphicView->drawEntity(newLine);
538         }
539         if (ret==NULL) {
540             ret = newLine;
541         }
542     }
543     if (document!=NULL && handleUndo) {
544         document->endUndoCycle();
545     }
546
547     return ret;
548 }
549
550
551
552 /**
553  * Creates a tangent between a given point and a circle or arc.
554  * Out of the 2 possible tangents, the one closest to
555  * the given coordinate is returned.
556  *
557  * @param coord Coordinate to define which tangent we want (typically a
558  *              mouse coordinate).
559  * @param point Point.
560  * @param circle Circle, arc or ellipse entity.
561  */
562 RS_Line* RS_Creation::createTangent1(const Vector& coord,
563                                      const Vector& point,
564                                      RS_Entity* circle) {
565     RS_Line* ret = NULL;
566     Vector circleCenter;
567
568     // check given entities:
569     if (circle==NULL || !point.valid ||
570             (circle->rtti()!=RS2::EntityArc && circle->rtti()!=RS2::EntityCircle
571              && circle->rtti()!=RS2::EntityEllipse)) {
572
573         return NULL;
574     }
575
576     if (circle->rtti()==RS2::EntityCircle) {
577         circleCenter = ((RS_Circle*)circle)->getCenter();
578     } else if (circle->rtti()==RS2::EntityArc) {
579         circleCenter = ((RS_Arc*)circle)->getCenter();
580     } else if (circle->rtti()==RS2::EntityEllipse) {
581         circleCenter = ((RS_Ellipse*)circle)->getCenter();
582     }
583
584     // the two tangent points:
585     VectorSolutions sol;
586
587     // calculate tangent points for arcs / circles:
588     if (circle->rtti()!=RS2::EntityEllipse) {
589         // create temp. thales circle:
590         Vector tCenter = (point + circleCenter)/2.0;
591         double tRadius = point.distanceTo(tCenter);
592
593         RS_Circle tmp(NULL, RS_CircleData(tCenter, tRadius));
594
595         // get the two intersection points which are the tangent points:
596         sol = RS_Information::getIntersection(&tmp, circle, false);
597     }
598
599     // calculate tangent points for ellipses:
600     else {
601         RS_Ellipse* el = (RS_Ellipse*)circle;
602         sol.alloc(2);
603         //sol.set(0, circleCenter);
604         //sol.set(1, circleCenter);
605
606
607         double a = el->getMajorRadius();     // the length of the major axis / 2
608         double b = el->getMinorRadius();     // the length of the minor axis / 2
609
610                 // rotate and move point:
611                 Vector point2 = point;
612                 point2.move(-el->getCenter());
613                 point2.rotate(-el->getAngle());
614
615         double xp = point2.x;             // coordinates of the given point
616         double yp = point2.y;
617
618         double xt1;                      // Tangent point 1
619         double yt1;
620         double xt2;                      // Tangent point 2
621         double yt2;
622
623         double a2 = a * a;
624         double b2 = b * b;
625         double d = a2 / b2 * yp / xp;
626         double e = a2 / xp;
627         double af = b2 * d * d + a2;
628         double bf = -b2 * d * e * 2.0;
629         double cf = b2 * e * e - a2 * b2;
630         double t = sqrt(bf * bf - af * cf * 4.0);
631         yt1 = (t - bf) / (af * 2.0);
632         xt1 = e - d * yt1;
633         yt2 = (-t - bf) / (af * 2.0);
634         xt2 = e - d * yt2;
635
636                 Vector s1 = Vector(xt1, yt1);
637                 Vector s2 = Vector(xt2, yt2);
638
639                 s1.rotate(el->getAngle());
640                 s1.move(el->getCenter());
641
642                 s2.rotate(el->getAngle());
643                 s2.move(el->getCenter());
644
645                 sol.set(0, s1);
646                 sol.set(1, s2);
647
648
649     }
650
651     if (!sol.get(0).valid || !sol.get(1).valid) {
652         return NULL;
653     }
654
655     // create all possible tangents:
656     RS_Line* poss[2];
657
658     RS_LineData d;
659
660     d = RS_LineData(sol.get(0), point);
661     poss[0] = new RS_Line(NULL, d);
662     d = RS_LineData(sol.get(1), point);
663     poss[1] = new RS_Line(NULL, d);
664
665     // find closest tangent:
666     double minDist = RS_MAXDOUBLE;
667     double dist;
668     int idx = -1;
669     for (int i=0; i<2; ++i) {
670         dist = poss[i]->getDistanceToPoint(coord);
671         if (dist<minDist) {
672             minDist = dist;
673             idx = i;
674         }
675     }
676
677     // create the closest tangent:
678     if (idx!=-1) {
679         RS_LineData d = poss[idx]->getData();
680
681         for (int i=0; i<2; ++i) {
682             delete poss[i];
683         }
684
685         if (document!=NULL && handleUndo) {
686             document->startUndoCycle();
687         }
688
689         ret = new RS_Line(container, d);
690         ret->setLayerToActive();
691         ret->setPenToActive();
692         if (container!=NULL) {
693             container->addEntity(ret);
694         }
695         if (document!=NULL && handleUndo) {
696             document->addUndoable(ret);
697             document->endUndoCycle();
698         }
699         if (graphicView!=NULL) {
700             graphicView->drawEntity(ret);
701         }
702     } else {
703         ret = NULL;
704     }
705
706     return ret;
707 }
708
709
710
711 /**
712  * Creates a tangent between two circles or arcs.
713  * Out of the 4 possible tangents, the one closest to
714  * the given coordinate is returned.
715  *
716  * @param coord Coordinate to define which tangent we want (typically a
717  *              mouse coordinate).
718  * @param circle1 1st circle or arc entity.
719  * @param circle2 2nd circle or arc entity.
720  */
721 RS_Line* RS_Creation::createTangent2(const Vector& coord,
722                                      RS_Entity* circle1,
723                                      RS_Entity* circle2) {
724     RS_Line* ret = NULL;
725     Vector circleCenter1;
726     Vector circleCenter2;
727     double circleRadius1 = 0.0;
728     double circleRadius2 = 0.0;
729
730     // check given entities:
731     if (circle1==NULL || circle2==NULL ||
732             (circle1->rtti()!=RS2::EntityArc &&
733              circle1->rtti()!=RS2::EntityCircle) ||
734             (circle2->rtti()!=RS2::EntityArc &&
735              circle2->rtti()!=RS2::EntityCircle) ) {
736
737         return NULL;
738     }
739
740     if (circle1->rtti()==RS2::EntityCircle) {
741         circleCenter1 = ((RS_Circle*)circle1)->getCenter();
742         circleRadius1 = ((RS_Circle*)circle1)->getRadius();
743     } else if (circle1->rtti()==RS2::EntityArc) {
744         circleCenter1 = ((RS_Arc*)circle1)->getCenter();
745         circleRadius1 = ((RS_Arc*)circle1)->getRadius();
746     }
747
748     if (circle2->rtti()==RS2::EntityCircle) {
749         circleCenter2 = ((RS_Circle*)circle2)->getCenter();
750         circleRadius2 = ((RS_Circle*)circle2)->getRadius();
751     } else if (circle2->rtti()==RS2::EntityArc) {
752         circleCenter2 = ((RS_Arc*)circle2)->getCenter();
753         circleRadius2 = ((RS_Arc*)circle2)->getRadius();
754     }
755
756     // create all possible tangents:
757     RS_Line* poss[4];
758     for (int i=0; i<4; ++i) {
759         poss[i] = NULL;
760     }
761
762     RS_LineData d;
763
764     double angle1 = circleCenter1.angleTo(circleCenter2);
765     double dist1 = circleCenter1.distanceTo(circleCenter2);
766
767     if (dist1>1.0e-6) {
768         // outer tangents:
769         double dist2 = circleRadius2 - circleRadius1;
770         if (dist1>dist2) {
771             double angle2 = asin(dist2/dist1);
772             double angt1 = angle1 + angle2 + M_PI/2.0;
773             double angt2 = angle1 - angle2 - M_PI/2.0;
774             Vector offs1;
775             Vector offs2;
776
777             offs1.setPolar(circleRadius1, angt1);
778             offs2.setPolar(circleRadius2, angt1);
779
780             d = RS_LineData(circleCenter1 + offs1,
781                             circleCenter2 + offs2);
782             poss[0] = new RS_Line(NULL, d);
783
784
785             offs1.setPolar(circleRadius1, angt2);
786             offs2.setPolar(circleRadius2, angt2);
787
788             d = RS_LineData(circleCenter1 + offs1,
789                             circleCenter2 + offs2);
790             poss[1] = new RS_Line(NULL, d);
791         }
792
793         // inner tangents:
794         double dist3 = circleRadius2 + circleRadius1;
795         if (dist1>dist3) {
796             double angle3 = asin(dist3/dist1);
797             double angt3 = angle1 + angle3 + M_PI/2.0;
798             double angt4 = angle1 - angle3 - M_PI/2.0;
799             Vector offs1;
800             Vector offs2;
801
802             offs1.setPolar(circleRadius1, angt3);
803             offs2.setPolar(circleRadius2, angt3);
804
805             d = RS_LineData(circleCenter1 - offs1,
806                             circleCenter2 + offs2);
807             poss[2] = new RS_Line(NULL, d);
808
809
810             offs1.setPolar(circleRadius1, angt4);
811             offs2.setPolar(circleRadius2, angt4);
812
813             d = RS_LineData(circleCenter1 - offs1,
814                             circleCenter2 + offs2);
815             poss[3] = new RS_Line(NULL, d);
816         }
817
818     }
819
820     // find closest tangent:
821     double minDist = RS_MAXDOUBLE;
822     double dist;
823     int idx = -1;
824     for (int i=0; i<4; ++i) {
825         if (poss[i]!=NULL) {
826             dist = poss[i]->getDistanceToPoint(coord);
827             if (dist<minDist) {
828                 minDist = dist;
829                 idx = i;
830             }
831         }
832     }
833
834     if (idx!=-1) {
835         RS_LineData d = poss[idx]->getData();
836         for (int i=0; i<4; ++i) {
837             if (poss[i]!=NULL) {
838                 delete poss[i];
839             }
840         }
841
842         if (document!=NULL && handleUndo) {
843             document->startUndoCycle();
844         }
845
846         ret = new RS_Line(container, d);
847         ret->setLayerToActive();
848         ret->setPenToActive();
849         if (container!=NULL) {
850             container->addEntity(ret);
851         }
852         if (document!=NULL && handleUndo) {
853             document->addUndoable(ret);
854             document->endUndoCycle();
855         }
856         if (graphicView!=NULL) {
857             graphicView->drawEntity(ret);
858         }
859     } else {
860         ret = NULL;
861     }
862
863     return ret;
864 }
865
866
867 /**
868  * Creates a line with a relative angle to the given entity.
869  *
870  * @param coord Coordinate to define the point where the line should end.
871  *              (typically a mouse coordinate).
872  * @param entity Pointer to basis entity. The angle is relative to the
873  *               angle of this entity.
874  * @param angle Angle of the line relative to the angle of the basis entity.
875  * @param length Length of the line we're creating.
876  */
877 RS_Line* RS_Creation::createLineRelAngle(const Vector& coord,
878         RS_Entity* entity,
879         double angle,
880         double length) {
881
882     // check given entity / coord:
883     if (entity==NULL || !coord.valid ||
884             (entity->rtti()!=RS2::EntityArc && entity->rtti()!=RS2::EntityCircle
885              && entity->rtti()!=RS2::EntityLine)) {
886
887         return NULL;
888     }
889
890     double a1=0.0;
891
892     switch (entity->rtti()) {
893     case RS2::EntityLine:
894         a1 = ((RS_Line*)entity)->getAngle1();
895         break;
896     case RS2::EntityArc:
897         a1 = ((RS_Arc*)entity)->getCenter().angleTo(coord) + M_PI/2.0;
898         break;
899     case RS2::EntityCircle:
900         a1 = ((RS_Circle*)entity)->getCenter().angleTo(coord);
901         break;
902     default:
903         // never reached
904         break;
905     }
906
907     a1 += angle;
908
909     Vector v1;
910     v1.setPolar(length, a1);
911     //RS_ConstructionLineData(coord-v1, coord+v1);
912     RS_LineData d(coord-v1, coord+v1);
913     RS_Line* ret;
914
915     if (document!=NULL && handleUndo) {
916         document->startUndoCycle();
917     }
918
919     ret = new RS_Line(container, d);
920     ret->setLayerToActive();
921     ret->setPenToActive();
922     if (container!=NULL) {
923         container->addEntity(ret);
924     }
925     if (document!=NULL && handleUndo) {
926         document->addUndoable(ret);
927         document->endUndoCycle();
928     }
929     if (graphicView!=NULL) {
930         graphicView->drawEntity(ret);
931     }
932
933     return ret;
934 }
935
936
937 /**
938  * Creates a polygon with 'number' edges.
939  *
940  * @param center Center of the polygon.
941  * @param corner The first corner of the polygon
942  * @param number Number of edges / corners.
943  */
944 RS_Line* RS_Creation::createPolygon(const Vector& center,
945                                     const Vector& corner,
946                                     int number) {
947
948     // check given coords / number:
949     if (!center.valid || !corner.valid || number<3) {
950         return NULL;
951     }
952
953     RS_Line* ret = NULL;
954
955     if (document!=NULL && handleUndo) {
956         document->startUndoCycle();
957     }
958
959     Vector c1(false);
960     Vector c2 = corner;
961     RS_Line* line;
962
963     for (int n=1; n<=number; ++n) {
964         c1 = c2;
965         c2 = c2.rotate(center, (M_PI*2)/number);
966
967         line = new RS_Line(container, RS_LineData(c1, c2));
968         line->setLayerToActive();
969         line->setPenToActive();
970
971         if (ret==NULL) {
972             ret = line;
973         }
974
975         if (container!=NULL) {
976             container->addEntity(line);
977         }
978         if (document!=NULL && handleUndo) {
979             document->addUndoable(line);
980         }
981         if (graphicView!=NULL) {
982             graphicView->drawEntity(line);
983         }
984     }
985
986     if (document!=NULL && handleUndo) {
987         document->endUndoCycle();
988     }
989
990     return ret;
991 }
992
993
994
995 /**
996  * Creates a polygon with 'number' edges.
997  *
998  * @param corner1 The first corner of the polygon.
999  * @param corner2 The second corner of the polygon.
1000  * @param number Number of edges / corners.
1001  */
1002 RS_Line* RS_Creation::createPolygon2(const Vector& corner1,
1003                                      const Vector& corner2,
1004                                      int number) {
1005
1006     // check given coords / number:
1007     if (!corner1.valid || !corner2.valid || number<3) {
1008         return NULL;
1009     }
1010
1011     RS_Line* ret = NULL;
1012
1013     if (document!=NULL && handleUndo) {
1014         document->startUndoCycle();
1015     }
1016
1017     double len = corner1.distanceTo(corner2);
1018     double ang1 = corner1.angleTo(corner2);
1019     double ang = ang1;
1020
1021     Vector c1(false);
1022     Vector c2 = corner1;
1023     Vector edge;
1024     RS_Line* line;
1025
1026     for (int n=1; n<=number; ++n) {
1027         c1 = c2;
1028         edge.setPolar(len, ang);
1029         c2 = c1 + edge;
1030
1031         line = new RS_Line(container, RS_LineData(c1, c2));
1032         line->setLayerToActive();
1033         line->setPenToActive();
1034
1035         if (ret==NULL) {
1036             ret = line;
1037         }
1038
1039         if (container!=NULL) {
1040             container->addEntity(line);
1041         }
1042         if (document!=NULL && handleUndo) {
1043             document->addUndoable(line);
1044         }
1045         if (graphicView!=NULL) {
1046             graphicView->drawEntity(line);
1047         }
1048
1049         // more accurate than incrementing the angle:
1050         ang = ang1 + (2*M_PI)/number*n;
1051     }
1052
1053     if (document!=NULL && handleUndo) {
1054         document->endUndoCycle();
1055     }
1056
1057     return ret;
1058 }
1059
1060 /**
1061  * Creates an insert with the given data.
1062  *
1063  * @param data Insert data (position, block name, ..)
1064  */
1065 RS_Insert* RS_Creation::createInsert(RS_InsertData & data)
1066 {
1067         RS_DEBUG->print("RS_Creation::createInsert");
1068
1069         if (document != NULL && handleUndo)
1070                 document->startUndoCycle();
1071
1072         RS_Insert * ins = new RS_Insert(container, data);
1073         // inserts are also on layers
1074         ins->setLayerToActive();
1075         ins->setPenToActive();
1076
1077         if (container != NULL)
1078                 container->addEntity(ins);
1079
1080         if (document != NULL && handleUndo)
1081         {
1082                 document->addUndoable(ins);
1083                 document->endUndoCycle();
1084         }
1085
1086         if (graphicView != NULL)
1087                 graphicView->drawEntity(ins);
1088
1089         RS_DEBUG->print("RS_Creation::createInsert: OK");
1090
1091         return ins;
1092 }
1093
1094 /**
1095  * Creates an image with the given data.
1096  */
1097 RS_Image* RS_Creation::createImage(RS_ImageData& data) {
1098
1099     if (document!=NULL && handleUndo) {
1100         document->startUndoCycle();
1101     }
1102
1103     RS_Image* img = new RS_Image(container, data);
1104     img->setLayerToActive();
1105     img->setPenToActive();
1106     img->update();
1107
1108     if (container!=NULL) {
1109         container->addEntity(img);
1110     }
1111     if (document!=NULL && handleUndo) {
1112         document->addUndoable(img);
1113         document->endUndoCycle();
1114     }
1115     if (graphicView!=NULL) {
1116         graphicView->drawEntity(img);
1117     }
1118
1119     return img;
1120 }
1121
1122 /**
1123  * Creates a new block from the currently selected entitiies.
1124  *
1125  * @param referencePoint Reference point for the block.
1126  * @param name Block name
1127  * @param remove true: remove existing entities, false: don't touch entities
1128  */
1129 RS_Block * RS_Creation::createBlock(const RS_BlockData & data,
1130         const Vector & referencePoint, const bool remove)
1131 {
1132         // start undo cycle for the container if we're deleting the existing entities
1133         if (remove && document!=NULL) {
1134                 document->startUndoCycle();
1135         }
1136
1137         RS_Block* block =
1138                 new RS_Block(container,
1139                                                 RS_BlockData(data.name, data.basePoint, data.frozen));
1140
1141         // copy entities into a block
1142         for(RS_Entity * e=container->firstEntity(); e!=NULL; e=container->nextEntity())
1143         {
1144                 //for (uint i=0; i<container->count(); ++i) {
1145                 //RS_Entity* e = container->entityAt(i);
1146
1147                 if (e != NULL && e->isSelected())
1148                 {
1149                         // delete / redraw entity in graphic view:
1150                         if (remove)
1151                         {
1152                                 if (graphicView != NULL)
1153                                         graphicView->deleteEntity(e);
1154
1155                                 e->setSelected(false);
1156                         }
1157                         else
1158                         {
1159                                 if (graphicView != NULL)
1160                                         graphicView->deleteEntity(e);
1161
1162                                 e->setSelected(false);
1163
1164                                 if (graphicView != NULL)
1165                                         graphicView->drawEntity(e);
1166                         }
1167
1168                         // add entity to block:
1169                         RS_Entity * c = e->clone();
1170                         c->move(-referencePoint);
1171                         block->addEntity(c);
1172
1173                         if (remove)
1174                         {
1175                                 //container->removeEntity(e);
1176                                 //i=0;
1177                                 e->changeUndoState();
1178
1179                                 if (document != NULL)
1180                                         document->addUndoable(e);
1181                         }
1182                 }
1183         }
1184
1185         if (remove && document != NULL)
1186                 document->endUndoCycle();
1187
1188         if (graphic != NULL)
1189                 graphic->addBlock(block);
1190
1191         return block;
1192 }
1193
1194 /**
1195  * Inserts a library item from the given path into the drawing.
1196  */
1197 RS_Insert * RS_Creation::createLibraryInsert(RS_LibraryInsertData & data)
1198 {
1199         RS_DEBUG->print("RS_Creation::createLibraryInsert");
1200         Drawing g;
1201
1202         if (!g.open(data.file, RS2::FormatUnknown))
1203         {
1204                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Creation::createLibraryInsert: Cannot open file: %s");
1205                 return NULL;
1206         }
1207
1208         // unit conversion:
1209         if (graphic != NULL)
1210         {
1211                 double uf = RS_Units::convert(1.0, g.getUnit(), graphic->getUnit());
1212                 g.scale(Vector(0.0, 0.0), Vector(uf, uf));
1213         }
1214
1215         //g.scale(Vector(data.factor, data.factor));
1216         //g.rotate(data.angle);
1217
1218 //      QString s = QFileInfo(data.file).baseName(true);
1219         QString s = QFileInfo(data.file).completeBaseName();
1220
1221         RS_Modification m(*container, graphicView);
1222         m.paste(RS_PasteData(data.insertionPoint, data.factor, data.angle, true, s), &g);
1223
1224         RS_DEBUG->print("RS_Creation::createLibraryInsert: OK");
1225
1226         return NULL;
1227 }