File Coverage

blib/lib/Math/Zap/Triangle.pm
Criterion Covered Total %
statement 143 197 72.5
branch 22 52 42.3
condition 53 119 44.5
subroutine 31 49 63.2
pod 25 40 62.5
total 274 457 59.9


line stmt bran cond sub pod time code
1            
2             =head1 Triangle
3            
4             Triangles in 3D space
5            
6             PhilipRBrenan@yahoo.com, 2004, Perl License
7            
8            
9             =head2 Synopsis
10            
11             Example t/triangle.t
12            
13             #_ Triangle ___________________________________________________________
14             # Test 3d triangles
15             # philiprbrenan@yahoo.com, 2004, Perl License
16             #______________________________________________________________________
17            
18             use Math::Zap::Vector;
19             use Math::Zap::Vector2;
20             use Math::Zap::Triangle;
21             use Test::Simple tests=>25;
22            
23             $t = triangle
24             (vector( 0, 0, 0),
25             vector( 0, 0, 4),
26             vector( 4, 0, 0),
27             );
28            
29             $u = triangle
30             (vector( 0, 0, 0),
31             vector( 0, 1, 4),
32             vector( 4, 1, 0),
33             );
34            
35             $T = triangle
36             (vector( 0, 1, 0),
37             vector( 0, 1, 1),
38             vector( 1, 1, 0),
39             );
40            
41             $c = vector(1, 1, 1);
42            
43             #_ Triangle ___________________________________________________________
44             # Distance to plane
45             #______________________________________________________________________
46            
47             ok($t->distance($c) == 1, 'Distance to plane');
48             ok($T->distance($c) == 0, 'Distance to plane');
49             ok($t->distance(2*$c) == 2, 'Distance to plane');
50             ok($t->distanceToPlaneAlongLine(vector(0,-1,0), vector(0,1,0)) == 1, 'Distance to plane towards a point');
51             ok($T->distanceToPlaneAlongLine(vector(0,-1,0), vector(0,1,0)) == 2, 'Distance to plane towards a point');
52            
53             #_ Triangle ___________________________________________________________
54             # Permute the points of a triangle
55             #______________________________________________________________________
56            
57             ok($t->permute == $t, 'Permute 1');
58             ok($t->permute->permute == $t, 'Permute 2');
59             ok($t->permute->permute->permute == $t, 'Permute 3');
60            
61             #_ Triangle ___________________________________________________________
62             # Intersection of a line with a plane defined by a triangle
63             #______________________________________________________________________
64            
65             #ok($t->intersection($c, vector(1, -1, 1)) == vector(1, 0, 1), 'Intersection of line with plane');
66             #ok($t->intersection($c, vector(-1, -1, -1)) == vector(0, 0, 0), 'Intersection of line with plane');
67            
68             #_ Triangle ___________________________________________________________
69             # Test whether a point is in front or behind a plane relative to another
70             # point
71             #______________________________________________________________________
72            
73             ok($t->frontInBehind($c, vector(1, 0.5, 1)) == +1, 'Front');
74             ok($t->frontInBehind($c, vector(1, 0, 1)) == 0, 'In');
75             ok($t->frontInBehind($c, vector(1, -0.5, 1)) == -1, 'Behind');
76            
77             #_ Triangle ___________________________________________________________
78             # Parallel
79             #______________________________________________________________________
80            
81             ok($t->parallel($T) == 1, 'Parallel');
82             ok($t->parallel($u) == 0, 'Not Parallel');
83            
84             #_ Triangle ___________________________________________________________
85             # Coplanar
86             #______________________________________________________________________
87            
88             #ok($t->coplanar($t) == 1, 'Coplanar');
89             #ok($t->coplanar($u) == 0, 'Not coplanar');
90             #ok($t->coplanar($T) == 0, 'Not coplanar');
91            
92             #_ Triangle ___________________________________________________________
93             # Project one triangle onto another
94             #______________________________________________________________________
95            
96             $p = vector(0, 2, 0);
97             $s = $t->project($T, $p);
98            
99             ok($s == triangle
100             (vector(0, 0, 2),
101             vector(0.5, 0, 2),
102             vector(0, 0.5, 2),
103             ), 'Projection of corner 3');
104            
105             #_ Triangle ___________________________________________________________
106             # Convert space to plane coordinates and vice versa
107             #______________________________________________________________________
108            
109             ok($t->convertSpaceToPlane(vector(2, 2, 2)) == vector(0.5,0.5,2), 'Space to Plane');
110             ok($t->convertPlaneToSpace(vector2(0.5, 0.5)) == vector(2, 0, 2), 'Plane to Space');
111            
112             #_ Triangle ___________________________________________________________
113             # Divide
114             #______________________________________________________________________
115            
116             $it = triangle # Intersects t
117             (vector( 0, -1, 2),
118             vector( 0, 2, 2),
119             vector( 3, 2, 2),
120             );
121            
122             @d = $t->divide($it);
123            
124             ok($d[0] == triangle(vector(0, -1, 2), vector(0, 0, 2), vector(1, 0, 2)));
125             ok($d[1] == triangle(vector(0, 2, 2), vector(0, 0, 2), vector(1, 0, 2)));
126             ok($d[2] == triangle(vector(0, 2, 2), vector(1, 0, 2), vector(3, 2, 2)));
127            
128             $it = triangle # Intersects t
129             (vector( 3, 2, 2),
130             vector( 0, 2, 2),
131             vector( 0, -1, 2),
132             );
133            
134             @d = $t->divide($it);
135            
136             ok($d[0] == triangle(vector(0, -1, 2), vector(0, 0, 2), vector(1, 0, 2)));
137             ok($d[1] == triangle(vector(3, 2, 2), vector(1, 0, 2), vector(0, 0, 2)));
138             ok($d[2] == triangle(vector(3, 2, 2), vector(0, 0, 2), vector(0, 2, 2)));
139            
140             $it = triangle # Intersects t
141             (vector( 3, 2, 2),
142             vector( 0, -1, 2),
143             vector( 0, 2, 2),
144             );
145            
146             @d = $t->divide($it);
147            
148             ok($d[0] == triangle(vector(0, -1, 2), vector(1, 0, 2), vector(0, 0, 2)));
149             ok($d[1] == triangle(vector(3, 2, 2), vector(1, 0, 2), vector(0, 0, 2)));
150             ok($d[2] == triangle(vector(3, 2, 2), vector(0, 0, 2), vector(0, 2, 2)));
151            
152            
153            
154             =head2 Description
155            
156             Triangles in 3D space
157            
158             Definitions:
159            
160             Space coordinates = 3d space
161            
162             Plane coordinates = a triangle in 3d space defines a 2d plane with a
163             natural coordinate system: the origin is the first point of the
164             triangle, the (x,y) units of this plane are the sides from the triangles
165             first point to its other points.
166            
167             =cut
168            
169            
170             package Math::Zap::Triangle;
171             $VERSION=1.07;
172 3     3   1679 use Math::Zap::Line2;
  3         8  
  3         85  
