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