]> gitweb.michael.orlitzky.com - spline3.git/blob - src/Tetrahedron.hs
Use pattern matching in the 'center' function. Might speed things up?
[spline3.git] / src / Tetrahedron.hs
1 module Tetrahedron
2 where
3
4 import Numeric.LinearAlgebra hiding (i, scale)
5 import Prelude hiding (LT)
6 import Test.QuickCheck (Arbitrary(..), Gen, choose)
7
8 import Cardinal
9 import Comparisons (nearly_ge)
10 import FunctionValues
11 import Misc (factorial)
12 import Point
13 import RealFunction
14 import ThreeDimensional
15
16 data Tetrahedron =
17 Tetrahedron { fv :: FunctionValues,
18 v0 :: Point,
19 v1 :: Point,
20 v2 :: Point,
21 v3 :: Point,
22 precomputed_volume :: Double,
23
24 -- | Between 0 and 23; used to quickly determine which
25 -- tetrahedron I am in the parent 'Cube' without
26 -- having to compare them all.
27 number :: Int
28 }
29 deriving (Eq)
30
31
32 instance Arbitrary Tetrahedron where
33 arbitrary = do
34 rnd_v0 <- arbitrary :: Gen Point
35 rnd_v1 <- arbitrary :: Gen Point
36 rnd_v2 <- arbitrary :: Gen Point
37 rnd_v3 <- arbitrary :: Gen Point
38 rnd_fv <- arbitrary :: Gen FunctionValues
39 rnd_no <- choose (0,23)
40
41 -- We can't assign an incorrect precomputed volume,
42 -- so we have to calculate the correct one here.
43 let t' = Tetrahedron rnd_fv rnd_v0 rnd_v1 rnd_v2 rnd_v3 0 rnd_no
44 let vol = volume t'
45 return (Tetrahedron rnd_fv rnd_v0 rnd_v1 rnd_v2 rnd_v3 vol rnd_no)
46
47
48 instance Show Tetrahedron where
49 show t = "Tetrahedron:\n" ++
50 " no: " ++ (show (number t)) ++ "\n" ++
51 " fv: " ++ (show (fv t)) ++ "\n" ++
52 " v0: " ++ (show (v0 t)) ++ "\n" ++
53 " v1: " ++ (show (v1 t)) ++ "\n" ++
54 " v2: " ++ (show (v2 t)) ++ "\n" ++
55 " v3: " ++ (show (v3 t)) ++ "\n"
56
57
58 instance ThreeDimensional Tetrahedron where
59 center (Tetrahedron _ v0' v1' v2' v3' _ _) =
60 (v0' + v1' + v2' + v3') `scale` (1/4)
61
62 contains_point t p =
63 b0_unscaled `nearly_ge` 0 &&
64 b1_unscaled `nearly_ge` 0 &&
65 b2_unscaled `nearly_ge` 0 &&
66 b3_unscaled `nearly_ge` 0
67 where
68 -- Drop the useless division and volume calculation that we
69 -- would do if we used the regular b0,..b3 functions.
70 b0_unscaled :: Double
71 b0_unscaled = volume inner_tetrahedron
72 where inner_tetrahedron = t { v0 = p }
73
74 b1_unscaled :: Double
75 b1_unscaled = volume inner_tetrahedron
76 where inner_tetrahedron = t { v1 = p }
77
78 b2_unscaled :: Double
79 b2_unscaled = volume inner_tetrahedron
80 where inner_tetrahedron = t { v2 = p }
81
82 b3_unscaled :: Double
83 b3_unscaled = volume inner_tetrahedron
84 where inner_tetrahedron = t { v3 = p }
85
86
87 polynomial :: Tetrahedron -> (RealFunction Point)
88 polynomial t =
89 sum [ (c t i j k l) `cmult` (beta t i j k l) | i <- [0..3],
90 j <- [0..3],
91 k <- [0..3],
92 l <- [0..3],
93 i + j + k + l == 3]
94
95
96 -- | Returns the domain point of t with indices i,j,k,l.
97 -- Simply an alias for the domain_point function.
98 xi :: Tetrahedron -> Int -> Int -> Int -> Int -> Point
99 xi = domain_point
100
101 -- | Returns the domain point of t with indices i,j,k,l.
102 domain_point :: Tetrahedron -> Int -> Int -> Int -> Int -> Point
103 domain_point t i j k l
104 | i + j + k + l == 3 = weighted_sum `scale` (1/3)
105 | otherwise = error "domain point index out of bounds"
106 where
107 v0' = (v0 t) `scale` (fromIntegral i)
108 v1' = (v1 t) `scale` (fromIntegral j)
109 v2' = (v2 t) `scale` (fromIntegral k)
110 v3' = (v3 t) `scale` (fromIntegral l)
111 weighted_sum = v0' + v1' + v2' + v3'
112
113
114 -- | The Bernstein polynomial on t with indices i,j,k,l. Denoted by a
115 -- capital 'B' in the Sorokina/Zeilfelder paper.
116 beta :: Tetrahedron -> Int -> Int -> Int -> Int -> (RealFunction Point)
117 beta t i j k l
118 | (i + j + k + l == 3) =
119 coefficient `cmult` (b0_term * b1_term * b2_term * b3_term)
120 | otherwise = error "basis function index out of bounds"
121 where
122 denominator = (factorial i)*(factorial j)*(factorial k)*(factorial l)
123 coefficient = 6 / (fromIntegral denominator)
124 b0_term = (b0 t) `fexp` i
125 b1_term = (b1 t) `fexp` j
126 b2_term = (b2 t) `fexp` k
127 b3_term = (b3 t) `fexp` l
128
129
130 -- | The coefficient function. c t i j k l returns the coefficient
131 -- c_ijkl with respect to the tetrahedron t. The definition uses
132 -- pattern matching to mimic the definitions given in Sorokina and
133 -- Zeilfelder, pp. 84-86. If incorrect indices are supplied, the
134 -- function will simply error.
135 c :: Tetrahedron -> Int -> Int -> Int -> Int -> Double
136 c t 0 0 3 0 = eval (fv t) $
137 (1/8) * (I + F + L + T + LT + FL + FT + FLT)
138
139 c t 0 0 0 3 = eval (fv t) $
140 (1/8) * (I + F + R + T + RT + FR + FT + FRT)
141
142 c t 0 0 2 1 = eval (fv t) $
143 (5/24)*(I + F + T + FT) +
144 (1/24)*(L + FL + LT + FLT)
145
146 c t 0 0 1 2 = eval (fv t) $
147 (5/24)*(I + F + T + FT) +
148 (1/24)*(R + FR + RT + FRT)
149
150 c t 0 1 2 0 = eval (fv t) $
151 (5/24)*(I + F) +
152 (1/8)*(L + T + FL + FT) +
153 (1/24)*(LT + FLT)
154
155 c t 0 1 0 2 = eval (fv t) $
156 (5/24)*(I + F) +
157 (1/8)*(R + T + FR + FT) +
158 (1/24)*(RT + FRT)
159
160 c t 0 1 1 1 = eval (fv t) $
161 (13/48)*(I + F) +
162 (7/48)*(T + FT) +
163 (1/32)*(L + R + FL + FR) +
164 (1/96)*(LT + RT + FLT + FRT)
165
166 c t 0 2 1 0 = eval (fv t) $
167 (13/48)*(I + F) +
168 (17/192)*(L + T + FL + FT) +
169 (1/96)*(LT + FLT) +
170 (1/64)*(R + D + FR + FD) +
171 (1/192)*(RT + LD + FRT + FLD)
172
173 c t 0 2 0 1 = eval (fv t) $
174 (13/48)*(I + F) +
175 (17/192)*(R + T + FR + FT) +
176 (1/96)*(RT + FRT) +
177 (1/64)*(L + D + FL + FD) +
178 (1/192)*(RD + LT + FLT + FRD)
179
180 c t 0 3 0 0 = eval (fv t) $
181 (13/48)*(I + F) +
182 (5/96)*(L + R + T + D + FL + FR + FT + FD) +
183 (1/192)*(RT + RD + LT + LD + FRT + FRD + FLT + FLD)
184
185 c t 1 0 2 0 = eval (fv t) $
186 (1/4)*I +
187 (1/6)*(F + L + T) +
188 (1/12)*(LT + FL + FT)
189
190 c t 1 0 0 2 = eval (fv t) $
191 (1/4)*I +
192 (1/6)*(F + R + T) +
193 (1/12)*(RT + FR + FT)
194
195 c t 1 0 1 1 = eval (fv t) $
196 (1/3)*I +
197 (5/24)*(F + T) +
198 (1/12)*FT +
199 (1/24)*(L + R) +
200 (1/48)*(LT + RT + FL + FR)
201
202 c t 1 1 1 0 = eval (fv t) $
203 (1/3)*I +
204 (5/24)*F +
205 (1/8)*(L + T) +
206 (5/96)*(FL + FT) +
207 (1/48)*(D + R + LT) +
208 (1/96)*(FD + LD + RT + FR)
209
210 c t 1 1 0 1 = eval (fv t) $
211 (1/3)*I +
212 (5/24)*F +
213 (1/8)*(R + T) +
214 (5/96)*(FR + FT) +
215 (1/48)*(D + L + RT) +
216 (1/96)*(FD + LT + RD + FL)
217
218 c t 1 2 0 0 = eval (fv t) $
219 (1/3)*I +
220 (5/24)*F +
221 (7/96)*(L + R + T + D) +
222 (1/32)*(FL + FR + FT + FD) +
223 (1/96)*(RT + RD + LT + LD)
224
225 c t 2 0 1 0 = eval (fv t) $
226 (3/8)*I +
227 (7/48)*(F + T + L) +
228 (1/48)*(R + D + B + LT + FL + FT) +
229 (1/96)*(RT + BT + FR + FD + LD + BL)
230
231 c t 2 0 0 1 = eval (fv t) $
232 (3/8)*I +
233 (7/48)*(F + T + R) +
234 (1/48)*(L + D + B + RT + FR + FT) +
235 (1/96)*(LT + BT + FL + FD + RD + BR)
236
237 c t 2 1 0 0 = eval (fv t) $
238 (3/8)*I +
239 (1/12)*(T + R + L + D) +
240 (1/64)*(FT + FR + FL + FD) +
241 (7/48)*F +
242 (1/48)*B +
243 (1/96)*(RT + LD + LT + RD) +
244 (1/192)*(BT + BR + BL + BD)
245
246 c t 3 0 0 0 = eval (fv t) $
247 (3/8)*I +
248 (1/12)*(T + F + L + R + D + B) +
249 (1/96)*(LT + FL + FT + RT + BT + FR) +
250 (1/96)*(FD + LD + BD + BR + RD + BL)
251
252 c _ _ _ _ _ = error "coefficient index out of bounds"
253
254
255
256 -- | The matrix used in the tetrahedron volume calculation as given in
257 -- Lai & Schumaker, Definition 15.4, page 436.
258 vol_matrix :: Tetrahedron -> Matrix Double
259 vol_matrix t = (4><4)
260 [1, 1, 1, 1,
261 x1, x2, x3, x4,
262 y1, y2, y3, y4,
263 z1, z2, z3, z4 ]
264 where
265 (x1, y1, z1) = v0 t
266 (x2, y2, z2) = v1 t
267 (x3, y3, z3) = v2 t
268 (x4, y4, z4) = v3 t
269
270 -- | Computed using the formula from Lai & Schumaker, Definition 15.4,
271 -- page 436.
272 volume :: Tetrahedron -> Double
273 volume t
274 | (v0 t) == (v1 t) = 0
275 | (v0 t) == (v2 t) = 0
276 | (v0 t) == (v3 t) = 0
277 | (v1 t) == (v2 t) = 0
278 | (v1 t) == (v3 t) = 0
279 | (v2 t) == (v3 t) = 0
280 | otherwise = (1/6)*(det (vol_matrix t))
281
282
283 -- | The barycentric coordinates of a point with respect to v0.
284 b0 :: Tetrahedron -> (RealFunction Point)
285 b0 t point = (volume inner_tetrahedron) / (precomputed_volume t)
286 where
287 inner_tetrahedron = t { v0 = point }
288
289
290 -- | The barycentric coordinates of a point with respect to v1.
291 b1 :: Tetrahedron -> (RealFunction Point)
292 b1 t point = (volume inner_tetrahedron) / (precomputed_volume t)
293 where
294 inner_tetrahedron = t { v1 = point }
295
296
297 -- | The barycentric coordinates of a point with respect to v2.
298 b2 :: Tetrahedron -> (RealFunction Point)
299 b2 t point = (volume inner_tetrahedron) / (precomputed_volume t)
300 where
301 inner_tetrahedron = t { v2 = point }
302
303
304 -- | The barycentric coordinates of a point with respect to v3.
305 b3 :: Tetrahedron -> (RealFunction Point)
306 b3 t point = (volume inner_tetrahedron) / (precomputed_volume t)
307 where
308 inner_tetrahedron = t { v3 = point }