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