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