Subversion Repositories Applications.gtt

Rev

Rev 61 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
60 jpm 1
<?php
2
/*
3
 * This work is hereby released into the Public Domain.
4
 * To view a copy of the public domain dedication,
5
 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
6
 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
7
 *
8
 */
9
 
10
require_once dirname(__FILE__)."/../Graph.class.php";
11
 
12
abstract class awShape {
13
 
14
	/**
15
	 * Is the shape hidden ?
16
	 *
17
	 * @var bool
18
	 */
19
	protected $hide = FALSE;
20
 
21
	/**
22
	 * Shape style
23
	 *
24
	 * @var int
25
	 */
26
	public $style;
27
 
28
	/**
29
	 * Shape thickness
30
	 *
31
	 * @var int
32
	 */
33
	public $thickness;
34
 
35
	/**
36
	 * Solid shape
37
	 *
38
	 * @var int
39
	 */
40
	const SOLID = 1;
41
 
42
	/**
43
	 * Dotted shape
44
	 *
45
	 * @var int
46
	 */
47
	const DOTTED = 2;
48
 
49
	/**
50
	 * Dashed shape
51
	 *
52
	 * @var int
53
	 */
54
	const DASHED = 3;
55
 
56
	/**
57
	 * Change shape style
58
	 *
59
	 * @param int $style Line style
60
	 */
61
	public function setStyle($style) {
62
		$this->style = (int)$style;
63
	}
64
 
65
	/**
66
	 * Return shape style
67
	 *
68
	 * @return int
69
	 */
70
	public function getStyle() {
71
		return $this->style;
72
	}
73
 
74
	/**
75
	 * Change shape thickness
76
	 *
77
	 * @param int $thickness Shape thickness in pixels
78
	 */
79
	public function setThickness($thickness) {
80
		$this->thickness = (int)$thickness;
81
	}
82
 
83
	/**
84
	 * Return shape thickness
85
	 *
86
	 * @return int
87
	 */
88
	public function getThickness() {
89
		return $this->thickness;
90
	}
91
 
92
	/**
93
	 * Hide the shape
94
	 *
95
	 * @param bool $hide
96
	 */
97
	public function hide($hide) {
98
		$this->hide = (bool)$hide;
99
	}
100
 
101
	/**
102
	 * Show the shape
103
	 *
104
	 * @param bool $shape
105
	 */
106
	public function show($shape) {
107
		$this->hide = (bool)!$shape;
108
	}
109
 
110
	/**
111
	 * Is the line hidden ?
112
	 *
113
	 * @return bool
114
	 */
115
	public function isHidden() {
116
		return $this->hide;
117
	}
118
 
119
}
120
 
121
registerClass('Shape', TRUE);
122
 
123
/**
124
 * Describe a point
125
 *
126
 * @package Artichow
127
 */
128
class awPoint extends awShape {
129
 
130
	/**
131
	 * X coord
132
	 *
133
	 * @var float
134
	 */
135
	public $x;
136
 
137
	/**
138
	 * Y coord
139
	 *
140
	 * @var float
141
	 */
142
	public $y;
143
 
144
	/**
145
	 * Build a new awpoint
146
	 *
147
	 * @param float $x
148
	 * @param float $y
149
	 */
150
	public function __construct($x, $y) {
151
 
152
		$this->setLocation($x, $y);
153
 
154
	}
155
 
156
	/**
157
	 * Change X value
158
	 *
159
	 * @param float $x
160
	 */
161
	public function setX($x) {
162
		$this->x = (float)$x;
163
	}
164
 
165
	/**
166
	 * Change Y value
167
	 *
168
	 * @param float $y
169
	 */
170
	public function setY($y) {
171
		$this->y = (float)$y;
172
	}
173
 
174
	/**
175
	 * Change point location
176
	 *
177
	 * @param float $x
178
	 * @param float $y
179
	 */
180
	public function setLocation($x, $y) {
181
		$this->setX($x);
182
		$this->setY($y);
183
	}
184
 
185
	/**
186
	 * Get point location
187
	 *
188
	 * @param array Point location
189
	 */
190
	public function getLocation() {
191
		return array($this->x, $this->y);
192
	}
193
 
194
	/**
195
	 * Get distance to another point
196
	 *
197
	 * @param awPoint $p A point
198
	 * @return float
199
	 */
200
	public function getDistance(awPoint $p) {
201
 
202
		return sqrt(pow($p->x - $this->x, 2) + pow($p->y - $this->y, 2));
203
 
204
	}
205
 
206
	/**
207
	 * Move the point to another location
208
	 *
209
	 * @param Point A Point with the new awlocation
210
	 */
211
	public function move($x, $y) {
212
 
213
		return new awPoint(
214
			$this->x + $x,
215
			$this->y + $y
216
		);
217
 
218
	}
219
 
220
}
221
 
