36
36
< body >
37
37
<!-- <pre></pre> -->
38
38
< canvas > </ canvas >
39
- < script src ="code/bundle.js "> </ script >
39
+ <!-- <script src="code/bundle.js"></script> -->
40
+
41
+ < script >
42
+
43
+ // Find intersection of RAY & SEGMENT
44
+ function getIntersection ( ray , segment ) {
45
+ // RAY in parametric: Point + Delta*T1
46
+ var r_px = ray . a . x ;
47
+ var r_py = ray . a . y ;
48
+ var r_dx = ray . b . x - ray . a . x ;
49
+ var r_dy = ray . b . y - ray . a . y ;
50
+
51
+ // SEGMENT in parametric: Point + Delta*T2
52
+ var s_px = segment . a . x ;
53
+ var s_py = segment . a . y ;
54
+ var s_dx = segment . b . x - segment . a . x ;
55
+ var s_dy = segment . b . y - segment . a . y ;
56
+
57
+ // Are they parallel? If so, no intersect
58
+ var r_mag = Math . sqrt ( r_dx * r_dx + r_dy * r_dy ) ;
59
+ var s_mag = Math . sqrt ( s_dx * s_dx + s_dy * s_dy ) ;
60
+ if ( r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag ) {
61
+ // Unit vectors are the same.
62
+ return null ;
63
+ }
64
+
65
+ // SOLVE FOR T1 & T2
66
+ // r_px+r_dx*T1 = s_px+s_dx*T2 && r_py+r_dy*T1 = s_py+s_dy*T2
67
+ // ==> T1 = (s_px+s_dx*T2-r_px)/r_dx = (s_py+s_dy*T2-r_py)/r_dy
68
+ // ==> s_px*r_dy + s_dx*T2*r_dy - r_px*r_dy = s_py*r_dx + s_dy*T2*r_dx - r_py*r_dx
69
+ // ==> T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx)
70
+ var T2 = ( r_dx * ( s_py - r_py ) + r_dy * ( r_px - s_px ) ) / ( s_dx * r_dy - s_dy * r_dx ) ;
71
+ var T1 = ( s_px + s_dx * T2 - r_px ) / r_dx ;
72
+
73
+ // Must be within parametic whatevers for RAY/SEGMENT
74
+ if ( T1 < 0 ) return null ;
75
+ if ( T2 < 0 || T2 > 1 ) return null ;
76
+
77
+ // Return the POINT OF INTERSECTION
78
+ return {
79
+ x : r_px + r_dx * T1 ,
80
+ y : r_py + r_dy * T1 ,
81
+ param : T1
82
+ } ;
83
+ }
84
+
85
+ function getSightPolygon ( sightX , sightY ) {
86
+ // Get all unique points
87
+ var points = ( function ( segments ) {
88
+ var a = [ ] ;
89
+ segments . forEach ( function ( seg ) {
90
+ a . push ( seg . a , seg . b ) ;
91
+ } ) ;
92
+ return a ;
93
+ } ) ( segments ) ;
94
+
95
+ var uniquePoints = ( function ( points ) {
96
+ var set = { } ;
97
+ return points . filter ( function ( p ) {
98
+ var key = p . x + "," + p . y ;
99
+ if ( key in set ) {
100
+ return false ;
101
+ } else {
102
+ set [ key ] = true ;
103
+ return true ;
104
+ }
105
+ } ) ;
106
+ } ) ( points ) ;
107
+
108
+ // Get all angles
109
+ var uniqueAngles = [ ] ;
110
+ for ( var j = 0 ; j < uniquePoints . length ; j ++ ) {
111
+ var uniquePoint = uniquePoints [ j ] ;
112
+ var angle = Math . atan2 ( uniquePoint . y - sightY , uniquePoint . x - sightX ) ;
113
+ uniquePoint . angle = angle ;
114
+ uniqueAngles . push ( angle - 0.00001 , angle , angle + 0.00001 ) ;
115
+ }
116
+
117
+ // RAYS IN ALL DIRECTIONS
118
+ var intersects = [ ] ;
119
+ for ( var j = 0 ; j < uniqueAngles . length ; j ++ ) {
120
+ var angle = uniqueAngles [ j ] ;
121
+ // Calculate dx & dy from angle
122
+ var dx = Math . cos ( angle ) ;
123
+ var dy = Math . sin ( angle ) ;
124
+
125
+ // Ray from light coord to point coord
126
+ var ray = {
127
+ a : { x : sightX , y : sightY } ,
128
+ b : { x : sightX + dx , y : sightY + dy }
129
+ } ;
130
+
131
+ // Find CLOSEST intersection
132
+ var closestIntersect = null ;
133
+ for ( var i = 0 ; i < segments . length ; i ++ ) {
134
+ var intersect = getIntersection ( ray , segments [ i ] ) ;
135
+ if ( ! intersect ) continue ;
136
+
137
+ // param (aka distance)
138
+ if ( ! closestIntersect || intersect . param < closestIntersect . param ) {
139
+ closestIntersect = intersect ;
140
+ }
141
+ }
142
+
143
+ // Intersect angle
144
+ if ( ! closestIntersect ) continue ;
145
+ closestIntersect . angle = angle ;
146
+
147
+ // Add to list of intersects
148
+ intersects . push ( closestIntersect ) ;
149
+ }
150
+
151
+ // Sort intersects by angle
152
+ intersects = intersects . sort ( function ( a , b ) {
153
+ return a . angle - b . angle ;
154
+ } ) ;
155
+
156
+ // Polygon is intersects, in order of angle
157
+ return intersects ;
158
+ }
159
+
160
+ ///////////////////////////////////////////////////////
161
+ // DRAWING
162
+ var canvas = document . querySelector ( "canvas" ) ;
163
+ canvas . width = window . innerWidth ;
164
+ canvas . height = window . innerHeight ;
165
+
166
+ var ctx = canvas . getContext ( "2d" ) ;
167
+
168
+ function draw ( ) {
169
+ // Clear canvas
170
+ ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
171
+
172
+ ctx . fillStyle = '#000' ;
173
+ ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
174
+
175
+ // Draw segments
176
+ ctx . strokeStyle = "#999" ;
177
+ for ( var i = 0 ; i < segments . length ; i ++ ) {
178
+ var seg = segments [ i ] ;
179
+ ctx . beginPath ( ) ;
180
+ ctx . moveTo ( seg . a . x , seg . a . y ) ;
181
+ ctx . lineTo ( seg . b . x , seg . b . y ) ;
182
+ ctx . stroke ( ) ;
183
+ }
184
+
185
+ var lightsCount = 5 ;
186
+
187
+
188
+ performance . mark ( 'getSightPolygonStart' ) ;
189
+
190
+ // Sight Polygons
191
+ var fuzzyRadius = 10 ;
192
+ var polygons = [ getSightPolygon ( Mouse . x , Mouse . y ) ] ;
193
+ for ( var angle = 0 ; angle < Math . PI * 2 ; angle += ( Math . PI * 2 ) / lightsCount ) {
194
+ var dx = Math . cos ( angle ) * fuzzyRadius ;
195
+ var dy = Math . sin ( angle ) * fuzzyRadius ;
196
+ polygons . push ( getSightPolygon ( Mouse . x + dx , Mouse . y + dy ) ) ;
197
+ } ;
198
+
199
+ performance . mark ( 'getSightPolygonEnd' ) ;
200
+ performance . measure ( 'getSightPolygon' , 'getSightPolygonStart' , 'getSightPolygonEnd' ) ;
201
+
202
+
203
+ // DRAW AS A GIANT POLYGON
204
+ for ( var i = 1 ; i < polygons . length ; i ++ ) {
205
+ drawPolygon ( polygons [ i ] , ctx , `rgba(255, 255, 255, ${ 1 / lightsCount } )` ) ;
206
+ }
207
+ drawPolygon ( polygons [ 0 ] , ctx , "#fff" ) ;
208
+
209
+
210
+ // Draw red dots
211
+ ctx . fillStyle = "#dd3838" ;
212
+ ctx . beginPath ( ) ;
213
+ ctx . arc ( Mouse . x , Mouse . y , 2 , 0 , 2 * Math . PI , false ) ;
214
+ ctx . fill ( ) ;
215
+ for ( var angle = 0 ; angle < Math . PI * 2 ; angle += ( Math . PI * 2 ) / lightsCount ) {
216
+ var dx = Math . cos ( angle ) * fuzzyRadius ;
217
+ var dy = Math . sin ( angle ) * fuzzyRadius ;
218
+ ctx . beginPath ( ) ;
219
+ ctx . arc ( Mouse . x + dx , Mouse . y + dy , 2 , 0 , 2 * Math . PI , false ) ;
220
+ ctx . fill ( ) ;
221
+ }
222
+ }
223
+
224
+ function drawPolygon ( polygon , ctx , fillStyle ) {
225
+ ctx . fillStyle = fillStyle ;
226
+ ctx . beginPath ( ) ;
227
+ ctx . moveTo ( polygon [ 0 ] . x , polygon [ 0 ] . y ) ;
228
+ for ( var i = 1 ; i < polygon . length ; i ++ ) {
229
+ var intersect = polygon [ i ] ;
230
+ ctx . lineTo ( intersect . x , intersect . y ) ;
231
+ }
232
+ ctx . fill ( ) ;
233
+ }
234
+
235
+ // LINE SEGMENTS
236
+ var segments = [
237
+ // Border
238
+ { a : { x : 0 , y : 0 } , b : { x : 640 , y : 0 } } ,
239
+ { a : { x : 640 , y : 0 } , b : { x : 640 , y : 360 } } ,
240
+ { a : { x : 640 , y : 360 } , b : { x : 0 , y : 360 } } ,
241
+ { a : { x : 0 , y : 360 } , b : { x : 0 , y : 0 } } ,
242
+ // Polygon #1
243
+ { a : { x : 100 , y : 150 } , b : { x : 120 , y : 50 } } ,
244
+ { a : { x : 120 , y : 50 } , b : { x : 200 , y : 80 } } ,
245
+ { a : { x : 200 , y : 80 } , b : { x : 140 , y : 210 } } ,
246
+ { a : { x : 140 , y : 210 } , b : { x : 100 , y : 150 } } ,
247
+ // Polygon #2
248
+ { a : { x : 100 , y : 200 } , b : { x : 120 , y : 250 } } ,
249
+ { a : { x : 120 , y : 250 } , b : { x : 60 , y : 300 } } ,
250
+ { a : { x : 60 , y : 300 } , b : { x : 100 , y : 200 } } ,
251
+ // Polygon #3
252
+ { a : { x : 200 , y : 260 } , b : { x : 220 , y : 150 } } ,
253
+ { a : { x : 220 , y : 150 } , b : { x : 300 , y : 200 } } ,
254
+ { a : { x : 300 , y : 200 } , b : { x : 350 , y : 320 } } ,
255
+ { a : { x : 350 , y : 320 } , b : { x : 200 , y : 260 } } ,
256
+ // Polygon #4
257
+ { a : { x : 340 , y : 60 } , b : { x : 360 , y : 40 } } ,
258
+ { a : { x : 360 , y : 40 } , b : { x : 370 , y : 70 } } ,
259
+ { a : { x : 370 , y : 70 } , b : { x : 340 , y : 60 } } ,
260
+ // Polygon #5
261
+ { a : { x : 450 , y : 190 } , b : { x : 560 , y : 170 } } ,
262
+ { a : { x : 560 , y : 170 } , b : { x : 540 , y : 270 } } ,
263
+ { a : { x : 540 , y : 270 } , b : { x : 430 , y : 290 } } ,
264
+ { a : { x : 430 , y : 290 } , b : { x : 450 , y : 190 } } ,
265
+ // Polygon #6
266
+ { a : { x : 400 , y : 95 } , b : { x : 580 , y : 50 } } ,
267
+ { a : { x : 580 , y : 50 } , b : { x : 480 , y : 150 } } ,
268
+ { a : { x : 480 , y : 150 } , b : { x : 400 , y : 95 } }
269
+ ] ;
270
+ // DRAW LOOP
271
+
272
+ var updateCanvas = true ;
273
+
274
+ function drawLoop ( ) {
275
+ requestAnimationFrame ( drawLoop ) ;
276
+ if ( updateCanvas ) {
277
+ draw ( ) ;
278
+ updateCanvas = false ;
279
+ }
280
+ }
281
+ window . onload = function ( ) {
282
+ drawLoop ( ) ;
283
+ } ;
284
+ // MOUSE
285
+ var Mouse = {
286
+ x : canvas . width / 2 ,
287
+ y : canvas . height / 2
288
+ } ;
289
+ canvas . onmousemove = function ( event ) {
290
+ Mouse . x = event . clientX ;
291
+ Mouse . y = event . clientY ;
292
+ updateCanvas = true ;
293
+ } ;
294
+
295
+ </ script >
40
296
</ body >
41
297
42
298
</ html >
0 commit comments