173 3     3   1053 use Math::Zap::Unique;
  3         7  
  3         86  
174 3     3   16 use Math::Zap::Vector2 check=>'vector2Check';
  3         7  
  3         83  
175 3     3   578 use Math::Zap::Vector check=>'vectorCheck';
  3         7  
  3         115  
176 3     3   1754 use Math::Zap::Matrix new3v=>'matrixNew3v';
  3         10  
  3         96  
177 3     3   15 use Carp qw(cluck confess);
  3         5  
  3         157  
178 3     3   49 use constant debug => 0; # Debugging level
  3         4  
  3         11820  
179            
180            
181             =head2 Constructors
182            
183            
184             =head3 new
185            
186             Create a triangle from 3 vectors specifying the coordinates of each
187             corner in space coordinates.
188            
189             =cut
190            
191            
192 28     28 1 823 sub new($$$)
193             {my ($a, $b, $c) = vectorCheck(@_);
194 28         100 my $t = bless {a=>$a, b=>$b, c=>$c};
195 28         61 narrow($t, 1);
196 28         139 $t;
197             }
198            
199            
200             =head3 triangle
201            
202             Create a triangle from 3 vectors specifying the coordinates of each
203             corner in space coordinates - synonym for L.
204            
205             =cut
206            
207            
208 27     27 1 78 sub triangle($$$) {new($_[0],$_[1],$_[2])};
209            
210            
211             =head2 Methods
212            
213            
214             =head3 narrow
215            
216             Narrow (colinear) triangle?
217            
218             =cut
219            
220            
221 28     28 1 35 sub narrow($$)
222             {my $t = shift; # Triangle
223 28         37 my $a = 1e-2; # Accuracy
224 28         34 my $A = shift; # Action 0: return indicator, 1: confess
225            
226 28         60 my $n = (($t->b-$t->a) x ($t->c-$t->a))->length < $a;
227            
228 28 50 33     188 confess "Narrow triangle" if $n and $A;
229 28         51 $n;
230             }
231            
232            
233             =head3 check
234            
235             Check its a triangle
236            
237             =cut
238            
239            
240             sub check(@)
241 61     61 1 104 {if (debug)
242             {for my $t(@_)
243             {confess "$t is not a triangle" unless ref($t) eq __PACKAGE__;
244             }
245             }
246 61         206 return (@_)
247             }
248            
249            
250             =head3 is
251            
252             Test its a triangle
253            
254             =cut
255            
256            
257 0 0       0 sub is(@)
258 0     0 1 0 {for my $t(@_)
259             {return 0 unless ref($t) eq __PACKAGE__;
260             }
261 0         0 'triangle';
262             }
263            
264            
265             =head3 components
266            
267             Components of a triangle
268            
269             =cut
270            
271            
272 162     162 0 180 sub a($) {check(@_) if debug; $_[0]->{a}}
  162         553  
