]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/canvas/liner.cpp
more region tests
[wxWidgets.git] / contrib / src / canvas / liner.cpp
CommitLineData
84fba40b
RR
1/*
2Program wxLine.CPP
3Purpose Mainly used for calculating crossings
4Last Update 05-12-1995
5*/
6
7#ifdef __GNUG__
8#pragma implementation "liner.cpp"
9#endif
10
11#include <math.h>
12
13#include <stdlib.h>
14
f9032263 15#include "wx/canvas/liner.h"
84fba40b
RR
16
17wxLine::wxLine( double x1, double y1, double x2, double y2 )
18{
19 m_AA = 0.0;
20 m_BB = 0.0;
21 m_CC = 0.0;
22
23 m_a=wxPoint2DDouble(x1,y1);
24 m_b=wxPoint2DDouble(x2,y2);
25 if (m_a==m_b)
26 assert(0);
27
28 m_valid_parameters = FALSE;
29}
30
31wxLine::~wxLine()
32{
33}
34
35wxLine::wxLine(const wxPoint2DDouble& a,const wxPoint2DDouble& b)
36{
37 if (a==b)
38 assert(0);
39
40 m_a=a;
41 m_b=b;
42 m_valid_parameters = FALSE;
43}
44
45
46
47// ActionOnTable1
48// This function decide which action must be taken, after PointInLine
49// has given the results of two points in relation to a wxLine. See table 1 in the report
50//
51// input Result_beginPoint:
52// Result_endPoint :
53// The results can be R_R_LEFT_SIDE, R_R_RIGHT_SIDE, R_R_ON_AREA, R_R_IN_AREA
54//
55// return -1: Illegal combination
56// 0: No action, no crosspoints
57// 1: Investigate results points in relation to the other wxLine
58// 2: endPoint is a crosspoint, no further investigation
59// 3: beginPoint is a crosspoint, no further investigation
60// 4: beginPoint and endPoint are crosspoints, no further investigation
61// 5: beginPoint is a crosspoint, need further investigation
62// 6: endPoint is a crosspoint, need further investigation
63int wxLine::ActionOnTable1(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
64{
65 // beginPoint and endPoint are crosspoints
66 if (
67 (Result_beginPoint == R_IN_AREA)
68 &&
69 (Result_endPoint == R_IN_AREA)
70 )
71 return 4;
72 // there are no crosspoints, no action
73 if (
74 (
75 (Result_beginPoint == R_LEFT_SIDE)
76 &&
77 (Result_endPoint == R_LEFT_SIDE)
78 )
79 ||
80 (
81 (Result_beginPoint == R_RIGHT_SIDE)
82 &&
83 (Result_endPoint == R_RIGHT_SIDE)
84 )
85 )
86 return 0;
87 // maybe there is a crosspoint, further investigation needed
88 if (
89 (
90 (Result_beginPoint == R_LEFT_SIDE)
91 &&
92 (
93 (Result_endPoint == R_RIGHT_SIDE)
94 ||
95 (Result_endPoint == R_ON_AREA)
96 )
97 )
98 ||
99 (
100 (Result_beginPoint == R_RIGHT_SIDE)
101 &&
102 (
103 (Result_endPoint == R_LEFT_SIDE)
104 ||
105 (Result_endPoint == R_ON_AREA)
106 )
107 )
108 ||
109 (
110 (Result_beginPoint == R_ON_AREA)
111 &&
112 (
113 (Result_endPoint == R_LEFT_SIDE)
114 ||
115 (Result_endPoint == R_RIGHT_SIDE)
116 ||
117 (Result_endPoint == R_ON_AREA)
118 )
119 )
120 )
121 return 1;
122 //there is a crosspoint
123 if (
124 (
125 (Result_beginPoint == R_LEFT_SIDE)
126 ||
127 (Result_beginPoint == R_RIGHT_SIDE)
128 )
129 &&
130 (Result_endPoint == R_IN_AREA)
131 )
132 return 2;
133 // there is a crosspoint
134 if (
135 (Result_beginPoint == R_IN_AREA)
136 &&
137 (
138 (Result_endPoint == R_LEFT_SIDE)
139 ||
140 (Result_endPoint == R_RIGHT_SIDE)
141 )
142 )
143 return 3;
144 // beginPoint is a crosspoint, further investigation needed
145 if (
146 (Result_beginPoint == R_IN_AREA)
147 &&
148 (Result_endPoint == R_ON_AREA)
149 )
150 return 5;
151 // endPoint is a crosspoint, further investigation needed
152 if (
153 (Result_beginPoint == R_ON_AREA)
154 &&
155 (Result_endPoint == R_IN_AREA)
156 )
157 return 6;
158 // All other combinations are illegal
159 return -1;
160}
161
162
163// ActionOnTable2
164// This function decide which action must be taken, after PointInLine
165// has given the results of two points in relation to a wxLine. It can only give a
166// correct decision if first the relation of the points from the wxLine
167// are investigated in relation to the wxLine wich can be constucted from the points.
168//
169// input Result_beginPoint:
170// Result_endPoint :
171// The results can be R_LEFT_SIDE, R_RIGHT_SIDE, R_ON_AREA, R_IN_AREA
172//
173// return -1: Illegal combination
174// 0: No action, no crosspoints
175// 1: Calculate crosspoint
176// 2: endPoint is a crosspoint
177// 3: beginPoint is a crosspoint
178// 4: beginPoint and endPoint are crosspoints
179int wxLine::ActionOnTable2(R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint)
180{
181 // beginPoint and eindpoint are crosspoints
182 if (
183 (Result_beginPoint == R_IN_AREA)
184 &&
185 (Result_endPoint == R_IN_AREA)
186 )
187 return 4;
188 // there are no crosspoints
189 if (
190 (
191 (Result_beginPoint == R_LEFT_SIDE)
192 &&
193 (
194 (Result_endPoint == R_LEFT_SIDE)
195 ||
196 (Result_endPoint == R_ON_AREA)
197 )
198 )
199 ||
200 (
201 (Result_beginPoint == R_RIGHT_SIDE)
202 &&
203 (
204 (Result_endPoint == R_RIGHT_SIDE)
205 ||
206 (Result_endPoint == R_ON_AREA)
207 )
208 )
209 ||
210 (
211 (Result_beginPoint == R_ON_AREA)
212 &&
213 (
214 (Result_endPoint == R_LEFT_SIDE)
215 ||
216 (Result_endPoint == R_RIGHT_SIDE)
217 ||
218 (Result_endPoint == R_ON_AREA)
219 )
220 )
221 )
222 return 0;
223 // there is a real intersection, which must be calculated
224 if (
225 (
226 (Result_beginPoint == R_LEFT_SIDE)
227 &&
228 (Result_endPoint == R_RIGHT_SIDE)
229 )
230 ||
231 (
232 (Result_beginPoint == R_RIGHT_SIDE)
233 &&
234 (Result_endPoint == R_LEFT_SIDE)
235 )
236 )
237 return 1;
238 // endPoint is a crosspoint
239 if (
240 (
241 (Result_beginPoint == R_LEFT_SIDE)
242 ||
243 (Result_beginPoint == R_RIGHT_SIDE)
244 ||
245 (Result_beginPoint == R_ON_AREA)
246 )
247 &&
248 (Result_endPoint == R_IN_AREA)
249 )
250 return 2;
251 // beginPoint is a crosspoint
252 if (
253 (Result_beginPoint == R_IN_AREA)
254 &&
255 (
256 (Result_endPoint == R_LEFT_SIDE)
257 ||
258 (Result_endPoint == R_RIGHT_SIDE)
259 ||
260 (Result_endPoint == R_ON_AREA)
261 )
262 )
263 return 3;
264 // All other combinations are illegal
265 return -1;
266}
267
268// Calculate the Y when the X is given
269double wxLine::Calculate_Y(double X)
270{
271 CalculateLineParameters();
272 if (m_AA != 0)
273 return -(m_AA * X + m_CC) / m_BB;
274 else
275 // horizontal wxLine
276 return m_a.m_y;
277}
278
279void wxLine::Virtual_Point(wxPoint2DDouble& a_point,double distance) const
280{
281 assert(m_valid_parameters);
282
283 //calculate the distance using the slope of the wxLine
284 //and rotate 90 degrees
285
286 a_point.m_y=a_point.m_y + (distance * -m_BB);
287 a_point.m_x=a_point.m_x - (distance * m_AA );
288}
289
290
291
292//
293// Calculate the lineparameters for the wxLine if nessecary
294//
295void wxLine::CalculateLineParameters()
296{
297 // if not valid_parameters calculate the parameters
298 if (!m_valid_parameters)
299 {
300 double length;
301
302 // bp AND ep may not be the same
303 if (m_a == m_b)
304 assert (0);
305
306 m_AA = (m_b.m_y - m_a.m_y); // A = (Y2-Y1)
307 m_BB = (m_a.m_x - m_b.m_x); // B = (X1-X2)
308
309 // the parameters A end B can now be normalized
310 length = sqrt(m_AA*m_AA + m_BB*m_BB);
311
312 assert(length !=0);
313
314 m_AA = (m_AA / length);
315 m_BB = (m_BB / length);
316
317 m_CC = -((m_AA * m_a.m_x) + (m_a.m_y * m_BB));
318
319 m_valid_parameters = TRUE;
320 }
321}
322
323
324// Checks if a wxLine intersect with another wxLine
325// inout wxLine : another wxLine
326// Marge: optional, standard on MARGE (declared in MISC.CPP)
327//
328// return true : wxLines are crossing
329// false: wxLines are not crossing
330//
331bool wxLine::CheckIntersect (wxLine& lijn, double Marge)
332{
333 double distance=0;
334
335 // bp AND ep may not be the same
336 if (m_a == m_b)
337 assert (0);
338
339 int Take_Action1, Take_Action2;
340 bool Total_Result=FALSE;
341 R_PointStatus Result_beginPoint,Result_endPoint;
342
343 Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
344 Result_endPoint = PointInLine(lijn.m_b,distance,Marge);
345 Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
346 switch (Take_Action1)
347 {
348 case 0: Total_Result = FALSE ; break;
349 case 1: {
350 Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
351 Result_endPoint = lijn.PointInLine(m_b,distance,Marge);
352 Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
353 switch (Take_Action2)
354 {
355 case 0: Total_Result = FALSE; break;
356 case 1: case 2: case 3: case 4: Total_Result = TRUE; break;
357 }
358 }; break; // This break belongs to the switch(Take_Action1)
359 case 2: case 3: case 4: case 5: case 6: Total_Result = TRUE; break;
360 }
361 return Total_Result; //This is the final decision
362}
363
364
365//
366// Get the beginPoint from the wxLine
367// usage: Point aPoint = a_line.GetBeginPoint()
368//
369wxPoint2DDouble wxLine::GetBeginPoint()
370{
371 return m_a;
372}
373
374
375//
376// Get the endPoint from the wxLine
377// usage: Point aPoint = a_line.GetEndPoint()
378//
379wxPoint2DDouble wxLine::GetEndPoint()
380{
381 return m_b;
382}
383
384// Intersects two wxLines
385// input wxLine : another wxLine
386// Marge: optional, standard on MARGE
387//
388// return 0: If there are no crossings
389// 1: If there is one crossing
390// 2: If there are two crossings
391int wxLine::Intersect(wxLine& lijn, wxPoint2DDouble& c1 ,wxPoint2DDouble& c2 , double Marge)
392{
393 double distance=0;
394
395 // bp AND ep may not be the same
396 if (m_a == m_b)
397 assert (0);
398
399 R_PointStatus Result_beginPoint,Result_endPoint;
400 int Take_Action1, Take_Action2, Number_of_Crossings = 0;
401
402 Result_beginPoint = PointInLine(lijn.m_a,distance,Marge);
403 Result_endPoint = PointInLine(lijn.m_b,distance,Marge);
404
405 Take_Action1 = ActionOnTable1(Result_beginPoint,Result_endPoint);
406// 0: No action, no crosspoints
407// 1: Investigate results points in relation to the other wxLine
408// 2: endPoint is a crosspoint, no further investigation
409// 3: beginPoint is a crosspoint, no further investigation
410// 4: beginPoint and endPoint are crosspoints, no further investigation
411// 5: beginPoint is a crosspoint, need further investigation
412// 6: endPoint is a crosspoint, need further investigation
413
414 // The first switch will insert a crosspoint immediatly
415 switch (Take_Action1)
416 {
417 case 2: case 6: c1=lijn.m_b;
418 Number_of_Crossings = 1;
419 break;
420 case 3: case 5: c1=lijn.m_a;
421 Number_of_Crossings = 1;
422 break;
423 case 4: c1=lijn.m_a;
424 c2=lijn.m_b;
425 Number_of_Crossings = 2;
426 break;
427 default:
428 break;
429 }
430
431 // This switch wil investigate the points of this wxLine in relation to lijn
432 // 1: Investigate results points in relation to the other wxLine
433 // 5: beginPoint is a crosspoint, need further investigation
434 // 6: endPoint is a crosspoint, need further investigation
435 switch (Take_Action1)
436 {
437 case 1: case 5: case 6:
438 {
439 Result_beginPoint = lijn.PointInLine(m_a,distance,Marge);
440 Result_endPoint = lijn.PointInLine(m_b,distance,Marge);
441 Take_Action2 = ActionOnTable2(Result_beginPoint,Result_endPoint);
442 // return -1: Illegal combination
443 // 0: No action, no crosspoints
444 // 1: Calculate crosspoint
445 // 2: endPoint is a crosspoint
446 // 3: beginPoint is a crosspoint
447 // 4: beginPoint and endPoint are crosspoints
448 switch (Take_Action2)
449 {
450 // for the cases see the returnvalue of ActionTable2
451 case 1: { // begin of scope to calculate the intersection
452 double X, Y, Denominator;
453 CalculateLineParameters();
454 Denominator = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
455 // Denominator may not be 0
456 assert(Denominator != 0.0);
457 // Calculate intersection of both linesegments
458 X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
459 Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;
460
461 c1.m_x=X;
462 c1.m_y=Y;
463 }
464 Number_of_Crossings++;
465 break;
466 case 2: c2=m_a;
467 Number_of_Crossings++;
468 break;
469 case 3: c2=m_b;
470 Number_of_Crossings++;
471 break;
472 case 4: c1=m_a;
473 c2=m_b;
474 Number_of_Crossings = 2;
475 break;
476 }
477 };
478 break;
479 default:
480 break;
481 }
482 return Number_of_Crossings; //This is de final number of crossings
483}
484
485//
486// test if a point lies in the linesegment. If the point isn't on the wxLine
487// the function returns a value that indicates on which side of the
488// wxLine the point is (in linedirection from first point to second point
489//
490// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
491// R_RIGHT_SIDE, when point lies on the right side of the wxLine
492// R_ON_AREA, when point lies on the infinite wxLine within a range
493// R_IN_AREA, when point lies in the area of the linesegment
494// the returnvalues are declared in (wxLine.H)
495R_PointStatus wxLine::PointInLine(const wxPoint2DDouble& a_Point, double& Distance,double Marge)
496{
497 Distance=0;
498
499 // Point may not be the same
500 assert(m_a != m_b);
501
502 int Result_ofm_BBox=FALSE;
503 R_PointStatus Result_of_Online;
504
505 //quick test if point is begin or endpoint
506 if (a_Point == m_a || a_Point == m_b)
507 return R_IN_AREA;
508
509 // Checking if point is in bounding-box with marge
510 double xmin=wxMin(m_a.m_x,m_b.m_x);
511 double xmax=wxMax(m_a.m_x,m_b.m_x);
512 double ymin=wxMin(m_a.m_y,m_b.m_y);
513 double ymax=wxMax(m_a.m_y,m_b.m_y);
514
515 if ( a_Point.m_x >= (xmin - Marge) && a_Point.m_x <= (xmax + Marge) &&
516 a_Point.m_y >= (ymin - Marge) && a_Point.m_y <= (ymax + Marge) )
517 Result_ofm_BBox=TRUE;
518
519 // Checking if point is on the infinite wxLine
520 Result_of_Online = PointOnLine(a_Point, Distance, Marge);
521
522 // point in boundingbox of the wxLine and is on the wxLine then the point is R_IN_AREA
523 if ((Result_ofm_BBox) && (Result_of_Online == R_ON_AREA))
524 return R_IN_AREA;
525 else
526 return Result_of_Online;
527}
528
529
530//
531// test if a point lies on the wxLine. If the point isn't on the wxLine
532// the function returns a value that indicates on which side of the
533// wxLine the point is (in linedirection from first point to second point
534//
535// returns R_LEFT_SIDE, when point lies on the left side of the wxLine
536// R_ON_AREA, when point lies on the infinite wxLine within a range
537// R_RIGHT_SIDE, when point lies on the right side of the wxLine
538// R_LEFT_SIDE , R_RIGHT_SIDE , R_ON_AREA
539R_PointStatus wxLine::PointOnLine(const wxPoint2DDouble& a_Point, double& Distance, double Marge)
540{
541 Distance=0;
542 // Point may not be queal
543 assert(m_a!=m_b);
544
545 //quick test if point is begin or endpoint
546 if (a_Point == m_a || a_Point == m_b)
547 return R_ON_AREA;
548
549 CalculateLineParameters();
550 // calculate the distance of a_Point in relation to the wxLine
551 Distance = (m_AA * a_Point.m_x)+(m_BB * a_Point.m_y) + m_CC;
552
553 if (Distance < -Marge)
554 return R_LEFT_SIDE;
555 else
556 {
557 if (Distance > Marge)
558 return R_RIGHT_SIDE;
559 else
560 return R_ON_AREA;
561 }
562}
563
564// makes a wxLine same as these
565// usage : wxLine1 = wxLine2;
566wxLine& wxLine::operator=(const wxLine& a_line)
567{
568 m_AA = a_line.m_AA;
569 m_BB = a_line.m_BB;
570 m_CC = a_line.m_CC;
571
572 m_a= a_line.m_a;
573 m_b= a_line.m_b;
574 m_valid_parameters = a_line.m_valid_parameters;
575 return *this;
576}
577
578void wxLine::OffsetContour(const wxLine& nextline,double factor,wxPoint2DDouble& offsetpoint) const
579{
580 wxPoint2DDouble offs_begin(m_a);
581 wxPoint2DDouble offs_end(m_b);
582
583 wxPoint2DDouble offs_bgn_next(nextline.m_a);
584 wxPoint2DDouble offs_end_next(nextline.m_b);
585 // make a wxPoint2DDouble from this point
586
587 Virtual_Point(offs_begin,factor);
588 Virtual_Point(offs_end,factor);
589 wxLine offs_currentline(offs_begin,offs_end);
590
591 nextline.Virtual_Point(offs_bgn_next,factor);
592 nextline.Virtual_Point(offs_end_next,factor);
593 wxLine offs_nextline(offs_bgn_next, offs_end_next);
594
595 offs_nextline.CalculateLineParameters();
596 offs_currentline.CalculateLineParameters();
597 offs_currentline.Intersect(offs_nextline,offsetpoint);
598}
599
600// Return the position of the second wxLine compared to this wxLine
601// Result = IS_ON | IS_LEFT | IS_RIGHT
602// Here Left and Right is defined as being left or right from
603// the this wxLine towards the center (common) node
604// direction of vetors taken as begin to endpoint with end of this at
605// begin of wxLine two
606OUTPRODUCT wxLine::OutProduct(const wxLine& two,double accur)
607{
608 R_PointStatus uitp;
609 double distance;
610 if (two.m_a==two.m_b)
611 assert(0);
612 if (m_a==m_b)
613 assert(0);
614
615 uitp=PointOnLine(two.m_b, distance, accur);
616
617
618 /*double uitp= (_x - first._x) * (third._y - _y) -
619 (_y - first._y) * (third._x - _x);
620 if (uitp>0) return IS_LEFT;
621 if (uitp<0) return IS_RIGHT;
622 return IS_ON;*/
623
624 //depending on direction of this link (going to or coming from centre)
625 if (uitp==R_LEFT_SIDE)
626 return R_IS_LEFT;
627 if (uitp==R_RIGHT_SIDE)
628 return R_IS_RIGHT;
629 return R_IS_ON;
630}
631
632// Intersects two lines if a crossing return TRUE
633// else FALSE
634bool wxLine::Intersect(wxLine& lijn,wxPoint2DDouble& crossing)
635{
636 // lijn must exist
637 assert(m_valid_parameters);
638 assert(lijn.m_valid_parameters);
639
640 double X, Y, Denominator;
641 Denominator = (m_AA * lijn.m_BB) - (lijn.m_AA * m_BB);
642 // Denominator may not be 0
643 if (Denominator == 0.0)
644 return FALSE;
645 // Calculate intersection of both linesegments
646 X = ((m_BB * lijn.m_CC) - (lijn.m_BB * m_CC)) / Denominator;
647 Y = ((lijn.m_AA * m_CC) - (m_AA * lijn.m_CC)) / Denominator;
648
649 crossing.m_x=X;
650 crossing.m_y=Y;
651 return TRUE;
652}
653