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