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