273 84     84 0 91 sub b($) {check(@_) if debug; $_[0]->{b}}
  84         343  
274 81     81 0 90 sub c($) {check(@_) if debug; $_[0]->{c}}
  81         198  
275            
276 83     83 0 95 sub ab($) {check(@_) if debug; ($_[0]->{b}-$_[0]->{a})}
  83         269  
277 83     83 0 98 sub ac($) {check(@_) if debug; ($_[0]->{c}-$_[0]->{a})}
  83         233  
278 0     0 0 0 sub ba($) {check(@_) if debug; ($_[0]->{a}-$_[0]->{b})}
  0         0  
279 3     3 0 4 sub bc($) {check(@_) if debug; ($_[0]->{c}-$_[0]->{b})}
  3         12  
280 0     0 0 0 sub ca($) {check(@_) if debug; ($_[0]->{a}-$_[0]->{c})}
  0         0  
281 0     0 0 0 sub cb($) {check(@_) if debug; ($_[0]->{b}-$_[0]->{c})}
  0         0  
282            
283 0     0 0 0 sub abc($) {check(@_) if debug; ($_[0]->{a}, $_[0]->{b}, $_[0]->{c})}
  0         0  
284 0     0 0 0 sub area($){check(@_) if debug; ($_[0]->ab x $_[0]->ac)->length}
  0         0  
