summaryrefslogtreecommitdiff
path: root/testsuite/tests/ghc-regress/programs/galois_raytrace/Geometry.hs
blob: 673c7d4812af514feaa56f993c0530f686418776 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
-- Copyright (c) 2000 Galois Connections, Inc.
-- All rights reserved.  This software is distributed as
-- free software under the license in the file "LICENSE",
-- which is included in the distribution.

module Geometry
    ( Coords
    , Ray
    , Point  -- abstract
    , Vector -- abstract
    , Matrix -- abstract
    , Color  -- abstract
    , Box(..)
    , Radian
    , matrix
    , coord
    , color
    , uncolor
    , xCoord , yCoord , zCoord
    , xComponent , yComponent , zComponent
    , point
    , vector
    , nearV
    , point_to_vector
    , vector_to_point
    , dot
    , cross
    , tangents
    , addVV
    , addPV
    , subVV
    , negV
    , subPP
    , norm
    , normalize
    , dist2
    , sq
    , distFrom0Sq
    , distFrom0
    , multSV
    , multMM
    , transposeM
    , multMV
    , multMP
    , multMQ
    , multMR
    , white
    , black
    , addCC
    , subCC
    , sumCC
    , multCC
    , multSC
    , nearC
    , offsetToPoint
    , epsilon
    , inf
    , nonZero
    , eqEps
    , near
    , clampf
    ) where

import List 

type Coords = (Double,Double,Double)

type Ray = (Point,Vector)    -- origin of ray, and unit vector giving direction

data Point  = P !Double !Double !Double -- implicit extra arg of 1
    deriving (Show)
data Vector = V !Double !Double !Double -- implicit extra arg of 0
    deriving (Show, Eq)
data Matrix = M !Quad   !Quad   !Quad   !Quad
    deriving (Show)

data Color  = C !Double !Double !Double
    deriving (Show, Eq)

data Box = B !Double !Double !Double !Double !Double !Double
    deriving (Show)

data Quad   = Q !Double !Double !Double !Double
    deriving (Show)

type Radian = Double

type Tup4 a = (a,a,a,a)