222
registerClass('Point');
223
 
224
 
225
/**
226
 * Describe a line
227
 *
228
 * @package Artichow
229
 */
230
class awLine extends awShape {
231
 
232
	/**
233
	 * Line first point
234
	 *
235
	 * @param Point
236
	 */
237
	public $p1;
238
 
239
	/**
240
	 * Line second point
241
	 *
242
	 * @param Point
243
	 */
244
	public $p2;
245
 
246
	/**
247
	 * The line slope (the m in y = mx + p)
248
	 *
249
	 * @param float
250
	 */
251
	private $slope;
252
 
253
	/**
254
	 * The y-intercept value of the line (the p in y = mx + p)
255
	 *
256
	 * @param float
257
	 */
258
	private $origin;
259
 
260
	/**
261
	 * Build a new awline
262
	 *
263
	 * @param awPoint $p1 First point
264
	 * @param awPoint $p2 Second point
265
	 * @param int $type Style of line (default to solid)
266
	 * @param int $thickness Line thickness (default to 1)
267
	 */
268
	public function __construct($p1 = NULL, $p2 = NULL, $type = awLine::SOLID, $thickness = 1) {
269
 
270
		$this->setLocation($p1, $p2);
271
		$this->setStyle($type);
272
		$this->setThickness($thickness);
273
 
274
	}
275
 
276
	/**
277
	 * Build a line from 4 coords
278
	 *
279
	 * @param int $x1 Left position
280
	 * @param int $y1 Top position
281
	 * @param int $x2 Right position
282
	 * @param int $y2 Bottom position
283
	 */
284
	public static function build($x1, $y1, $x2, $y2) {
285
 
286
		return new awLine(
287
			new awPoint($x1, $y1),
288
			new awPoint($x2, $y2)
289
		);
290
 
291
	}
292
 
293
	/**
294
	 * Change X values of the line
295
	 *
296
	 * @param int $x1 Begin value
297
	 * @param int $x2 End value
298
	 */
299
	public function setX($x1, $x2) {
300
		$this->p1->setX($x1);
301
		$this->p2->setX($x2);
302
 
303
		// Resets slope and origin values so they are
304
		// recalculated when and if needed.
305
		$this->slope = NULL;
306
		$this->origin = NULL;
307
	}
308
 
309
	/**
310
	 * Change Y values of the line
311
	 *
312
	 * @param int $y1 Begin value
313
	 * @param int $y2 End value
314
	 */
315
	public function setY($y1, $y2) {
316
		$this->p1->setY($y1);
317
		$this->p2->setY($y2);
318
 
319
		// Resets slope and origin values so they are
320
		// recalculated when and if needed.
321
		$this->slope = NULL;
322
		$this->origin = NULL;
323
	}
324
 
325
	/**
326
	 * Change line location
327
	 *
328
	 * @param awPoint $p1 First point
329
	 * @param awPoint $p2 Second point
330
	 */
331
	public function setLocation($p1, $p2) {
332
		if(is_null($p1) or $p1 instanceof awPoint) {
333
			$this->p1 = $p1;
334
		}
335
		if(is_null($p2) or $p2 instanceof awPoint) {
336
			$this->p2 = $p2;
337
		}
338
 
339
		// Resets slope and origin values so they are
340
		// recalculated when and if needed.
341
		$this->slope = NULL;
342
		$this->origin = NULL;
343
	}
344
 
345
	/**
346
	 * Get line location
347
	 *
348
	 * @param array Line location
349
	 */
350
	public function getLocation() {
351
		return array($this->p1, $this->p2);
352
	}
353
 
354
	/**
355
	 * Get the line size
356
	 *
357
	 * @return float
358
	 */
359
	public function getSize() {
360
 
361
		$square = pow($this->p2->x - $this->p1->x, 2) + pow($this->p2->y - $this->p1->y, 2);
362
		return sqrt($square);
363
 
364
	}
365
 
366
	/**
367
	 * Calculate the line slope
368
	 *
369
	 */
370
	private function calculateSlope() {
371
		if($this->isHorizontal()) {
372
			$this->slope = 0;
373
		} else {
374
			$slope = ($this->p1->y - $this->p2->y) / ($this->p1->x - $this->p2->x);
375
 
376
			$this->slope = $slope;
377
		}
378
	}
379
 
380
	/**
381
	 * Calculate the y-intercept value of the line
382
	 *
383
	 */
384
	private function calculateOrigin() {
385
		if($this->isHorizontal()) {
386
			$this->origin = $this->p1->y; // Or p2->y
387
		} else {
388
			$y1 = $this->p1->y;
389
			$y2 = $this->p2->y;
390
			$x1 = $this->p1->x;
391
			$x2 = $this->p2->x;
392
 
393
			$origin = ($y2 * $x1 - $y1 * $x2) / ($x1 - $x2);
394
 
395
			$this->origin = $origin;
396
		}
397
	}
398
 
399
	/**
400
	 * Calculate the slope and y-intercept value of the line
401
	 *
402
	 */
403
	private function calculateEquation() {
404
		$this->calculateSlope();
405
		$this->calculateOrigin();
406
	}
407
 
408
	/**
409
	 * Get the line slope value
410
	 *
411
	 * @return float
412
	 */
413
	public function getSlope() {
414
		if($this->isVertical()) {
415
			return NULL;
416
		} elseif($this->slope !== NULL) {
417
			return $this->slope;
418
		} else {
419
			$this->calculateSlope();
420
			return $this->slope;
421
		}
422
	}
423
 
424
	/**
425
	 * Get the line y-intercept value
426
	 *
427
	 * @return float
428
	 */
429
	public function getOrigin() {
430
		if($this->isVertical()) {
431
			return NULL;
432
		} elseif($this->origin !== NULL) {
433
			return $this->origin;
434
		} else {
435
			$this->calculateOrigin();
436
			return $this->origin;
437
		}
438
	}
439
 
440
	/**
441
	 * Get the line equation
442
	 *
443
	 * @return array An array containing the slope and y-intercept value of the line
444
	 */
445
	public function getEquation() {
446
		$slope	= $this->getSlope();
447
		$origin = $this->getOrigin();
448
 
449
		return array($slope, $origin);
450
	}
451
 
452
	/**
453
	 * Return the x coordinate of a point on the line
454
	 * given its y coordinate.
455
	 *
456
	 * @param float $y The y coordinate of the Point
457
	 * @return float $x The corresponding x coordinate
458
	 */
459
	public function getXFrom($y) {
460
		$x = NULL;
461
 
462
		if($this->isVertical()) {
463
			list($p, ) = $this->getLocation();
464
			$x = $p->x;
465
		} else {
466
			list($slope, $origin) = $this->getEquation();
467
 
468
			if($slope !== 0) {
469
				$y = (float)$y;
470
				$x = ($y - $origin) / $slope;
471
			}
472
		}
473
 
474
		return $x;
475
	}
476
 
477
	/**
478
	 * Return the y coordinate of a point on the line
479
	 * given its x coordinate.
480
	 *
481
	 * @param float $x The x coordinate of the Point
482
	 * @return float $y The corresponding y coordinate
483
	 */
484
	public function getYFrom($x) {
485
		$y = NULL;
486
 
487
		if($this->isHorizontal()) {
488
			list($p, ) = $this->getLocation();
489
			$y = $p->y;
490
		} else {
491
			list($slope, $origin) = $this->getEquation();
492
 
493
			if($slope !== NULL) {
494
				$x = (float)$x;
495
				$y = $slope * $x + $origin;
496
			}
497
		}
498
 
499
		return $y;
500
	}
501
 
502
	/**
503
	 * Test if the line can be considered as a point
504
	 *
505
	 * @return bool
506
	 */
507
	public function isPoint() {
508
		return ($this->p1->x === $this->p2->x and $this->p1->y === $this->p2->y);
509
	}
510
 
511
	/**
512
	 * Test if the line is a vertical line
513
	 *
514
	 * @return bool
515
	 */
516
	public function isVertical() {
517
		return ($this->p1->x === $this->p2->x);
518
	}
519
 
520
	/**
521
	 * Test if the line is an horizontal line
522
	 *
523
	 * @return bool
524
	 */
525
	public function isHorizontal() {
526
		return ($this->p1->y === $this->p2->y);
527
	}
528
 
529
	/**
530
	 * Returns TRUE if the line is going all the way from the top
531
	 * to the bottom of the polygon surrounding box.
532
	 *
533
	 * @param $polygon Polygon A Polygon object
534
	 * @return bool
535
	 */
536
	public function isTopToBottom(awPolygon $polygon) {
537
		list($xMin, $xMax) = $polygon->getBoxXRange();
538
		list($yMin, $yMax) = $polygon->getBoxYRange();
539
 
540
		if($this->isHorizontal()) {
541
			return FALSE;
542
		} else {
543
			if($this->p1->y < $this->p2->y) {
544
				$top = $this->p1;
545
				$bottom = $this->p2;
546
			} else {
547
				$top = $this->p2;
548
				$bottom = $this->p1;
549
			}
550
 
551
			return (
552
				$this->isOnBoxTopSide($top, $xMin, $xMax, $yMin)
553
				and
554
				$this->isOnBoxBottomSide($bottom, $xMin, $xMax, $yMax)
555
			);
556
		}
557
	}
558
 
559
	/**
560
	 * Returns TRUE if the line is going all the way from the left side
561
	 * to the right side of the polygon surrounding box.
562
	 *
563
	 * @param $polygon Polygon A Polygon object
564
	 * @return bool
565
	 */
566
	public function isLeftToRight(awPolygon $polygon) {
567
		list($xMin, $xMax) = $polygon->getBoxXRange();
568
		list($yMin, $yMax) = $polygon->getBoxYRange();
569
 
570
		if($this->isVertical()) {
571
			return FALSE;
572
		} else {
573
			if($this->p1->x < $this->p2->x) {
574
				$left = $this->p1;
575
				$right = $this->p2;
576
			} else {
577
				$left = $this->p2;
578
				$right = $this->p1;
579
			}
580
		}
581
 
582
		return (
583
			$this->isOnBoxLeftSide($left, $yMin, $yMax, $xMin)
584
			and
585
			$this->isOnBoxRightSide($right, $yMin, $yMax, $xMax)
586
		);
587
	}
588
 
589
	private function isOnBoxTopSide(awPoint $point, $xMin, $xMax, $yMin) {
590
		if(
591
			$point->y === $yMin
592
			and
593
			$point->x >= $xMin
594
			and
595
			$point->x <= $xMax
596
		) {
597
			return TRUE;
598
		} else {
599
			return FALSE;
600
		}
601
	}
602
 
603
	private function isOnBoxBottomSide(awPoint $point, $xMin, $xMax, $yMax) {
604
		if(
605
			$point->y === $yMax
606
			and
607
			$point->x >= $xMin
608
			and
609
			$point->x <= $xMax
610
		) {
611
			return TRUE;
612
		} else {
613
			return FALSE;
614
		}
615
	}
616
 
617
	private function isOnBoxLeftSide(awPoint $point, $yMin, $yMax, $xMin) {
618
		if(
619
			$point->x === $xMin
620
			and
621
			$point->y >= $yMin
622
			and
623
			$point->y <= $yMax
624
		) {
625
			return TRUE;
626
		} else {
627
			return FALSE;
628
		}
629
	}
630
 
631
	private function isOnBoxRightSide(awPoint $point, $yMin, $yMax, $xMax) {
632
		if(
633
			$point->x === $xMax
634
			and
635
			$point->y >= $yMin
636
			and
637
			$point->y <= $yMax
638
		) {
639
			return TRUE;
640
		} else {
641
			return FALSE;
642
		}
643
	}
644
 
645
}
646
 
