1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 
27 #include<cmath>
28 #include <QString>
29 #include <QFileInfo>
30 #include "rs_creation.h"
31 #include "rs_document.h"
32 #include "rs_constructionline.h"
33 #include "rs_graphicview.h"
34 #include "rs_graphic.h"
35 #include "rs_arc.h"
36 #include "rs_block.h"
37 #include "rs_line.h"
38 #include "rs_circle.h"
39 #include "rs_ellipse.h"
40 #include "rs_insert.h"
41 #include "rs_image.h"
42 #include "lc_hyperbola.h"
43 #include "lc_splinepoints.h"
44 #include "rs_modification.h"
45 #include "rs_information.h"
46 #include "rs_math.h"
47 #include "rs_debug.h"
48 #include "lc_undosection.h"
49 
50 /**
51  * Default constructor.
52  *
53  * @param container The container to which we will add
54  *        entities. Usually that's an RS_Graphic entity but
55  *        it can also be a polyline, text, ...
56  */
RS_Creation(RS_EntityContainer * container,RS_GraphicView * graphicView,bool handleUndo)57 RS_Creation::RS_Creation(RS_EntityContainer* container,
58 						 RS_GraphicView* graphicView,
59 						 bool handleUndo):
60 	container(container)
61   ,graphic(container?container->getGraphic():nullptr)
62   ,document(container?container->getDocument():nullptr)
63   ,graphicView(graphicView)
64   ,handleUndo(handleUndo)
65 {
66 }
67 
68 /**
69  * Creates an entity parallel to the given entity e through the given
70  * 'coord'.
71  *
72  * @param coord Coordinate to define the distance / side (typically a
73  *              mouse coordinate).
74  * @param number Number of parallels.
75  * @param e Original entity.
76  *
77  * @return Pointer to the first created parallel or nullptr if no
78  *    parallel has been created.
79  */
createParallelThrough(const RS_Vector & coord,int number,RS_Entity * e)80 RS_Entity* RS_Creation::createParallelThrough(const RS_Vector& coord,
81                                               int number,
82                                               RS_Entity* e) {
83 	if (!e) {
84 		return nullptr;
85     }
86 
87     double dist;
88 
89     if (e->rtti()==RS2::EntityLine) {
90         RS_Line* l = (RS_Line*)e;
91 		RS_ConstructionLine cl(nullptr,
92                                RS_ConstructionLineData(l->getStartpoint(),
93                                                        l->getEndpoint()));
94         dist = cl.getDistanceToPoint(coord);
95     } else {
96         dist = e->getDistanceToPoint(coord);
97     }
98 
99     if (dist<RS_MAXDOUBLE) {
100         return createParallel(coord, dist, number, e);
101     } else {
102 		return nullptr;
103     }
104 }
105 
106 
107 
108 /**
109  * Creates an entity parallel to the given entity e.
110  * Out of the 2 possible parallels, the one closest to
111  * the given coordinate is returned.
112  * Lines, Arcs and Circles can have parallels.
113  *
114  * @param coord Coordinate to define which parallel we want (typically a
115  *              mouse coordinate).
116  * @param distance Distance of the parallel.
117  * @param number Number of parallels.
118  * @param e Original entity.
119  *
120  * @return Pointer to the first created parallel or nullptr if no
121  *    parallel has been created.
122  */
createParallel(const RS_Vector & coord,double distance,int number,RS_Entity * e)123 RS_Entity* RS_Creation::createParallel(const RS_Vector& coord,
124                                        double distance, int number,
125                                        RS_Entity* e) {
126 	if (!e) {
127 		return nullptr;
128     }
129 
130     switch (e->rtti()) {
131     case RS2::EntityLine:
132         return createParallelLine(coord, distance, number, (RS_Line*)e);
133         break;
134 
135     case RS2::EntityArc:
136         return createParallelArc(coord, distance, number, (RS_Arc*)e);
137         break;
138 
139     case RS2::EntityCircle:
140         return createParallelCircle(coord, distance, number, (RS_Circle*)e);
141         break;
142 
143     case RS2::EntitySplinePoints:
144         return createParallelSplinePoints(coord, distance, number, (LC_SplinePoints*)e);
145         break;
146 
147     default:
148         break;
149     }
150 
151 	return nullptr;
152 }
153 
154 /**
155  * Creates a line parallel to the given line e.
156  * Out of the 2 possible parallels, the one closest to
157  * the given coordinate is returned.
158  *
159  * @param coord Coordinate to define which parallel we want (typically a
160  *              mouse coordinate).
161  * @param distance Distance of the parallel.
162  * @param number Number of parallels.
163  * @param e Original entity.
164  *
165  * @return Pointer to the first created parallel or nullptr if no
166  *    parallel has been created.
167  */
createParallelLine(const RS_Vector & coord,double distance,int number,RS_Line * e)168 RS_Line* RS_Creation::createParallelLine(const RS_Vector& coord,
169                                          double distance, int number,
170                                          RS_Line* e) {
171 
172 	if (!e) {
173 		return nullptr;
174     }
175 
176 	double ang = e->getAngle1() + M_PI_2;
177     RS_LineData parallelData;
178 	RS_Line* ret = nullptr;
179 
180     LC_UndoSection undo( document, handleUndo);
181     for (int num=1; num<=number; ++num) {
182 
183         // calculate 1st parallel:
184 		RS_Vector p1 = RS_Vector::polar(distance*num, ang);
185         p1 += e->getStartpoint();
186 		RS_Vector p2 = RS_Vector::polar(distance*num, ang);
187         p2 += e->getEndpoint();
188 		RS_Line parallel1{p1, p2};
189 
190         // calculate 2nd parallel:
191         p1.setPolar(distance*num, ang+M_PI);
192         p1 += e->getStartpoint();
193         p2.setPolar(distance*num, ang+M_PI);
194         p2 += e->getEndpoint();
195 		RS_Line parallel2{p1, p2};
196 
197         double dist1 = parallel1.getDistanceToPoint(coord);
198         double dist2 = parallel2.getDistanceToPoint(coord);
199         double minDist = std::min(dist1, dist2);
200 
201         if (minDist<RS_MAXDOUBLE) {
202             if (dist1<dist2) {
203                 parallelData = parallel1.getData();
204             } else {
205                 parallelData = parallel2.getData();
206             }
207 
208 			RS_Line* newLine = new RS_Line{container, parallelData};
209 			if (!ret) {
210 				ret = newLine;
211 			}
212 			setEntity(newLine);
213         }
214     }
215 
216     return ret;
217 }
218 
219 
220 
221 /**
222  * Creates a arc parallel to the given arc e.
223  * Out of the 2 possible parallels, the one closest to
224  * the given coordinate is returned.
225  *
226  * @param coord Coordinate to define which parallel we want (typically a
227  *              mouse coordinate).
228  * @param distance Distance of the parallel.
229  * @param number Number of parallels.
230  * @param e Original entity.
231  *
232  * @return Pointer to the first created parallel or nullptr if no
233  *    parallel has been created.
234  */
createParallelArc(const RS_Vector & coord,double distance,int number,RS_Arc * e)235 RS_Arc* RS_Creation::createParallelArc(const RS_Vector& coord,
236                                        double distance, int number,
237                                        RS_Arc* e) {
238 
239 	if (!e) {
240 		return nullptr;
241     }
242 
243     RS_ArcData parallelData;
244 	RS_Arc* ret = nullptr;
245 
246     bool inside = (e->getCenter().distanceTo(coord) < e->getRadius());
247 
248     if (inside) {
249         distance *= -1;
250     }
251 
252     for (int num=1; num<=number; ++num) {
253 
254         // calculate parallel:
255         bool ok = true;
256 		RS_Arc parallel1(nullptr, e->getData());
257         parallel1.setRadius(e->getRadius() + distance*num);
258         if (parallel1.getRadius()<0.0) {
259             parallel1.setRadius(RS_MAXDOUBLE);
260             ok = false;
261         }
262 
263         // calculate 2nd parallel:
264 		//RS_Arc parallel2(nullptr, e->getData());
265         //parallel2.setRadius(e->getRadius()+distance*num);
266 
267         //double dist1 = parallel1.getDistanceToPoint(coord);
268         //double dist2 = parallel2.getDistanceToPoint(coord);
269         //double minDist = min(dist1, dist2);
270 
271         //if (minDist<RS_MAXDOUBLE) {
272 		if (ok) {
273             //if (dist1<dist2) {
274             parallelData = parallel1.getData();
275             //} else {
276             //    parallelData = parallel2.getData();
277             //}
278 
279             LC_UndoSection undo( document, handleUndo);
280             RS_Arc* newArc = new RS_Arc(container, parallelData);
281 			if (!ret) {
282 				ret = newArc;
283 			}
284 			setEntity(newArc);
285         }
286     }
287 
288     return ret;
289 }
290 
291 
292 
293 /**
294  * Creates a circle parallel to the given circle e.
295  * Out of the 2 possible parallels, the one closest to
296  * the given coordinate is returned.
297  *
298  * @param coord Coordinate to define which parallel we want (typically a
299  *              mouse coordinate).
300  * @param distance Distance of the parallel.
301  * @param number Number of parallels.
302  * @param e Original entity.
303  *
304  * @return Pointer to the first created parallel or nullptr if no
305  *    parallel has been created.
306  */
createParallelCircle(const RS_Vector & coord,double distance,int number,RS_Circle * e)307 RS_Circle* RS_Creation::createParallelCircle(const RS_Vector& coord,
308                                              double distance, int number,
309                                              RS_Circle* e) {
310 
311 	if (!e) {
312 		return nullptr;
313     }
314 
315     RS_CircleData parallelData;
316 	RS_Circle* ret = nullptr;
317 
318     bool inside = (e->getCenter().distanceTo(coord) < e->getRadius());
319 
320     if (inside) {
321         distance *= -1;
322     }
323 
324     for (int num=1; num<=number; ++num) {
325 
326         // calculate parallel:
327         bool ok = true;
328 		RS_Circle parallel1(nullptr, e->getData());
329         parallel1.setRadius(e->getRadius() + distance*num);
330         if (parallel1.getRadius()<0.0) {
331             parallel1.setRadius(RS_MAXDOUBLE);
332             ok = false;
333         }
334 
335         // calculate 2nd parallel:
336 		//RS_Circle parallel2(nullptr, e->getData());
337         //parallel2.setRadius(e->getRadius()+distance*num);
338 
339         //double dist1 = parallel1.getDistanceToPoint(coord);
340         //double dist2 = parallel2.getDistanceToPoint(coord);
341         //double minDist = min(dist1, dist2);
342 
343         //if (minDist<RS_MAXDOUBLE) {
344 		if (ok) {
345             //if (dist1<dist2) {
346             parallelData = parallel1.getData();
347             //} else {
348             //    parallelData = parallel2.getData();
349             //}
350 
351             LC_UndoSection undo( document, handleUndo);
352             RS_Circle* newCircle = new RS_Circle(container, parallelData);
353 			if (!ret) {
354 				ret = newCircle;
355 			}
356 			setEntity(newCircle);
357         }
358     }
359     return ret;
360 }
361 
362 /**
363  * Creates a spline pseudo-parallel to the given circle e.
364  * Out of the 2 possible parallels, the one closest to
365  * the given coordinate is returned.
366  *
367  * @param coord Coordinate to define which parallel we want (typically a
368  *              mouse coordinate).
369  * @param distance Distance of the parallel.
370  * @param number Number of parallels.
371  * @param e Original entity.
372  *
373  * @return Pointer to the first created parallel or nullptr if no
374  *    parallel has been created.
375  */
createParallelSplinePoints(const RS_Vector & coord,double distance,int number,LC_SplinePoints * e)376 LC_SplinePoints* RS_Creation::createParallelSplinePoints(const RS_Vector& coord,
377 	double distance, int number, LC_SplinePoints* e)
378 {
379 	if(!e) return nullptr;
380 
381 	LC_SplinePoints *psp, *ret = nullptr;
382 
383     LC_UndoSection undo( document, handleUndo);
384     for(int i = 1; i <= number; ++i)
385 	{
386 		psp = (LC_SplinePoints*)e->clone();
387 		psp->offset(coord, i*distance);
388 
389 		psp->setParent(container);
390 		if(!ret) ret = psp;
391 		setEntity(psp);
392 	}
393 
394 	return ret;
395 }
396 
397 
398 /**
399  * Creates a bisecting line of the angle between the entities
400  * e1 and e2. Out of the 4 possible bisectors, the one closest to
401  * the given coordinate is returned.
402  *
403  * @param coord Coordinate to define which bisector we want (typically a
404  *              mouse coordinate).
405  * @param length Length of the bisecting line.
406  * @param num Number of bisectors
407  * @param l1 First line.
408  * @param l2 Second line.
409  *
410  * @return Pointer to the first bisector created or nullptr if no bisectors
411  *   were created.
412  */
createBisector(const RS_Vector & coord1,const RS_Vector & coord2,double length,int num,RS_Line * l1,RS_Line * l2)413 RS_Line* RS_Creation::createBisector(const RS_Vector& coord1,
414                                      const RS_Vector& coord2,
415                                      double length,
416                                      int num,
417                                      RS_Line* l1,
418                                      RS_Line* l2) {
419 
420     // check given entities:
421 	if (!(l1 && l2))
422 		return nullptr;
423 	if (!(l1->rtti()==RS2::EntityLine && l2->rtti()==RS2::EntityLine))
424 		return nullptr;
425 
426     // intersection between entities:
427 	RS_VectorSolutions const& sol =
428 			RS_Information::getIntersection(l1, l2, false);
429     RS_Vector inters = sol.get(0);
430 	if (!inters.valid) {
431 		return nullptr;
432     }
433 
434     double angle1 = inters.angleTo(l1->getNearestPointOnEntity(coord1));
435     double angle2 = inters.angleTo(l2->getNearestPointOnEntity(coord2));
436     double angleDiff = RS_Math::getAngleDifference(angle1, angle2);
437 	if (angleDiff > M_PI) {
438 		angleDiff = angleDiff - 2.*M_PI;
439     }
440 	RS_Line* ret = nullptr;
441 
442     LC_UndoSection undo( document, handleUndo);
443     for (int n=1; n <= num; ++n) {
444 
445         double angle = angle1 +
446                 (angleDiff / (num+1) * n);
447 
448 		RS_Vector const& v = RS_Vector::polar(length, angle);
449 
450 		RS_Line* newLine = new RS_Line{container, inters, inters + v};
451 		if (!ret) ret = newLine;
452 		setEntity(newLine);
453     }
454 
455     return ret;
456 }
457 
458 /**
459  * create a tangent line which is orthogonal to the given RS_Line(normal)
460  * @coord, the tangent line closest to this point
461  * @normal, the line orthogonal to the tangent line
462  * @circle, arc/circle/ellipse for tangent line
463  *
464  * Author: Dongxu Li
465  */
createLineOrthTan(const RS_Vector & coord,RS_Line * normal,RS_Entity * circle)466 RS_Line* RS_Creation::createLineOrthTan(const RS_Vector& coord,
467                                         RS_Line* normal,
468                                         RS_Entity* circle) {
469 	RS_Line* ret = nullptr;
470 
471     // check given entities:
472 	if (!(circle && normal))
473 		return ret;
474 	if (!circle->isArc())
475 		return ret;
476     //if( normal->getLength()<RS_TOLERANCE) return ret;//line too short
477 	RS_Vector const& t0 = circle->getNearestOrthTan(coord,*normal,false);
478     if(!t0.valid) return ret;
479 	RS_Vector const& vp=normal->getNearestPointOnEntity(t0, false);
480     LC_UndoSection undo( document, handleUndo);
481     ret = new RS_Line{container, vp, t0};
482     ret->setLayerToActive();
483     ret->setPenToActive();
484     return ret;
485 }
486 
487 /**
488 * Creates a tangent between a given point and a circle or arc.
489 * Out of the 2 possible tangents, the one closest to
490 * the given coordinate is returned.
491 *
492 * @param coord Coordinate to define which tangent we want (typically a
493 *              mouse coordinate).
494 * @param point Point.
495 * @param circle Circle, arc or ellipse entity.
496 */
createTangent1(const RS_Vector & coord,const RS_Vector & point,RS_Entity * circle)497 RS_Line* RS_Creation::createTangent1(const RS_Vector& coord,
498                                      const RS_Vector& point,
499                                      RS_Entity* circle) {
500 	RS_Line* ret = nullptr;
501     //RS_Vector circleCenter;
502 
503     // check given entities:
504 	if (!(circle && point.valid)) return nullptr;
505 	if (!(circle->isArc() || circle->rtti()==RS2::EntitySplinePoints)){
506 		return nullptr;
507 	}
508 
509     // the two tangent points:
510     RS_VectorSolutions sol=circle->getTangentPoint(point);
511 
512 	if (!sol.getNumber())
513 		return nullptr;
514 	RS_Vector const vp2{sol.getClosest(coord)};
515     RS_LineData d;
516     if( (vp2-point).squared() > RS_TOLERANCE2 ) {
517 		d={vp2, point};
518     }else{//the given point is a tangential point
519 		d={point+circle->getTangentDirection(point), point};
520     }
521 
522 
523     // create the closest tangent:
524     LC_UndoSection undo( document, handleUndo);
525     ret = new RS_Line{container, d};
526 	setEntity(ret);
527 
528     return ret;
529 }
530 
531 /**
532 * Creates a tangent between two circles or arcs.
533 * Out of the 4 possible tangents, the one closest to
534 * the given coordinate is returned.
535 *
536 * @param coord Coordinate to define which tangent we want (typically a
537 *              mouse coordinate).
538 * @param circle1 1st circle or arc entity.
539 * @param circle2 2nd circle or arc entity.
540 */
createTangent2(const RS_Vector & coord,RS_Entity * circle1,RS_Entity * circle2)541 RS_Line* RS_Creation::createTangent2(const RS_Vector& coord,
542                                      RS_Entity* circle1,
543                                      RS_Entity* circle2) {
544 	RS_Line* ret = nullptr;
545     RS_Vector circleCenter1;
546     RS_Vector circleCenter2;
547     double circleRadius1 = 0.0;
548     double circleRadius2 = 0.0;
549 
550     // check given entities:
551 	if(! (circle1 && circle2))
552 		return nullptr;
553 	if( !(circle1->isArc() && circle2->isArc()))
554 		return nullptr;
555 
556 	std::vector<RS_Line*> poss;
557     //        for (int i=0; i<4; ++i) {
558 	//            poss[i] = nullptr;
559     //        }
560     RS_LineData d;
561     if( circle1->rtti() == RS2::EntityEllipse) {
562         std::swap(circle1,circle2);//move Ellipse to the second place
563     }
564     circleCenter1=circle1->getCenter();
565     circleRadius1=circle1->getRadius();
566     circleCenter2=circle2->getCenter();
567     circleRadius2=circle2->getRadius();
568     if(circle2->rtti() != RS2::EntityEllipse) {
569         //no ellipse
570 
571         // create all possible tangents:
572 
573         double angle1 = circleCenter1.angleTo(circleCenter2);
574         double dist1 = circleCenter1.distanceTo(circleCenter2);
575 
576         if (dist1>1.0e-6) {
577             // outer tangents:
578             double dist2 = circleRadius2 - circleRadius1;
579             if (dist1>dist2) {
580                 double angle2 = asin(dist2/dist1);
581 				double angt1 = angle1 + angle2 + M_PI_2;
582 				double angt2 = angle1 - angle2 - M_PI_2;
583 				RS_Vector offs1 = RS_Vector::polar(circleRadius1, angt1);
584 				RS_Vector offs2 = RS_Vector::polar(circleRadius2, angt1);
585 
586 				poss.push_back( new RS_Line{circleCenter1 + offs1,
587 													  circleCenter2 + offs2});
588 
589 
590                 offs1.setPolar(circleRadius1, angt2);
591                 offs2.setPolar(circleRadius2, angt2);
592 
593 				poss.push_back( new RS_Line{circleCenter1 + offs1,
594 													  circleCenter2 + offs2});
595             }
596 
597             // inner tangents:
598             double dist3 = circleRadius2 + circleRadius1;
599             if (dist1>dist3) {
600                 double angle3 = asin(dist3/dist1);
601 				double angt3 = angle1 + angle3 + M_PI_2;
602 				double angt4 = angle1 - angle3 - M_PI_2;
603                 RS_Vector offs1;
604                 RS_Vector offs2;
605 
606                 offs1.setPolar(circleRadius1, angt3);
607                 offs2.setPolar(circleRadius2, angt3);
608 
609 				poss.push_back( new RS_Line{circleCenter1 - offs1,
610 													  circleCenter2 + offs2});
611 
612 
613                 offs1.setPolar(circleRadius1, angt4);
614                 offs2.setPolar(circleRadius2, angt4);
615 
616 				poss.push_back( new RS_Line{circleCenter1 - offs1,
617 													  circleCenter2 + offs2});
618             }
619 
620         }
621     }else{
622         //circle2 is Ellipse
623 		std::unique_ptr<RS_Ellipse> e2((RS_Ellipse*)circle2->clone());
624 //        RS_Ellipse* e2=new RS_Ellipse(nullptr,RS_EllipseData(RS_Vector(4.,1.),RS_Vector(2.,0.),0.5,0.,0.,false));
625 //        RS_Ellipse  e3(nullptr,RS_EllipseData(RS_Vector(4.,1.),RS_Vector(2.,0.),0.5,0.,0.,false));
626 //        RS_Ellipse* circle1=new RS_Ellipse(nullptr,RS_EllipseData(RS_Vector(0.,0.),RS_Vector(1.,0.),1.,0.,0.,false));
627         RS_Vector m0(circle1->getCenter());
628 //        std::cout<<"translation: "<<-m0<<std::endl;
629         e2->move(-m0); //circle1 centered at origin
630 
631         double a,b;
632         double a0(0.);
633         if(circle1->rtti() != RS2::EntityEllipse){//circle1 is either arc or circle
634             a=fabs(circle1->getRadius());
635             b=a;
636 			if(fabs(a)<RS_TOLERANCE) return nullptr;
637         }else{//circle1 is ellipse
638             RS_Ellipse* e1=static_cast<RS_Ellipse*>(circle1);
639             a0=e1->getAngle();
640 //            std::cout<<"rotation: "<<-a0<<std::endl;
641             e2->rotate(-a0);//e1 major axis along x-axis
642             a=e1->getMajorRadius();
643             b=e1->getRatio()*a;
644 			if(fabs(a)<RS_TOLERANCE || fabs(b)<RS_TOLERANCE) return nullptr;
645         }
646         RS_Vector factor1(1./a,1./b);
647 //        std::cout<<"scaling: factor1="<<factor1<<std::endl;
648         e2->scale(RS_Vector(0.,0.),factor1);//circle1 is a unit circle
649         factor1.set(a,b);
650         double a2(e2->getAngle());
651 //        std::cout<<"rotation: a2="<<-a2<<std::endl;
652         e2->rotate(-a2); //ellipse2 with major axis in x-axis direction
653         a=e2->getMajorP().x;
654         b=a*e2->getRatio();
655         RS_Vector v(e2->getCenter());
656 //        std::cout<<"Center: (x,y)="<<v<<std::endl;
657 
658 
659         std::vector<double> m(0,0.);
660         m.push_back(1./(a*a)); //ma000
661         m.push_back(1./(b*b)); //ma000
662         m.push_back(v.y*v.y-1.); //ma100
663         m.push_back(v.x*v.y); //ma101
664         m.push_back(v.x*v.x-1.); //ma111
665         m.push_back(2.*a*b*v.y); //mb10
666         m.push_back(2.*a*b*v.x); //mb11
667         m.push_back(a*a*b*b); //mc1
668 
669 		auto vs0=RS_Math::simultaneousQuadraticSolver(m); //to hold solutions
670 		if (vs0.getNumber()<1) return nullptr;
671 //        for(size_t i=0;i<vs0.getNumber();i++){
672 		for(RS_Vector vpec: vs0){
673 			RS_Vector vpe2(e2->getCenter()+
674 						   RS_Vector(vpec.y/e2->getRatio(),vpec.x*e2->getRatio()));
675             vpec.x *= -1.;//direction vector of tangent
676             RS_Vector vpe1(vpe2 - vpec*(RS_Vector::dotP(vpec,vpe2)/vpec.squared()));
677 //            std::cout<<"vpe1.squared()="<<vpe1.squared()<<std::endl;
678 			RS_Line *l=new RS_Line{vpe1, vpe2};
679             l->rotate(a2);
680             l->scale(factor1);
681             l->rotate(a0);
682             l->move(m0);
683             poss.push_back(l);
684 
685         }
686         //debugging
687 
688     }
689     // find closest tangent:
690 	if(poss.size()<1) return nullptr;
691     double minDist = RS_MAXDOUBLE;
692     double dist;
693     int idx = -1;
694 	for (size_t i=0; i<poss.size(); ++i) {
695 		if (poss[i]) {
696             poss[i]->getNearestPointOnEntity(coord,false,&dist);
697 //        std::cout<<poss.size()<<": i="<<i<<" dist="<<dist<<"\n";
698             if (dist<minDist) {
699                 minDist = dist;
700                 idx = i;
701             }
702         }
703     }
704 //idx=static_cast<int>(poss.size()*(random()/(double(1.0)+RAND_MAX)));
705     if (idx!=-1) {
706         RS_LineData d = poss[idx]->getData();
707 		for(auto p: poss){
708 			if(p)
709 				delete p;
710 		}
711 
712         LC_UndoSection undo( document, handleUndo);
713         ret = new RS_Line{container, d};
714 		setEntity(ret);
715     } else {
716 		ret = nullptr;
717     }
718 
719     return ret;
720 }
721 
722 /**
723   * create the path of centers of common tangent circles of the two given circles
724   *@ return nullptr, if failed
725   *@ at success return either an ellipse or hyperbola
726   */
createCircleTangent2(RS_Entity * circle1,RS_Entity * circle2)727  std::vector<RS_Entity*> RS_Creation::createCircleTangent2( RS_Entity* circle1,RS_Entity* circle2)
728  {
729 	std::vector<RS_Entity*> ret(0, nullptr);
730 	if (!(circle1 && circle2)) return ret;
731 	RS_Entity* e1=circle1;
732 	RS_Entity* e2=circle2;
733 
734 	if (e1->getRadius() < e2->getRadius()) std::swap(e1,e2);
735 
736 	RS_Vector center1=e1->getCenter();
737 	RS_Vector center2=e2->getCenter();
738 	RS_Vector cp=(center1+center2)*0.5;
739     double dist=center1.distanceTo(center2);
740     if(dist<RS_TOLERANCE) return ret;
741 	RS_Vector vp= center1 - cp;
742      double c=dist/(e1->getRadius()+e2->getRadius());
743 	 if( c < 1. - RS_TOLERANCE) {
744 		 //two circles intersection or one circle in the other, there's an ellipse path
745 		 ret.push_back(
746 					 new RS_Ellipse(nullptr,
747 									{cp, vp, sqrt(1. - c*c), 0., 0., false}
748 					 ));
749 	 }
750     if( dist + e2 ->getRadius() < e1->getRadius() +RS_TOLERANCE ) {
751         //one circle inside of another, the path is an ellipse
752         return ret;
753     }
754     if(c > 1. + RS_TOLERANCE) {
755         //not circle in circle, there's a hyperbola path
756     c= (e1->getRadius()  - e2->getRadius())/dist;
757 	ret.push_back(new LC_Hyperbola(nullptr, LC_HyperbolaData(cp,vp*c,sqrt(1. - c*c),0.,0.,false)));
758     return ret;
759 }
760 	ret.push_back(new RS_Line{cp, {cp.x - vp.y, cp.y+vp.x}});
761     return ret;
762 }
763 
764 /**
765      * Creates a line with a relative angle to the given entity.
766      *
767      * @param coord Coordinate to define the point where the line should end.
768      *              (typically a mouse coordinate).
769      * @param entity Pointer to basis entity. The angle is relative to the
770      *               angle of this entity.
771      * @param angle Angle of the line relative to the angle of the basis entity.
772      * @param length Length of the line we're creating.
773      */
createLineRelAngle(const RS_Vector & coord,RS_Entity * entity,double angle,double length)774 RS_Line* RS_Creation::createLineRelAngle(const RS_Vector& coord,
775                                          RS_Entity* entity,
776                                          double angle,
777                                          double length) {
778 
779     // check given entity / coord:
780 	if (!(entity && coord))
781 		return nullptr;
782 
783 	switch(entity->rtti()){
784 	default:
785 		return nullptr;
786 	case RS2::EntityArc:
787 	case RS2::EntityCircle:
788 	case RS2::EntityLine:
789 	case RS2::EntityEllipse:
790 		break;
791 	}
792 
793 	auto const vp = entity->getNearestPointOnEntity(coord, false);
794 
795 	double const a1 = angle + entity->getTangentDirection(vp).angle();
796 
797 	RS_Vector const v1 = RS_Vector::polar(length, a1);
798     //RS_ConstructionLineData(coord-v1, coord+v1);
799 
800     LC_UndoSection undo( document, handleUndo);
801     RS_Line* ret = new RS_Line{container, coord-v1, coord+v1};
802 	setEntity(ret);
803 
804     return ret;
805 }
806 
807 
808 /**
809      * Creates a polygon with 'number' edges.
810      *
811      * @param center Center of the polygon.
812      * @param corner The first corner of the polygon
813      * @param number Number of edges / corners.
814      */
createPolygon(const RS_Vector & center,const RS_Vector & corner,int number)815 RS_Line* RS_Creation::createPolygon(const RS_Vector& center,
816                                     const RS_Vector& corner,
817                                     int number) {
818     // check given coords / number:
819     if (!center.valid || !corner.valid || number<3) {
820 		return nullptr;
821     }
822 
823 	RS_Line* ret = nullptr;
824 
825 	double const r = center.distanceTo(corner);
826 	double const angle0 = center.angleTo(corner);
827 	double const da = 2.*M_PI/number;
828     LC_UndoSection undo( document, handleUndo);
829     for (int i=0; i < number; ++i) {
830 		RS_Vector const& c0 = center +
831 				RS_Vector::polar(r, angle0 + i*da);
832 		RS_Vector const& c1 = center +
833 				RS_Vector::polar(r, angle0 + ((i+1)%number)*da);
834 
835 		RS_Line* line = new RS_Line{container, c0, c1};
836         line->setLayerToActive();
837         line->setPenToActive();
838 
839 		if (!ret) ret = line;
840 
841 		if (container) {
842             container->addEntity(line);
843         }
844         undo.addUndoable(line);
845 		if (graphicView) {
846             graphicView->drawEntity(line);
847         }
848     }
849 
850     return ret;
851 }
852 
853 
854 
855 /**
856      * Creates a polygon with 'number' edges.
857      *
858      * @param corner1 The first corner of the polygon.
859      * @param corner2 The second corner of the polygon.
860      * @param number Number of edges / corners.
861      */
createPolygon2(const RS_Vector & corner1,const RS_Vector & corner2,int number)862 RS_Line* RS_Creation::createPolygon2(const RS_Vector& corner1,
863                                      const RS_Vector& corner2,
864                                      int number) {
865     // check given coords / number:
866     if (!corner1.valid || !corner2.valid || number<3) {
867 		return nullptr;
868     }
869 
870 	RS_Line* ret = nullptr;
871 
872     LC_UndoSection undo( document, handleUndo);
873     double const len = corner1.distanceTo(corner2);
874 	double const da = 2.*M_PI/number;
875 	double const r = 0.5*len/sin(0.5*da);
876 	double const angle1 = corner1.angleTo(corner2);
877 	RS_Vector center = (corner1 + corner2)*0.5;
878 
879 	//TODO, the center or the polygon could be at left or right side
880 	//left is chosen here
881 	center += RS_Vector::polar(0.5*len/tan(0.5*da), angle1 + M_PI_2);
882 	double const angle0 = center.angleTo(corner1);
883 
884 
885 	for (int i=0; i<number; ++i) {
886 		RS_Vector const& c0 = center +
887 				RS_Vector::polar(r, angle0 + i*da);
888 		RS_Vector const& c1 = center +
889 				RS_Vector::polar(r, angle0 + ((i+1)%number)*da);
890 
891 		RS_Line* line = new RS_Line{container, c0, c1};
892         line->setLayerToActive();
893         line->setPenToActive();
894 
895 		if (!ret) ret = line;
896 
897 		if (container) {
898             container->addEntity(line);
899         }
900         undo.addUndoable(line);
901 		if (graphicView) {
902             graphicView->drawEntity(line);
903         }
904 
905     }
906 
907     return ret;
908 }
909 
910 /**
911      * Creates a polygon with 'number' edges.
912      *
913      * @param center Center of the polygon.
914      * @param tangent The first tangent of the polygon with a circle
915      * @param number Number of edges / corners.
916      */
createPolygon3(const RS_Vector & center,const RS_Vector & tangent,int number)917 RS_Line* RS_Creation::createPolygon3(const RS_Vector& center,    //added by txmy
918                                      const RS_Vector& tangent,
919                                      int number) {
920     // check given coords / number:
921     if (!center.valid || !tangent.valid || number<3) {
922         return nullptr;
923     }
924 
925     RS_Line* ret = nullptr;
926 
927     LC_UndoSection undo( document, handleUndo);
928     RS_Vector corner(0, 0);
929     double angle = 2.*M_PI/number/2.0;
930     corner.x = tangent.x + (center.y - tangent.y) * tan(angle);
931     corner.y = tangent.y + (tangent.x - center.x) * tan(angle);
932 
933     double const r = center.distanceTo(corner);
934     double const angle0 = center.angleTo(corner);
935     double const da = 2.*M_PI/number;
936 
937     for (int i=0; i < number; ++i) {
938         RS_Vector const& c0 = center +
939                 RS_Vector::polar(r, angle0 + i*da);
940         RS_Vector const& c1 = center +
941                 RS_Vector::polar(r, angle0 + ((i+1)%number)*da);
942 
943         RS_Line* line = new RS_Line{container, c0, c1};
944         line->setLayerToActive();
945         line->setPenToActive();
946 
947         if (!ret) ret = line;
948 
949         if (container) {
950             container->addEntity(line);
951         }
952         undo.addUndoable(line);
953         if (graphicView) {
954             graphicView->drawEntity(line);
955         }
956     }
957 
958     return ret;
959 }
960 
961 /**
962      * Creates an insert with the given data.
963      *
964      * @param data Insert data (position, block name, ..)
965      */
createInsert(const RS_InsertData * pdata)966 RS_Insert* RS_Creation::createInsert(const RS_InsertData* pdata) {
967 
968     RS_DEBUG->print("RS_Creation::createInsert");
969 
970     LC_UndoSection undo( document, handleUndo);
971     RS_Insert* ins = new RS_Insert(container, *pdata);
972     // inserts are also on layers
973 	setEntity(ins);
974 
975     RS_DEBUG->print("RS_Creation::createInsert: OK");
976 
977     return ins;
978 }
979 
980 
981 
982 /**
983      * Creates an image with the given data.
984      */
createImage(const RS_ImageData * data)985 RS_Image* RS_Creation::createImage(const RS_ImageData* data) {
986 
987     LC_UndoSection undo( document, handleUndo);
988     RS_Image* img = new RS_Image(container, *data);
989     img->update();
990 	setEntity(img);
991 
992     return img;
993 }
994 
995 
996 /**
997      * Creates a new block from the currently selected entitiies.
998      *
999      * @param referencePoint Reference point for the block.
1000      * @param name Block name
1001      * @param remove true: remove existing entities, false: don't touch entities
1002      */
createBlock(const RS_BlockData * data,const RS_Vector & referencePoint,const bool remove)1003 RS_Block* RS_Creation::createBlock(const RS_BlockData* data,
1004                                    const RS_Vector& referencePoint,
1005                                    const bool remove) {
1006 
1007     // start undo cycle for the container if we're deleting the existing entities
1008     LC_UndoSection undo(document, remove);
1009     RS_Block* block;
1010     // Block cannot contain blocks.
1011     if (container->rtti() == RS2::EntityBlock) {
1012         block = new RS_Block(container->getParent(), RS_BlockData(*data));
1013     } else {
1014         block = new RS_Block(container, RS_BlockData(*data));
1015     }
1016 
1017 	// copy entities into a block
1018 	for(auto e: *container){
1019         //for (unsigned i=0; i<container->count(); ++i) {
1020         //RS_Entity* e = container->entityAt(i);
1021 
1022 		if (e && e->isSelected()) {
1023 
1024             // delete / redraw entity in graphic view:
1025             if (remove) {
1026 				if (graphicView) {
1027                     graphicView->deleteEntity(e);
1028                 }
1029                 e->setSelected(false);
1030             } else {
1031 				if (graphicView) {
1032                     graphicView->deleteEntity(e);
1033                 }
1034                 e->setSelected(false);
1035 				if (graphicView) {
1036                     graphicView->drawEntity(e);
1037                 }
1038             }
1039 
1040             // add entity to block:
1041             RS_Entity* c = e->clone();
1042             c->move(-referencePoint);
1043             block->addEntity(c);
1044 
1045             if (remove) {
1046                 //container->removeEntity(e);
1047                 //i=0;
1048                 e->changeUndoState();
1049                 undo.addUndoable(e);
1050             }
1051         }
1052     }
1053 
1054 	if (graphic) {
1055         graphic->addBlock(block);
1056     }
1057 
1058     return block;
1059 }
1060 
1061 
1062 
1063 /**
1064      * Inserts a library item from the given path into the drawing.
1065      */
createLibraryInsert(RS_LibraryInsertData & data)1066 RS_Insert* RS_Creation::createLibraryInsert(RS_LibraryInsertData& data) {
1067 
1068     RS_DEBUG->print("RS_Creation::createLibraryInsert");
1069 
1070     RS_Graphic g;
1071     if (!g.open(data.file, RS2::FormatUnknown)) {
1072         RS_DEBUG->print(RS_Debug::D_WARNING,
1073                         "RS_Creation::createLibraryInsert: Cannot open file: %s");
1074 		return nullptr;
1075     }
1076 
1077     // unit conversion:
1078 	if (graphic) {
1079         double uf = RS_Units::convert(1.0, g.getUnit(),
1080                                       graphic->getUnit());
1081         g.scale(RS_Vector(0.0, 0.0), RS_Vector(uf, uf));
1082     }
1083 
1084     //g.scale(RS_Vector(data.factor, data.factor));
1085     //g.rotate(data.angle);
1086 
1087     QString s;
1088     s = QFileInfo(data.file).completeBaseName();
1089 
1090     RS_Modification m(*container, graphicView);
1091     m.paste(
1092                 RS_PasteData(
1093                     data.insertionPoint,
1094                     data.factor, data.angle, true,
1095                     s),
1096                 &g);
1097 
1098     RS_DEBUG->print("RS_Creation::createLibraryInsert: OK");
1099 
1100 	return nullptr;
1101 }
1102 
setEntity(RS_Entity * en) const1103 void RS_Creation::setEntity(RS_Entity* en) const
1104 {
1105 	en->setLayerToActive();
1106 	en->setPenToActive();
1107 
1108 	if (container) {
1109 		container->addEntity(en);
1110 	}
1111     LC_UndoSection undo( document, handleUndo);
1112     undo.addUndoable(en);
1113     if (graphicView) {
1114 		graphicView->drawEntity(en);
1115 	}
1116 }
1117 
1118 
1119 // EOF
1120