--{-# INLINE matrix #-}
matrix :: Tup4 (Tup4 Double) -> Matrix
matrix ((m11, m12, m13, m14),
          (m21, m22, m23, m24),
          (m31, m32, m33, m34),
          (m41, m42, m43, m44))
  = M (Q m11 m12 m13 m14)
      (Q m21 m22 m23 m24)
      (Q m31 m32 m33 m34)
      (Q m41 m42 m43 m44)

coord x y z = (x, y, z)

color r g b = C r g b

uncolor (C r g b) = (r,g,b)

{-# INLINE xCoord #-}
xCoord (P x y z) = x
{-# INLINE yCoord #-}
yCoord (P x y z) = y
{-# INLINE zCoord #-}
zCoord (P x y z) = z

{-# INLINE xComponent #-}
xComponent (V x y z) = x
{-# INLINE yComponent #-}
yComponent (V x y z) = y
{-# INLINE zComponent #-}
zComponent (V x y z) = z

point :: Double -> Double -> Double -> Point
point x y z = P x y z

vector :: Double -> Double -> Double -> Vector
vector x y z = V x y z

nearV :: Vector -> Vector -> Bool
nearV (V a b c) (V d e f) = a `near` d && b `near` e && c `near` f

point_to_vector :: Point -> Vector
point_to_vector (P x y z) = V x y z

vector_to_point :: Vector -> Point
vector_to_point (V x y z)  = P x y z 

{-# INLINE vector_to_quad #-}
vector_to_quad :: Vector -> Quad
vector_to_quad (V x y z) = Q x y z 0

{-# INLINE point_to_quad #-}
point_to_quad :: Point -> Quad
point_to_quad (P x y z) = Q x y z 1

{-# INLINE quad_to_point #-}
quad_to_point :: Quad -> Point
quad_to_point (Q x y z _) = P x y z

{-# INLINE quad_to_vector #-}
quad_to_vector :: Quad -> Vector
quad_to_vector (Q x y z _) = V x y z

--{-# INLINE dot #-}
dot :: Vector -> Vector -> Double
dot (V x1 y1 z1) (V x2 y2 z2) = x1 * x2 + y1 * y2 + z1 * z2

cross :: Vector -> Vector -> Vector
cross (V x1 y1 z1) (V x2 y2 z2)
  = V (y1 * z2 - z1 * y2) (z1 * x2 - x1 * z2) (x1 * y2 - y1 * x2)

-- assumption: the input vector is a normal
tangents :: Vector -> (Vector, Vector)
tangents v@(V x y z)
  = (v1, v `cross` v1)
  where v1 | x == 0    = normalize (vector 0 z (-y))
	   | otherwise = normalize (vector (-y) x 0)

{-# INLINE dot4 #-}
dot4 :: Quad -> Quad -> Double
dot4 (Q x1 y1 z1 w1) (Q x2 y2 z2 w2) = x1 * x2 + y1 * y2 + z1 * z2 + w1 * w2

addVV :: Vector -> Vector -> Vector
addVV (V x1 y1 z1) (V x2 y2 z2) 
    = V (x1 + x2) (y1 + y2) (z1 + z2)

addPV :: Point -> Vector -> Point
addPV (P x1 y1 z1) (V x2 y2 z2) 
    = P (x1 + x2) (y1 + y2) (z1 + z2)

subVV :: Vector -> Vector -> Vector
subVV (V x1 y1 z1) (V x2 y2 z2) 
    = V (x1 - x2) (y1 - y2) (z1 - z2)

negV :: Vector -> Vector
negV (V x1 y1 z1) 
    = V (-x1) (-y1) (-z1)

subPP :: Point -> Point -> Vector
subPP (P x1 y1 z1) (P x2 y2 z2) 
    = V (x1 - x2) (y1 - y2) (z1 - z2)

--{-# INLINE norm #-}
norm :: Vector -> Double
norm (V x y z) = sqrt (sq x + sq y + sq z)

--{-# INLINE normalize #-}
-- normalize a vector to a unit vector
normalize :: Vector -> Vector
normalize v@(V x y z)
             | norm /= 0 = multSV (1/norm) v
	     | otherwise = error "normalize empty!"
    where norm = sqrt (sq x + sq y + sq z)

-- This does computes the distance *squared*
dist2 :: Point -> Point -> Double
dist2 us vs = sq x + sq y + sq z
    where
       (V x y z) = subPP us vs

{-# INLINE sq #-}
sq :: Double -> Double
sq d = d * d 

{-# INLINE distFrom0Sq #-}
distFrom0Sq :: Point -> Double  -- Distance of point from origin.
distFrom0Sq (P x y z) = sq x + sq y + sq z

{-# INLINE distFrom0 #-}
distFrom0 :: Point -> Double  -- Distance of point from origin.
distFrom0 p = sqrt (distFrom0Sq p)

--{-# INLINE multSV #-}
multSV :: Double -> Vector -> Vector
multSV k (V x y z) = V (k*x) (k*y) (k*z)

--{-# INLINE multMM #-}
multMM :: Matrix -> Matrix -> Matrix
multMM m1@(M q1 q2 q3 q4) m2
     = M (multMQ m2' q1)
         (multMQ m2' q2)
         (multMQ m2' q3)
         (multMQ m2' q4)
  where
     m2' = transposeM m2

{-# INLINE transposeM #-}     
transposeM :: Matrix -> Matrix
transposeM (M (Q e11  e12  e13  e14)
              (Q e21  e22  e23  e24)
              (Q e31  e32  e33  e34)
              (Q e41  e42  e43  e44)) = (M (Q e11  e21  e31  e41)
                                           (Q e12  e22  e32  e42)
                                           (Q e13  e23  e33  e43)
                                           (Q e14  e24  e34  e44))


--multMM m1 m2 = [map (dot4 row) (transpose m2) | row <- m1]

--{-# INLINE multMV #-}
multMV :: Matrix -> Vector -> Vector
multMV m v = quad_to_vector (multMQ m (vector_to_quad v))

--{-# INLINE multMP #-}
multMP :: Matrix -> Point -> Point
multMP m p = quad_to_point (multMQ m (point_to_quad p))

-- mat vec = map (dot4 vec) mat

{-# INLINE multMQ #-}
multMQ :: Matrix -> Quad -> Quad
multMQ (M q1 q2 q3 q4) q
       = Q (dot4 q q1)
           (dot4 q q2)
           (dot4 q q3)
           (dot4 q q4)

{-# INLINE multMR #-}
multMR :: Matrix -> Ray -> Ray
multMR m (r, v) = (multMP m r, multMV m v)

white :: Color
white = C 1 1 1
black :: Color
black = C 0 0 0

addCC :: Color -> Color -> Color
addCC (C a b c) (C d e f) = C (a+d) (b+e) (c+f)

subCC :: Color -> Color -> Color
subCC (C a b c) (C d e f) = C (a-d) (b-e) (c-f)

sumCC :: [Color] -> Color
sumCC = foldr addCC black

multCC :: Color -> Color -> Color
multCC (C a b c) (C d e f) = C (a*d) (b*e) (c*f)

multSC :: Double -> Color -> Color
multSC k       (C a b c) = C (a*k) (b*k) (c*k)

nearC :: Color -> Color -> Bool
nearC (C a b c) (C d e f) = a `near` d && b `near` e && c `near` f

offsetToPoint :: Ray -> Double -> Point
offsetToPoint (r,v) i = r `addPV` (i `multSV` v)

--

epsilon, inf :: Double      -- aproximate zero and infinity
epsilon = 1.0e-10
inf = 1.0e20

nonZero :: Double -> Double         -- Use before a division. It makes definitions
nonZero x | x > epsilon  = x        -- more complete and I bet the errors that get 
          | x < -epsilon = x        -- introduced will be undetectable if epsilon
          | otherwise    = epsilon  -- is small enough


eqEps x y = abs (x-y) < epsilon
near = eqEps

clampf :: Double -> Double
clampf p | p < 0 = 0
         | p > 1 = 1
         | True  = p