647
registerClass('Line');
648
 
649
/**
650
 * A vector is a type of line
651
 * The sense of the vector goes from $p1 to $p2.
652
 *
653
 * @package Artichow
654
 */
655
class awVector extends awLine {
656
 
657
	/**
658
	 * Get vector angle in radians
659
	 *
660
	 * @return float
661
	 */
662
	public function getAngle() {
663
 
664
		if($this->isPoint()) {
665
			return 0.0;
666
		}
667
 
668
		$size = $this->getSize();
669
 
670
		$width = ($this->p2->x - $this->p1->x);
671
		$height = ($this->p2->y - $this->p1->y) * -1;
672
 
673
		if($width >= 0 and $height >= 0) {
674
			return acos($width / $size);
675
		} else if($width <= 0 and $height >= 0) {
676
			return acos($width / $size);
677
		} else {
678
			$height *= -1;
679
			if($width >= 0 and $height >= 0) {
680
				return 2 * M_PI - acos($width / $size);
681
			} else if($width <= 0 and $height >= 0) {
682
				return 2 * M_PI - acos($width / $size);
683
			}
684
		}
685
 
686
	}
687
 
688
}
689
 
690
registerClass('Vector');
691
 
692
 
693
/**
694
 * Describe a polygon
695
 *
696
 * @package Artichow
697
 */
