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