285            
286            
287             =head3 clone
288            
289             Create a triangle from another triangle
290            
291             =cut
292            
293            
294 0     0 1 0 sub clone($)
295             {my ($t) = check(@_); # Triangle
296 0         0 bless {a=>$t->a, b=>$t->b, c=>$t->c};
297             }
298            
299            
300             =head3 permute
301            
302             Cyclically permute the points of a triangle
303            
304             =cut
305            
306            
307 12     12 1 30 sub permute($)
308             {my ($t) = check(@_); # Triangle
309 12         28 bless {a=>$t->b, b=>$t->c, c=>$t->a};
310             }
311            
312            
313             =head3 center
314            
315             Center
316            
317             =cut
318            
319            
320 0     0 1 0 sub center($)
321             {my ($t) = check(@_); # Triangle
322 0         0 ($t->a + $t->b + $t->c) / 3;
323             }
324            
325            
326             =head3 add
327            
328             Add a vector to a triangle
329            
330             =cut
331            
332            
333 0     0 1 0 sub add($$)
334             {my ($t) = check(@_[0..0]); # Triangle
335 0         0 my ($v) = vectorCheck(@_[1..1]); # Vector
336 0         0 new($t->a+$v, $t->b+$v, $t->c+$v);
337             }
338            
339            
340             =head3 subtract
341            
342             Subtract a vector from a triangle
343            
344             =cut
345            
346            
347 0     0 1 0 sub subtract($$)
348             {my ($t) = check(@_[0..0]); # Triangle
349 0         0 my ($v) = vectorCheck(@_[1..1]); # Vector
350 0         0 new($t->a-$v, $t->b-$v, $t->c-$v);
351             }
352            
353            
354             =head3 print
355            
356             Print triangle
357            
358             =cut
359            
360            
361 0     0 1 0 sub print($)
362             {my ($t) = check(@_); # Triangle
363 0         0 my ($a, $b, $c) = ($t->a, $t->b, $t->c);
364 0         0 "triangle($a, $b, $c)";
365             }
366            
367            
368             =head3 accuracy
369            
370             # Get/Set accuracy for comparisons
371            
372             =cut
373            
374            
375             my $accuracy = 1e-10;
376            
377             sub accuracy
378 0 0   0 1 0 {return $accuracy unless scalar(@_);
379 0         0 $accuracy = shift();
380             }
381            
382            
383             =head3 distance
384            
385             Shortest distance from plane defined by triangle t to point p
386            
387             =cut
388            
389            
390 15     15 1 44 sub distance($$)
391             {my ($t) = check(@_[0..0]); # Triangle
392 15         484 my ($p) = vectorCheck(@_[1..1]); # Vector
393 15         38 my $n = $t->ab x $t->ac; # Plane normal
394 15         74 my ($a, $b) = ($p, $p+$n);
395            
396 15         38 my $s = matrixNew3v($t->ab, $t->ac, $a-$b)/($a-$t->a);
397            
398 15         137 ($n*$s->z)->length;
399             }
400            
401            
402             =head3 intersectionInPlane
403            
404             Intersect line between two points with plane defined by triangle and
405             return the intersection in plane coordinates.
406             Identical logic as per intersection().
407             Note: no checks (yet) for line parallel to plane.
408            
409             =cut
410            
411            
412 10     10 1 27 sub intersectionInPlane($$$)
413             {my ($t) = check(@_[0..0]); # Triangle
414 10         313 my ($a, $b) = vectorCheck(@_[1..2]); # Vectors
415            
416 10         27 matrixNew3v($t->ab, $t->ac, $a-$b)/($a-$t->a);
417             }
418            
419            
420             =head3 distanceToPlaneAlongLine
421            
422             Distance to plane defined by triangle t going from a to b, or undef
423             if the line is parallel to the plane
424            
425             =cut
426            
427            
428 2     2 1 7 sub distanceToPlaneAlongLine($$$)
429             {my ($t) = check(@_[0..0]); # Triangle
430 2         61 my ($a, $b) = vectorCheck(@_[1..2]); # Vectors
431            
432 2 50       6 return undef if abs(($t->ab x $t->ac) * ($b - $a)) < $accuracy;
433            
434 2         13 my $i = matrixNew3v($t->ab, $t->ac, $a-$b)/($a-$t->a);
435 2         29 $i->z * ($a-$b)->length;
436             }
437            
438            
439             =head3 convertSpaceToPlane
440            
441             Convert space to plane coordinates
442            
443             =cut
444            
445            
446 1     1 1 5 sub convertSpaceToPlane($$)
447             {my ($t) = check(@_[0..0]); # Triangle
448 1         32 my ($p) = vectorCheck(@_[1..1]); # Vector
449            
450 1         3 my $q = $p-$t->a;
451            
452 1         5 vector
453             ($q * $t->ab / ($t->ab * $t->ab),
454             $q * $t->ac / ($t->ac * $t->ac),
455             $q * ($t->ab x $t->ac)->norm
456             );
457             }
458            
459            
460             =head3 convertPlaneToSpace
461            
462             Convert splane to space coordinates
463            
464             =cut
465            
466            
467 7     7 1 14 sub convertPlaneToSpace($$)
468             {my ($t, $p) = @_;
469 7         8 check(@_[0..0]) if debug; # Triangle
470 7         10 vector2Check(@_[1..1]) if debug; # Vector in plane
471            
472 7         15 $t->a + ($p->x * $t->ab) + ($p->y * $t->ac);
473             }
474            
475            
476             =head3 frontInBehind
477            
478             Determine whether a test point b as viewed from a view point a is in
479             front of(1), in(0), or behind(-1) a plane defined by a triangle t.
480             Identical logic as per intersection(), except this time we use the
481             z component to determine the relative position of the point b.
482             Note: no checks (yet) for line parallel to plane.
483            
484             =cut
485            
486            
487 3     3 1 5 sub frontInBehind($$$)
488             {my ($t, $a, $b) = @_;
489 3         4 check(@_[0..0]) if debug; # Triangle
490 3         3 vectorCheck(@_[1..2]) if debug; # Vectors
491 3 50       10 return 1 if abs(($t->ab x $t->ac) * ($a-$b)) < $accuracy; # Parallel
492 3         19 $s = matrixNew3v($t->ab, $t->ac, $a-$b)/($a-$t->a);
493 3         28 $s->z <=> 1;
494             }
495            
496            
497             =head3 frontInBehindZ
498            
499             Determine whether a test point b as viewed from a view point a is in
500             front of(1), in(0), or behind(-1) a plane defined by a triangle t.
501             Identical logic as per intersection(), except this time we use the
502             z component to determine the relative position of the point b.
503             Note: no checks (yet) for line parallel to plane.
504            
505             =cut
506            
507            
508 0     0 1 0 sub frontInBehindZ($$$)
509             {my ($t, $a, $b) = @_;
510 0         0 check(@_[0..0]) if debug; # Triangle
511 0         0 vectorCheck(@_[1..2]) if debug; # Vectors
512 0 0       0 return undef if abs(($t->ab x $t->ac) * ($a-$b)) < $accuracy; # Parallel
513 0         0 $s = matrixNew3v($t->ab, $t->ac, $a-$b)/($a-$t->a);
514 0         0 $s->z;
515             }
516            
517            
518             =head3 parallel
519            
520             Are two triangle parallel?
521             I.e. do they define planes that are parallel?
522             If they are parallel, their normals will have zero cross product
523            
524             =cut
525            
526            
527 5     5 1 18 sub parallel($$)
528             {my ($a, $b) = check(@_); # Triangles
529 5         17 !(($a->ab x $a->ac) x ($b->ab x $b->ac))->length;
530             }
531            
532            
533             =head3 divide
534            
535             Divide triangle b by a: split b into triangles each of which is not
536             intersected by a.
537             Triangles are easy to draw in 3d except when they intersect:
538             If they do not intersect, we can always draw one on top of the other
539             and obtain the correct result;
540             If they do intersect, they have to be split along the line of
541             intersection into a sub triangle and a quadralateral: which can
542             be be split again to obtain a result consisting of only triangles.
543             The splitting can be done once: Each new view point only requires
544             the correct ordering of the non intersecting triangles.
545            
546             =cut
547            
548            
549 3     3 1 24 sub divide($$)
550             {my ($a, $b) = check(@_); # Triangles
551            
552 3 50       12 return ($b) if $a->parallel($b); # Parallel: no need to split
553            
554 3 50       34 my $A = $a->permute; $a = $A if $b->distance($A->a) > $b->distance($a->a);
  3         12  
555 3 50       15 $A = $A->permute; $a = $A if $b->distance($A->a) > $b->distance($a->a);
  3         10  
556            
557 3         14 my $na = $a->ab x $a->ac; # Normal to a
558 3         16 my $nb = $b->ab x $b->ac; # Normal to b
559            
560 3         14 my $aa = $a->a;
561 3         25 my $ab = $a->b;
562 3         8 my $ac = $a->c;
563 3         10 my $bc = $a->bc;
564            
565             # Avoid using vectors in a that are parallel to b
566 3 100       10 $ab += $bc/2 if ($a->ab->norm * $nb->norm) < 0.1;
567 3 50       19 $ac += $bc/2 if ($a->ac->norm * $nb->norm) < 0.1;
568            
569             # Two points in both planes in b plane coordinates
570 3         23 my $i = $b->intersectionInPlane($aa, $ab);
571 3         28 my $j = $b->intersectionInPlane($aa, $ac);
572            
573            
574             # Does the line between these points intersect the sides of triangle b?
575 3         29 my $l = line2
576             (vector2($i->x, $i->y),
577             vector2($j->x, $j->y),
578             );
579 3 50       17 return ($b) if ($l->b-$l->a)->length < $accuracy;
580            
581             # Triangle b has very simple sides in b plane coordinates
582            
583 3         95 my $l1 = line2(vector2(0, 0), vector2(1, 0)); # ab
584 3         90 my $l2 = line2(vector2(0, 0), vector2(0, 1)); # ac
585 3         92 my $l3 = line2(vector2(1, 0), vector2(0, 1)); # bc
586            
587 3   66     14 my $i1 = ((!$l->parallel($l1)) and ($l->intersectWithin($l1)));
588 3   66     15 my $i2 = ((!$l->parallel($l2)) and ($l->intersectWithin($l2)));
589 3   66     15 my $i3 = ((!$l->parallel($l3)) and ($l->intersectWithin($l3)));
590            
591             # There should be either 0 or 2 intersections.
592 3         8 {my $n = $i1+$i2+$i3;
  3         7  
593 3 50 33     33 ($n == 1 or $n == 3) and debug and warn "There should 0 or 2 intersections, not $n";
      50        
594 3 50       11 return ($b) unless $n == 2; # No division required
595             }
596            
597             # There are two intersections.
598             # Make a copy of b called c, orientated so that the line of
599             # intersection crosses sides c->ab, c->ac
600 3         5 my $c;
601 3 100 100     15 $c = $b if $i1 and $i2;
602 3 100 100     15 $c = triangle($b->b, $b->a, $b->c) if $i1 and $i3;
603 3 100 100     17 $c = triangle($b->c, $b->a, $b->b) if $i2 and $i3;
604            
605             # Find intersection points in terms of reorientated triangle
606            
607 3 100 100     32 unless ($i1 and $i2)
  2         7  
608             {$i = $c->intersectionInPlane($aa, $ab);
609 2         19 $j = $c->intersectionInPlane($aa, $ac);
610 2         20 $l = line2
611             (vector2($i->x, $i->y),
612             vector2($j->x, $j->y),
613             );
614             }
615            
616             # this time in plane coordinates
617 3         18 $i1 = $l->intersect($l1);
618 3         14 $i2 = $l->intersect($l2);
619            
620             # Convert to space coordinates
621 3         18 my $s1 = $c->convertPlaneToSpace($i1);
622 3         23 my $s2 = $c->convertPlaneToSpace($i2);
623            
624             # Vertices close to intersection points
625 3         21 my $a1 = ($c->a - $s1)->length < 1e-3;
626 3         13 my $a2 = ($c->a - $s2)->length < 1e-3;
627 3         12 my $b1 = ($c->b - $s1)->length < 1e-3;
628 3         12 my $b2 = ($c->b - $s2)->length < 1e-3;
629 3         12 my $c1 = ($c->c - $s1)->length < 1e-3;
630 3         12 my $c2 = ($c->c - $s2)->length < 1e-3;
631            
632 3 0 33     40 return ($b) if ($a1 or $b1 or $c1) and ($a2 or $b2 or $c2);
      0        
      33        
633            
634             # Divide b into 3 if the intersections points are far from the vertices
635             return
636 3 50 33     58 (triangle($c->a, $s1, $s2),
      33        
      33        
      33        
      33        
637             triangle($c->b, $s1, $s2),
638             triangle($c->b, $s2, $c->c),
639             ) unless $a1 or $a2 or $b1 or $b2 or $c1 or $c2;
640            
641             # If only one intersection point is close to a vertex, make it s1.
642 0 0 0     0 ($s1, $s2, $a1, $b1, $c1, $a2, $b2, $c2) =
      0        
      0        
643             ($s2, $s1, $a2, $b2, $c2, $a1, $b1, $c1) if !($a1 or $b1 or $c1) and ($a2 or $b2 or $c2);
644            
645             # Divide b into 2 if one intersection point is close to a vertex
646             return
647 0 0       0 (triangle($c->a, $c->b, $s2),
648             triangle($c->a, $c->c, $s2),
649             ) if $a1;
650             return
651 0 0       0 (triangle($c->a, $c->b, $s2),
652             triangle($c->c, $c->b, $s2),
653             ) if $b1;
654             return
655 0 0       0 (triangle($c->a, $c->c, $s2),
656             triangle($c->b, $c->c, $s2),
657             ) if $c1;
658 0         0 confess "Unable to divide triangle $a by $b\n"
659             }
660            
661            
662             =head3 project
663            
664             Project onto the plane defined by triangle t the image of a triangle
665             triangle T as viewed from a view point p.
666             Return the coordinates of the projection of T onto t using the plane
667             coordinates induced by t.
668             The projection coordinates are (of course) 2d in the projection plane,
669             however they are returned as the x,y components of a 3d vector with
670             the z component set to the multiple of the distance from the view point
671             to the corresponding corner of T required to reach t. If z > 1, this
672             corner of T is in front the plane of t, if z < 1 this corner of T is
673             behind the plane of t.
674             The logic is the same as intersection().
675            
676             =cut
677            
678            
679 1     1 1 8 sub project($$$)
680             {my ($t, $T, $p) = @_;
681 1         2 check(@_[0..1]) if debug; # Triangles
682 1         3 vectorCheck(@_[2..2]) if debug; # Vector
683            
684 1         5 new
685             (matrixNew3v($t->ab, $t->ac, $p-$T->a)/($p-$t->a),
686             matrixNew3v($t->ab, $t->ac, $p-$T->b)/($p-$t->a),
687             matrixNew3v($t->ab, $t->ac, $p-$T->c)/($p-$t->a),
688             );
689             }
690            
691            
692             =head3 split
693            
694             Split a triangle into 4 sub triangles unless the sub triangles would
695             be too small
696            
697             =cut
698            
699            
700 0     0 1 0 sub split($$)
701             {my ($t) = check(@_[0..0]); # Triangles
702 0         0 my ($s) = (@_[1..1]); # Minimum size
703            
704 0 0 0     0 return () unless
      0        
705             $t->ab->length > $s and
706             $t->ac->length > $s and
707             $t->bc->length > $s;
708            
709 0         0 (new($t->a, ($t->a+$t->b)/2, ($t->a+$t->c)/2),
710             new($t->b, ($t->b+$t->a)/2, ($t->b+$t->c)/2),
711             new($t->c, ($t->c+$t->a)/2, ($t->c+$t->b)/2),
712             new(($t->a+$t->b)/2, ($t->a+$t->b)/2, ($t->b+$t->c)/2)
713             )
714             }
715            
716            
717             =head3 triangulate
718            
719             Triangulate
720            
721             =cut
722            
723            
724 0     0 1 0 sub triangulate($$)
725             {my ($t) = check(@_[0..0]); # Triangle
726 0         0 my $color = @_[1..1]; # Color
727 0         0 my $plane = unique(); # Plane
728            
729 0         0 {triangle=>$t, color=>$color, plane=>$plane};
730             }
731            
732            
733             =head3 equals
734            
735             Compare two triangles for equality
736            
737             =cut
738            
739            
740 13     13 1 26 sub equals($$)
741             {my ($a, $b) = check(@_); # Triangles
742 13         31 my ($aa, $ab, $ac) = ($a->a, $a->b, $a->c);
743 13         26 my ($ba, $bb, $bc) = ($b->a, $b->b, $b->c);
744 13         24 my $d = $accuracy;
745            
746 13 50 100     37 return 1 if
      66        
      66        
      66        
      66        
      66        
      66        
      66        
      33        
      33        
      66        
      33        
      33        
      33        
      0        
      0        
      33        
747             abs(($aa-$ba)->length) < $d and abs(($ab-$bb)->length) < $d and abs(($ac-$bc)->length) < $d or
748             abs(($aa-$ba)->length) < $d and abs(($ab-$bc)->length) < $d and abs(($ac-$bb)->length) < $d or
749             abs(($aa-$bb)->length) < $d and abs(($ab-$bc)->length) < $d and abs(($ac-$ba)->length) < $d or
750             abs(($aa-$bb)->length) < $d and abs(($ab-$ba)->length) < $d and abs(($ac-$bc)->length) < $d or
751             abs(($aa-$bc)->length) < $d and abs(($ab-$ba)->length) < $d and abs(($ac-$bb)->length) < $d or
752             abs(($aa-$bc)->length) < $d and abs(($ab-$bb)->length) < $d and abs(($ac-$ba)->length) < $d;
753 0         0 0;
754             }
755            
756            
757             =head2 Operators
758            
759             Operator overloads
760            
761             =cut
762            
763            
764             use overload
765 3         56 '+', => \&add3, # Add a vector
766             '-', => \&sub3, # Subtract a vector
767             '==' => \&equals3, # Equals
768             '""' => \&print3, # Print
769 3     3   31 'fallback' => FALSE;
  3         7  