698
class awPolygon extends awShape {
699
 
700
	/**
701
	 * Polygon points
702
	 *
703
	 * @var array
704
	 */
705
	protected $points = array();
706
 
707
	/**
708
	 * Set a point in the polygon
709
	 *
710
	 * @param int $pos Point position
711
	 * @param awPoint $point
712
	 */
713
	public function set($pos, $point) {
714
		if(is_null($point) or $point instanceof awPoint) {
715
			$this->points[$pos] = $point;
716
		}
717
	}
718
 
719
	/**
720
	 * Add a point at the end of the polygon
721
	 *
722
	 * @param awPoint $point
723
	 */
724
	public function append($point) {
725
		if(is_null($point) or $point instanceof awPoint) {
726
			$this->points[] = $point;
727
		}
728
	}
729
 
730
	/**
731
	 * Get a point at a position in the polygon
732
	 *
733
	 * @param int $pos Point position
734
	 * @return Point
735
	 */
736
	public function get($pos) {
737
		return $this->points[$pos];
738
	}
739
 
740
	/**
741
	 * Count number of points in the polygon
742
	 *
743
	 * @return int
744
	 */
745
	public function count() {
746
		return count($this->points);
747
	}
748
 
749
	/**
750
	 * Returns all points in the polygon
751
	 *
752
	 * @return array
753
	 */
754
	public function all() {
755
		return $this->points;
756
	}
757
 
758
	/**
759
	 * Returns the different lines formed by the polygon vertices
760
	 *
761
	 * @return array
762
	 */
763
	public function getLines() {
764
		$lines = array();
765
		$count = $this->count();
766
 
767
		for($i = 0; $i < $count - 1; $i++) {
768
			$lines[] = new Line($this->get($i), $this->get($i + 1));
769
		}
770
 
771
		// "Close" the polygon
772
		$lines[] = new Line($this->get($count - 1), $this->get(0));
773
 
774
		return $lines;
775
	}
776
 
777
	/**
778
	 * Get the upper-left and lower-right points
779
	 * of the bounding box around the polygon
780
	 *
781
	 * @return array An array of two Point objects
782
	 */
783
	public function getBoxPoints() {
784
		$count = $this->count();
785
		$x = $y = array();
786
 
787
		for($i = 0; $i < $count; $i++) {
788
			$point = $this->get($i);
789
 
790
			list($x[], $y[]) = $point->getLocation();
791
		}
792
 
793
		$upperLeft  = new Point(min($x), min($y));
794
		$lowerRight = new Point(max($x), max($y));
795
 
796
		return array($upperLeft, $lowerRight);
797
	}
798
 
799
	/**
800
	 * Return the range of the polygon on the y axis,
801
	 * i.e. the minimum and maximum y value of any point in the polygon
802
	 *
803
	 * @return array
804
	 */
805
	public function getBoxYRange() {
806
		list($p1, $p2) = $this->getBoxPoints();
807
 
808
		list(, $yMin) = $p1->getLocation();
809
		list(, $yMax) = $p2->getLocation();
810
 
811
		return array($yMin, $yMax);
812
	}
813
 
814
	/**
815
	 * Return the range of the polygon on the x axis,
816
	 * i.e. the minimum and maximum x value of any point in the polygon
817
	 *
818
	 * @return array
819
	 */
820
	public function getBoxXRange() {
821
		list($p1, $p2) = $this->getBoxPoints();
822
 
823
		list($xMin, ) = $p1->getLocation();
824
		list($xMax, ) = $p2->getLocation();
825
 
826
		return array($xMin, $xMax);
827
	}
828
 
829
}
830
 
831
registerClass('Polygon');
832
?>