]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/liner.cpp
Speed-up for wxCanvasImage.
[wxWidgets.git] / contrib / src / canvas / liner.cpp
1 /*
2 Program wxLine.CPP
3 Purpose Mainly used for calculating crossings
4 Last 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
15 #include "wx/canvas/liner.h"
16
17 wxLine::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
31 wxLine::~wxLine()
32 {
33 }
34
35 wxLine::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
63 int 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
179 int 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
269 double 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
279 void 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 //
295 void 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 //
331 bool 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 //
369 wxPoint2DDouble 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 //
379 wxPoint2DDouble 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
391 int 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)
495 R_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
539 R_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;
566 wxLine& 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
578 void 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
606 OUTPRODUCT 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
634 bool 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