770            
771            
772             =head3 add
773            
774             Add operator.
775            
776             =cut
777            
778            
779             sub add3
780 0     0 0 0 {my ($a, $b, $c) = @_;
781 0         0 return $a->add($b);
782             }
783            
784            
785             =head3 subtract
786            
787             Subtract operator.
788            
789             =cut
790            
791            
792             sub sub3
793 0     0 0 0 {my ($a, $b, $c) = @_;
794 0         0 return $a->subtract($b);
795             }
796            
797            
798             =head3 equals
799            
800             Equals operator.
801            
802             =cut
803            
804            
805             sub equals3
806 13     13 0 23 {my ($a, $b, $c) = @_;
807 13         35 return $a->equals($b);
808             }
809            
810            
811             =head3 print
812            
813             Print a triangle
814            
815             =cut
816            
817            
818             sub print3
819 0     0 0   {my ($a) = @_;
820 0           return $a->print;
821             }
822            
823            
824             =head2 Exports
825            
826             Export L
827            
828             =cut
829            
830            
831 3         29 use Math::Zap::Exports qw(
832             triangle ($$$)
833 3     3   739 );
  3         8  
834            
835             #_ Triangle ___________________________________________________________
836             # Package loaded successfully
837             #______________________________________________________________________
838            
839             1;
840            
841            
842            
843             =head2 Credits
844            
845             =head3 Author
846            
847             philiprbrenan@yahoo.com
848            
849             =head3 Copyright
850            
851             philiprbrenan@yahoo.com, 2004
852            
853             =head3 License
854            
855             Perl License.
856            
857            
858             =cut