]> Shamusworld >> Repos - architektonas/blob - src/base/rs_information.cpp
GPL compliance check...
[architektonas] / src / base / rs_information.cpp
1 // rs_information.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  06/01/2010  Added this text. :-)
15 //
16
17 #include "rs_information.h"
18
19 #include "rs_constructionline.h"
20
21 /**
22  * Default constructor.
23  *
24  * @param container The container to which we will add
25  *        entities. Usually that's an Drawing entity but
26  *        it can also be a polyline, text, ...
27  */
28 RS_Information::RS_Information(RS_EntityContainer& container)
29 {
30         this->container = &container;
31 }
32
33 /**
34  * @return true: if the entity is a dimensioning enity.
35  *         false: otherwise
36  */
37 bool RS_Information::isDimension(RS2::EntityType type)
38 {
39     if (type==RS2::EntityDimAligned ||
40             type==RS2::EntityDimLinear ||
41             type==RS2::EntityDimRadial ||
42             type==RS2::EntityDimDiametric ||
43             type==RS2::EntityDimAngular) {
44         return true;
45     } else {
46         return false;
47     }
48 }
49
50
51
52 /**
53  * @retval true the entity can be trimmed.
54  * i.e. it is in a graphic or in a polyline.
55  */
56 bool RS_Information::isTrimmable(RS_Entity* e) {
57         if (e!=NULL) {
58                 if (e->getParent()!=NULL) {
59                         if (e->getParent()->rtti()==RS2::EntityPolyline) {
60                                 return true;
61                         }
62                         else if (e->getParent()->rtti()==RS2::EntityContainer ||
63                                   e->getParent()->rtti()==RS2::EntityGraphic ||
64                                           e->getParent()->rtti()==RS2::EntityBlock) {
65
66                                 // normal entity:
67                                 return true;
68                         }
69                 }
70         }
71
72         return false;
73 }
74
75
76 /**
77  * @retval true the two entities can be trimmed to each other;
78  * i.e. they are in a graphic or in the same polyline.
79  */
80 bool RS_Information::isTrimmable(RS_Entity* e1, RS_Entity* e2) {
81         if (e1!=NULL && e2!=NULL) {
82                 if (e1->getParent()!=NULL && e2->getParent()!=NULL) {
83                         if (e1->getParent()->rtti()==RS2::EntityPolyline &&
84                            e2->getParent()->rtti()==RS2::EntityPolyline &&
85                            e1->getParent()==e2->getParent()) {
86
87                                 // in the same polyline
88                                 RS_EntityContainer* pl = e1->getParent();
89                                 int idx1 = pl->findEntity(e1);
90                                 int idx2 = pl->findEntity(e2);
91                                 RS_DEBUG->print("RS_Information::isTrimmable: "
92                                         "idx1: %d, idx2: %d", idx1, idx2);
93                                 if (abs(idx1-idx2)==1 || abs(idx1-idx2)==pl->count()-1) {
94                                         // directly following entities
95                                         return true;
96                                 }
97                                 else {
98                                         // not directly following entities
99                                         return false;
100                                 }
101                         }
102                         else if ((e1->getParent()->rtti()==RS2::EntityContainer ||
103                                   e1->getParent()->rtti()==RS2::EntityGraphic ||
104                                           e1->getParent()->rtti()==RS2::EntityBlock) &&
105                                          (e2->getParent()->rtti()==RS2::EntityContainer ||
106                                   e2->getParent()->rtti()==RS2::EntityGraphic ||
107                                           e2->getParent()->rtti()==RS2::EntityBlock)) {
108
109                                 // normal entities:
110                                 return true;
111                         }
112                 }
113                 else {
114                         // independent entities with the same parent:
115                         return (e1->getParent()==e2->getParent());
116                 }
117         }
118
119         return false;
120 }
121
122
123 /**
124  * Gets the nearest end point to the given coordinate.
125  *
126  * @param coord Coordinate (typically a mouse coordinate)
127  *
128  * @return the coordinate found or an invalid vector
129  * if there are no elements at all in this graphics
130  * container.
131  */
132 Vector RS_Information::getNearestEndpoint(const Vector& coord,
133         double* dist) const {
134     return container->getNearestEndpoint(coord, dist);
135 }
136
137
138 /**
139  * Gets the nearest point to the given coordinate which is on an entity.
140  *
141  * @param coord Coordinate (typically a mouse coordinate)
142  * @param dist Pointer to a double which will contain the
143  *        measured distance after return or NULL
144  * @param entity Pointer to a pointer which will point to the
145  *        entity on which the point is or NULL
146  *
147  * @return the coordinate found or an invalid vector
148  * if there are no elements at all in this graphics
149  * container.
150  */
151 Vector RS_Information::getNearestPointOnEntity(const Vector& coord,
152         bool onEntity,
153         double* dist,
154         RS_Entity** entity) const {
155
156     return container->getNearestPointOnEntity(coord, onEntity, dist, entity);
157 }
158
159
160 /**
161  * Gets the nearest entity to the given coordinate.
162  *
163  * @param coord Coordinate (typically a mouse coordinate)
164  * @param dist Pointer to a double which will contain the
165  *             masured distance after return
166  * @param level Level of resolving entities.
167  *
168  * @return the entity found or NULL if there are no elements
169  * at all in this graphics container.
170  */
171 RS_Entity* RS_Information::getNearestEntity(const Vector& coord,
172         double* dist,
173         RS2::ResolveLevel level) const {
174
175     return container->getNearestEntity(coord, dist, level);
176 }
177
178
179
180 /**
181  * Calculates the intersection point(s) between two entities.
182  *
183  * @param onEntities true: only return intersection points which are
184  *                   on both entities.
185  *                   false: return all intersection points.
186  *
187  * @todo support more entities
188  *
189  * @return All intersections of the two entities. The tangent flag in
190  * VectorSolutions is set if one intersection is a tangent point.
191  */
192 VectorSolutions RS_Information::getIntersection(RS_Entity* e1,
193         RS_Entity* e2, bool onEntities) {
194
195     VectorSolutions ret;
196         double tol = 1.0e-4;
197
198     if (e1==NULL || e2==NULL) {
199         return ret;
200     }
201
202     // unsupported entities / entity combinations:
203     if ((e1->rtti()==RS2::EntityEllipse && e2->rtti()==RS2::EntityEllipse) ||
204             e1->rtti()==RS2::EntityText || e2->rtti()==RS2::EntityText ||
205             isDimension(e1->rtti()) || isDimension(e2->rtti())) {
206
207         return ret;
208     }
209
210     // (only) one entity is an ellipse:
211     if (e1->rtti()==RS2::EntityEllipse || e2->rtti()==RS2::EntityEllipse) {
212         if (e2->rtti()==RS2::EntityEllipse) {
213             RS_Entity* tmp = e1;
214             e1 = e2;
215             e2 = tmp;
216         }
217         if (e2->rtti()==RS2::EntityLine) {
218             RS_Ellipse* ellipse = (RS_Ellipse*)e1;
219             ret = getIntersectionLineEllipse((RS_Line*)e2, ellipse);
220                         tol = 1.0e-1;
221         }
222
223                 // ellipse / arc, ellipse / ellipse: not supported:
224                 else {
225             return ret;
226         }
227     } else {
228
229         RS_Entity* te1 = e1;
230         RS_Entity* te2 = e2;
231
232         // entity copies - so we only have to deal with lines and arcs
233         RS_Line l1(NULL,
234                    RS_LineData(Vector(0.0, 0.0), Vector(0.0,0.0)));
235         RS_Line l2(NULL,
236                    RS_LineData(Vector(0.0, 0.0), Vector(0.0,0.0)));
237
238         RS_Arc a1(NULL,
239                   RS_ArcData(Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false));
240         RS_Arc a2(NULL,
241                   RS_ArcData(Vector(0.0,0.0), 1.0, 0.0, 2*M_PI, false));
242
243         // convert construction lines to lines:
244         if (e1->rtti()==RS2::EntityConstructionLine) {
245             RS_ConstructionLine* cl = (RS_ConstructionLine*)e1;
246
247             l1.setStartpoint(cl->getPoint1());
248             l1.setEndpoint(cl->getPoint2());
249
250             te1 = &l1;
251         }
252         if (e2->rtti()==RS2::EntityConstructionLine) {
253             RS_ConstructionLine* cl = (RS_ConstructionLine*)e2;
254
255             l2.setStartpoint(cl->getPoint1());
256             l2.setEndpoint(cl->getPoint2());
257
258             te2 = &l2;
259         }
260
261
262         // convert circles to arcs:
263         if (e1->rtti()==RS2::EntityCircle) {
264             RS_Circle* c = (RS_Circle*)e1;
265
266             RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false);
267             a1.setData(data);
268
269             te1 = &a1;
270         }
271         if (e2->rtti()==RS2::EntityCircle) {
272             RS_Circle* c = (RS_Circle*)e2;
273
274             RS_ArcData data(c->getCenter(), c->getRadius(), 0.0, 2*M_PI, false);
275             a2.setData(data);
276
277             te2 = &a2;
278         }
279
280
281         // line / line:
282         //
283         //else
284         if (te1->rtti()==RS2::EntityLine &&
285                 te2->rtti()==RS2::EntityLine) {
286
287             RS_Line* line1 = (RS_Line*)te1;
288             RS_Line* line2 = (RS_Line*)te2;
289
290             ret = getIntersectionLineLine(line1, line2);
291         }
292
293         // line / arc:
294         //
295         else if (te1->rtti()==RS2::EntityLine &&
296                  te2->rtti()==RS2::EntityArc) {
297
298             RS_Line* line = (RS_Line*)te1;
299             RS_Arc* arc = (RS_Arc*)te2;
300
301             ret = getIntersectionLineArc(line, arc);
302         }
303
304         // arc / line:
305         //
306         else if (te1->rtti()==RS2::EntityArc &&
307                  te2->rtti()==RS2::EntityLine) {
308
309             RS_Arc* arc = (RS_Arc*)te1;
310             RS_Line* line = (RS_Line*)te2;
311
312             ret = getIntersectionLineArc(line, arc);
313         }
314
315         // arc / arc:
316         //
317         else if (te1->rtti()==RS2::EntityArc &&
318                  te2->rtti()==RS2::EntityArc) {
319
320             RS_Arc* arc1 = (RS_Arc*)te1;
321             RS_Arc* arc2 = (RS_Arc*)te2;
322
323             ret = getIntersectionArcArc(arc1, arc2);
324         } else {
325             RS_DEBUG->print("RS_Information::getIntersection:: Unsupported entity type.");
326         }
327     }
328
329
330     // Check all intersection points for being on entities:
331     //
332     if (onEntities==true) {
333         if (!e1->isPointOnEntity(ret.get(0), tol) ||
334                 !e2->isPointOnEntity(ret.get(0), tol)) {
335             ret.set(0, Vector(false));
336         }
337         if (!e1->isPointOnEntity(ret.get(1), tol) ||
338                 !e2->isPointOnEntity(ret.get(1), tol)) {
339             ret.set(1, Vector(false));
340         }
341         if (!e1->isPointOnEntity(ret.get(2), tol) ||
342                 !e2->isPointOnEntity(ret.get(2), tol)) {
343             ret.set(2, Vector(false));
344         }
345         if (!e1->isPointOnEntity(ret.get(3), tol) ||
346                 !e2->isPointOnEntity(ret.get(3), tol)) {
347             ret.set(3, Vector(false));
348         }
349     }
350
351     int k=0;
352     for (int i=0; i<4; ++i) {
353         if (ret.get(i).valid) {
354             ret.set(k, ret.get(i));
355             k++;
356         }
357     }
358     for (int i=k; i<4; ++i) {
359         ret.set(i, Vector(false));
360     }
361
362     return ret;
363 }
364
365
366
367 /**
368  * @return Intersection between two lines.
369  */
370 VectorSolutions RS_Information::getIntersectionLineLine(RS_Line* e1,
371         RS_Line* e2) {
372
373     VectorSolutions ret;
374
375     if (e1==NULL || e2==NULL) {
376         return ret;
377     }
378
379     Vector p1 = e1->getStartpoint();
380     Vector p2 = e1->getEndpoint();
381     Vector p3 = e2->getStartpoint();
382     Vector p4 = e2->getEndpoint();
383
384     double num = ((p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x));
385     double div = ((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
386
387     if (fabs(div)>RS_TOLERANCE) {
388         double u = num / div;
389
390         double xs = p1.x + u * (p2.x-p1.x);
391         double ys = p1.y + u * (p2.y-p1.y);
392         ret = VectorSolutions(Vector(xs, ys));
393     }
394
395     // lines are parallel
396     else {
397         ret = VectorSolutions();
398     }
399
400     return ret;
401 }
402
403
404
405 /**
406  * @return One or two intersection points between given entities.
407  */
408 VectorSolutions RS_Information::getIntersectionLineArc(RS_Line* line,
409         RS_Arc* arc) {
410
411     VectorSolutions ret;
412
413     if (line==NULL || arc==NULL) {
414         return ret;
415     }
416
417     double dist=0.0;
418     Vector nearest;
419     nearest = line->getNearestPointOnEntity(arc->getCenter(), false, &dist);
420
421     // special case: arc touches line (tangent):
422     if (fabs(dist - arc->getRadius()) < 1.0e-4) {
423         ret = VectorSolutions(nearest);
424         ret.setTangent(true);
425         return ret;
426     }
427
428     Vector p = line->getStartpoint();
429     Vector d = line->getEndpoint() - line->getStartpoint();
430     if (d.magnitude()<1.0e-6) {
431         return ret;
432     }
433
434     Vector c = arc->getCenter();
435     double r = arc->getRadius();
436     Vector delta = p - c;
437
438     // root term:
439     double term = RS_Math::pow(Vector::dotP(d, delta), 2.0)
440                   - RS_Math::pow(d.magnitude(), 2.0)
441                   * (RS_Math::pow(delta.magnitude(), 2.0) - RS_Math::pow(r, 2.0));
442
443     // no intersection:
444     if (term<0.0) {
445         VectorSolutions s;
446         ret = s;
447     }
448
449     // one or two intersections:
450     else {
451         double t1 = (- Vector::dotP(d, delta) + sqrt(term))
452                     / RS_Math::pow(d.magnitude(), 2.0);
453         double t2;
454         bool tangent = false;
455
456         // only one intersection:
457         if (fabs(term)<RS_TOLERANCE) {
458             t2 = t1;
459             tangent = true;
460         }
461
462         // two intersections
463         else {
464             t2 = (-Vector::dotP(d, delta) - sqrt(term))
465                  / RS_Math::pow(d.magnitude(), 2.0);
466         }
467
468         Vector sol1;
469         Vector sol2(false);
470
471         sol1 = p + d * t1;
472
473         if (!tangent) {
474             sol2 = p + d * t2;
475         }
476
477         ret = VectorSolutions(sol1, sol2);
478         ret.setTangent(tangent);
479     }
480
481     return ret;
482 }
483
484
485
486 /**
487  * @return One or two intersection points between given entities.
488  */
489 VectorSolutions RS_Information::getIntersectionArcArc(RS_Arc* e1,
490         RS_Arc* e2) {
491
492     VectorSolutions ret;
493
494     if (e1==NULL || e2==NULL) {
495         return ret;
496     }
497
498     Vector c1 = e1->getCenter();
499     Vector c2 = e2->getCenter();
500
501     double r1 = e1->getRadius();
502     double r2 = e2->getRadius();
503
504     Vector u = c2 - c1;
505
506     // concentric
507     if (u.magnitude()<1.0e-6) {
508         return ret;
509     }
510
511     Vector v = Vector(u.y, -u.x);
512
513     double s, t1, t2, term;
514
515     s = 1.0/2.0 * ((r1*r1 - r2*r2)/(RS_Math::pow(u.magnitude(), 2.0)) + 1.0);
516
517     term = (r1*r1)/(RS_Math::pow(u.magnitude(), 2.0)) - s*s;
518
519     // no intersection:
520     if (term<0.0) {
521         ret = VectorSolutions();
522     }
523
524     // one or two intersections:
525     else {
526         t1 = sqrt(term);
527         t2 = -sqrt(term);
528         bool tangent = false;
529
530         Vector sol1 = c1 + u*s + v*t1;
531         Vector sol2 = c1 + u*s + v*t2;
532
533         if (sol1.distanceTo(sol2)<1.0e-4) {
534             sol2 = Vector(false);
535             ret = VectorSolutions(sol1);
536             tangent = true;
537         } else {
538             ret = VectorSolutions(sol1, sol2);
539         }
540
541         ret.setTangent(tangent);
542     }
543
544     return ret;
545 }
546
547
548
549 /**
550  * @return One or two intersection points between given entities.
551  */
552 VectorSolutions RS_Information::getIntersectionLineEllipse(RS_Line* line,
553         RS_Ellipse* ellipse) {
554
555     VectorSolutions ret;
556
557     if (line==NULL || ellipse==NULL) {
558         return ret;
559     }
560
561     // rotate into normal position:
562     double ang = ellipse->getAngle();
563
564     double rx = ellipse->getMajorRadius();
565     double ry = ellipse->getMinorRadius();
566     Vector center = ellipse->getCenter();
567     Vector a1 = line->getStartpoint().rotate(center, -ang);
568     Vector a2 = line->getEndpoint().rotate(center, -ang);
569     Vector origin = a1;
570     Vector dir = a2-a1;
571     Vector diff = origin - center;
572     Vector mDir = Vector(dir.x/(rx*rx), dir.y/(ry*ry));
573     Vector mDiff = Vector(diff.x/(rx*rx), diff.y/(ry*ry));
574
575     double a = Vector::dotP(dir, mDir);
576     double b = Vector::dotP(dir, mDiff);
577     double c = Vector::dotP(diff, mDiff) - 1.0;
578     double d = b*b - a*c;
579
580     if (d < 0) {
581         RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 0");
582     } else if ( d > 0 ) {
583         double root = sqrt(d);
584         double t_a = (-b - root) / a;
585         double t_b = (-b + root) / a;
586
587         /*if ( (t_a < 0 || 1 < t_a) && (t_b < 0 || 1 < t_b) ) {
588             if ( (t_a < 0 && t_b < 0) || (t_a > 1 && t_b > 1) ) {
589                 RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 1");
590             }
591             else {
592                 RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: inside 1");
593             }
594         } else {*/
595             RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: intersection 1");
596             Vector ret1(false);
597             Vector ret2(false);
598             //if ( 0 <= t_a && t_a <= 1 ) {
599                 //RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t_a<=1");
600                 ret1 = a1.lerp(a2, t_a);
601                 RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret1: %f/%f", ret1.x, ret1.y);
602             //}
603             //if ( 0 <= t_b && t_b <= 1 ) {
604                 //RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t_b<=1");
605                 ret2 = a1.lerp(a2, t_b);
606                 RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret2: %f/%f", ret2.x, ret2.y);
607             //}
608             if (ret1.valid && ret2.valid) {
609                 ret = VectorSolutions(ret1, ret2);
610             }
611             else {
612                 if (ret1.valid) {
613                     ret = VectorSolutions(ret1);
614                 }
615                 if (ret2.valid) {
616                     ret = VectorSolutions(ret2);
617                 }
618             }
619         //}
620     } else {
621         double t = -b/a;
622         if ( 0 <= t && t <= 1 ) {
623             RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: 0<=t<=1");
624             RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: intersection 2");
625             ret = VectorSolutions(a1.lerp(a2, t));
626             RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: ret1: %f/%f", ret.get(0).x, ret.get(0).y);
627         } else {
628             RS_DEBUG->print("RS_Information::getIntersectionLineEllipse: outside 2");
629         }
630     }
631
632     ret.rotate(center, ang);
633     return ret;
634
635
636
637     /*
638     RS_Arc* arc = new RS_Arc(NULL,
639                              RS_ArcData(ellipse->getCenter(),
640                                         ellipse->getMajorRadius(),
641                                         ellipse->getAngle1(),
642                                         ellipse->getAngle2(),
643                                         false));
644     RS_Line* other = (RS_Line*)line->clone();
645     double angle = ellipse->getAngle();
646     //double ratio = ellipse->getRatio();
647
648     // rotate entities:
649     other->rotate(ellipse->getCenter(), -angle);
650     other->scale(ellipse->getCenter(), Vector(1.0, 1.0/ellipse->getRatio()));
651
652     ret = getIntersectionLineArc(other, arc);
653
654     ret.scale(ellipse->getCenter(), Vector(1.0, ellipse->getRatio()));
655     ret.rotate(ellipse->getCenter(), angle);
656
657     delete arc;
658     delete other;
659
660     return ret;
661     */
662 }
663
664
665 /**
666  * Checks if the given coordinate is inside the given contour.
667  *
668  * @param point Coordinate to check.
669  * @param contour One or more entities which shape a contour.
670  *         If the given contour is not closed, the result is undefined.
671  *         The entities don't need to be in a specific order.
672  * @param onContour Will be set to true if the given point it exactly
673  *         on the contour.
674  */
675 bool RS_Information::isPointInsideContour(const Vector& point,
676         RS_EntityContainer* contour, bool* onContour) {
677
678     if (contour==NULL) {
679         RS_DEBUG->print(RS_Debug::D_WARNING,
680                         "RS_Information::isPointInsideContour: contour is NULL");
681         return false;
682     }
683
684     if (point.x < contour->getMin().x || point.x > contour->getMax().x ||
685             point.y < contour->getMin().y || point.y > contour->getMax().y) {
686         return false;
687     }
688
689     double width = contour->getSize().x+1.0;
690
691     bool sure;
692     int counter;
693     int tries = 0;
694     double rayAngle = 0.0;
695     do {
696         sure = true;
697
698         // create ray:
699         Vector v;
700         v.setPolar(width*10.0, rayAngle);
701         RS_Line ray(NULL, RS_LineData(point, point+v));
702         counter = 0;
703         VectorSolutions sol;
704
705         if (onContour!=NULL) {
706             *onContour = false;
707         }
708
709         for (RS_Entity* e = contour->firstEntity(RS2::ResolveAll);
710                 e!=NULL;
711                 e = contour->nextEntity(RS2::ResolveAll)) {
712
713             // intersection(s) from ray with contour entity:
714             sol = RS_Information::getIntersection(&ray, e, true);
715
716             for (int i=0; i<=1; ++i) {
717                 Vector p = sol.get(i);
718
719                 if (p.valid) {
720                     // point is on the contour itself
721                     if (p.distanceTo(point)<1.0e-5) {
722                         if (onContour!=NULL) {
723                             *onContour = true;
724                         }
725                     } else {
726                         if (e->rtti()==RS2::EntityLine) {
727                             RS_Line* line = (RS_Line*)e;
728
729                             // ray goes through startpoint of line:
730                             if (p.distanceTo(line->getStartpoint())<1.0e-4) {
731                                 if (RS_Math::correctAngle(line->getAngle1())<M_PI) {
732                                     counter++;
733                                     sure = false;
734                                 }
735                             }
736
737                             // ray goes through endpoint of line:
738                             else if (p.distanceTo(line->getEndpoint())<1.0e-4) {
739                                 if (RS_Math::correctAngle(line->getAngle2())<M_PI) {
740                                     counter++;
741                                     sure = false;
742                                 }
743                             }
744                             // ray goes through the line:
745
746
747                             else {
748                                 counter++;
749                             }
750                         } else if (e->rtti()==RS2::EntityArc) {
751                             RS_Arc* arc = (RS_Arc*)e;
752
753                             if (p.distanceTo(arc->getStartpoint())<1.0e-4) {
754                                 double dir = arc->getDirection1();
755                                 if ((dir<M_PI && dir>=1.0e-5) ||
756                                         ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) &&
757                                          arc->getCenter().y>p.y)) {
758                                     counter++;
759                                     sure = false;
760                                 }
761                             }
762                             else if (p.distanceTo(arc->getEndpoint())<1.0e-4) {
763                                 double dir = arc->getDirection2();
764                                 if ((dir<M_PI && dir>=1.0e-5) ||
765                                         ((dir>2*M_PI-1.0e-5 || dir<1.0e-5) &&
766                                          arc->getCenter().y>p.y)) {
767                                     counter++;
768                                     sure = false;
769                                 }
770                             } else {
771                                 counter++;
772                             }
773                         } else if (e->rtti()==RS2::EntityCircle) {
774                             // tangent:
775                             if (i==0 && sol.get(1).valid==false) {
776                                 if (!sol.isTangent()) {
777                                     counter++;
778                                 } else {
779                                     sure = false;
780                                 }
781                             } else if (i==1 || sol.get(1).valid==true) {
782                                 counter++;
783                             }
784                         }
785                     }
786                 }
787             }
788         }
789
790         rayAngle+=0.02;
791         tries++;
792     }
793     while (!sure && rayAngle<2*M_PI && tries<6);
794
795     // remove double intersections:
796     /*
797        Q3PtrList<Vector> is2;
798        bool done;
799     Vector* av;
800        do {
801            done = true;
802            double minDist = RS_MAXDOUBLE;
803            double dist;
804         av = NULL;
805            for (Vector* v = is.first(); v!=NULL; v = is.next()) {
806                dist = point.distanceTo(*v);
807                if (dist<minDist) {
808                    minDist = dist;
809                    done = false;
810                         av = v;
811                }
812            }
813
814         if (!done && av!=NULL) {
815                 is2.append(*av);
816         }
817        } while (!done);
818     */
819
820     return ((counter%2)==1);
821 }
822