1 ! Copyright (C) 2007, 2008 Alex Chapman
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays colors combinators float-arrays kernel
4 locals math math.constants math.matrices math.order math.ranges
5 math.vectors math.quadratic random sequences vectors jamshred.oint ;
8 : n-segments ( -- n ) 5000 ; inline
10 TUPLE: segment < oint number color radius ;
13 : segment-number++ ( segment -- )
14 [ number>> 1+ ] keep (>>number) ;
16 : random-color ( -- color )
17 { 100 100 100 } [ random 100 / >float ] map first3 1.0 <rgba> ;
19 : tunnel-segment-distance ( -- n ) 0.4 ;
20 : random-rotation-angle ( -- theta ) pi 20 / ;
22 : random-segment ( previous-segment -- segment )
23 clone dup random-rotation-angle random-turn
24 tunnel-segment-distance over go-forward
25 random-color >>color dup segment-number++ ;
27 : (random-segments) ( segments n -- segments )
29 >r dup peek random-segment over push r> 1- (random-segments)
32 : default-segment-radius ( -- r ) 1 ;
34 : initial-segment ( -- segment )
35 F{ 0 0 0 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 }
36 0 random-color default-segment-radius <segment> ;
38 : random-segments ( n -- segments )
39 initial-segment 1vector swap (random-segments) ;
41 : simple-segment ( n -- segment )
42 [ F{ 0 0 -1 } n*v F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] keep
43 random-color default-segment-radius <segment> ;
45 : simple-segments ( n -- segments )
46 [ simple-segment ] map ;
48 : <random-tunnel> ( -- segments )
49 n-segments random-segments ;
51 : <straight-tunnel> ( -- segments )
52 n-segments simple-segments ;
54 : sub-tunnel ( from to segments -- segments )
55 #! return segments between from and to, after clamping from and to to
57 [ sequence-index-range [ clamp-to-range ] curry bi@ ] keep <slice> ;
59 : nearer-segment ( segment segment oint -- segment )
60 #! return whichever of the two segments is nearer to the oint
61 >r 2dup r> tuck distance >r distance r> < -rot ? ;
63 : (find-nearest-segment) ( nearest next oint -- nearest ? )
64 #! find the nearest of 'next' and 'nearest' to 'oint', and return
65 #! t if the nearest hasn't changed
66 pick >r nearer-segment dup r> = ;
68 : find-nearest-segment ( oint segments -- segment )
69 dup first swap rest-slice rot [ (find-nearest-segment) ] curry
72 : nearest-segment-forward ( segments oint start -- segment )
73 rot dup length swap <slice> find-nearest-segment ;
75 : nearest-segment-backward ( segments oint start -- segment )
76 swapd 1+ 0 spin <slice> <reversed> find-nearest-segment ;
78 : nearest-segment ( segments oint start-segment -- segment )
79 #! find the segment nearest to 'oint', and return it.
80 #! start looking at segment 'start-segment'
82 [ nearest-segment-forward ] 3keep
83 nearest-segment-backward r> nearer-segment ;
85 : get-segment ( segments n -- segment )
86 over sequence-index-range clamp-to-range swap nth ;
88 : next-segment ( segments current-segment -- segment )
89 number>> 1+ get-segment ;
91 : previous-segment ( segments current-segment -- segment )
92 number>> 1- get-segment ;
94 : heading-segment ( segments current-segment heading -- segment )
95 #! the next segment on the given heading
96 over forward>> v. 0 <=> {
97 { +gt+ [ next-segment ] }
98 { +lt+ [ previous-segment ] }
99 { +eq+ [ nip ] } ! current segment
102 :: distance-to-next-segment ( current next location heading -- distance )
103 [let | cf [ current forward>> ] |
104 cf next location>> v. cf location v. - cf heading v. / ] ;
106 :: distance-to-next-segment-area ( current next location heading -- distance )
107 [let | cf [ current forward>> ]
108 h [ next current half-way-between-oints ] |
109 cf h v. cf location v. - cf heading v. / ] ;
111 : vector-to-centre ( seg loc -- v )
112 over location>> swap v- swap forward>> proj-perp ;
114 : distance-from-centre ( seg loc -- distance )
115 vector-to-centre norm ;
117 : wall-normal ( seg oint -- n )
118 location>> vector-to-centre normalize ;
120 : distant ( -- n ) 1000 ;
122 : max-real ( a b -- c )
123 #! sometimes collision-coefficient yields complex roots, so we ignore these (hack)
125 over real? [ max ] [ nip ] if
127 drop dup real? [ drop distant ] unless
130 :: collision-coefficient ( v w r -- c )
134 [let* | a [ v dup v. ]
136 c [ w dup v. r sq - ] |
137 c b a quadratic max-real ]
140 : sideways-heading ( oint segment -- v )
141 [ forward>> ] bi@ proj-perp ;
143 : sideways-relative-location ( oint segment -- loc )
144 [ [ location>> ] bi@ v- ] keep forward>> proj-perp ;
146 : (distance-to-collision) ( oint segment -- distance )
147 [ sideways-heading ] [ sideways-relative-location ]
148 [ nip radius>> ] 2tri collision-coefficient ;
150 : collision-vector ( oint segment -- v )
151 dupd (distance-to-collision) swap forward>> n*v ;
153 : bounce-forward ( segment oint -- )
154 [ wall-normal ] [ forward>> swap reflect ] [ (>>forward) ] tri ;
156 : bounce-left ( segment oint -- )
157 #! must be done after forward
158 [ forward>> vneg ] dip [ left>> swap reflect ]
159 [ forward>> proj-perp normalize ] [ (>>left) ] tri ;
161 : bounce-up ( segment oint -- )
162 #! must be done after forward and left!
163 nip [ forward>> ] [ left>> cross ] [ (>>up) ] tri ;
165 : bounce-off-wall ( oint segment -- )
166 swap [ bounce-forward ] [ bounce-left ] [ bounce-up ] 2tri ;