4 import Data.List ( (\\) )
5 import Test.QuickCheck (Arbitrary(..), Gen, Positive(..), choose)
8 import qualified Face (Face(Face, v0, v1, v2, v3))
11 import Tetrahedron hiding (c)
12 import ThreeDimensional
14 data Cube = Cube { h :: Double,
19 tetrahedra_volume :: Double }
23 instance Arbitrary Cube where
25 (Positive h') <- arbitrary :: Gen (Positive Double)
26 i' <- choose (coordmin, coordmax)
27 j' <- choose (coordmin, coordmax)
28 k' <- choose (coordmin, coordmax)
29 fv' <- arbitrary :: Gen FunctionValues
30 (Positive tet_vol) <- arbitrary :: Gen (Positive Double)
31 return (Cube h' i' j' k' fv' tet_vol)
33 coordmin = -268435456 -- -(2^29 / 2)
34 coordmax = 268435456 -- +(2^29 / 2)
37 instance Show Cube where
39 "Cube_" ++ subscript ++ "\n" ++
40 " h: " ++ (show (h c)) ++ "\n" ++
41 " Center: " ++ (show (center c)) ++ "\n" ++
42 " xmin: " ++ (show (xmin c)) ++ "\n" ++
43 " xmax: " ++ (show (xmax c)) ++ "\n" ++
44 " ymin: " ++ (show (ymin c)) ++ "\n" ++
45 " ymax: " ++ (show (ymax c)) ++ "\n" ++
46 " zmin: " ++ (show (zmin c)) ++ "\n" ++
47 " zmax: " ++ (show (zmax c)) ++ "\n" ++
48 " fv: " ++ (show (Cube.fv c)) ++ "\n"
51 (show (i c)) ++ "," ++ (show (j c)) ++ "," ++ (show (k c))
54 -- | Returns an empty 'Cube'.
56 empty_cube = Cube 0 0 0 0 empty_values 0
59 -- | The left-side boundary of the cube. See Sorokina and Zeilfelder,
61 xmin :: Cube -> Double
62 xmin c = (2*i' - 1)*delta / 2
64 i' = fromIntegral (i c) :: Double
67 -- | The right-side boundary of the cube. See Sorokina and Zeilfelder,
69 xmax :: Cube -> Double
70 xmax c = (2*i' + 1)*delta / 2
72 i' = fromIntegral (i c) :: Double
75 -- | The front boundary of the cube. See Sorokina and Zeilfelder,
77 ymin :: Cube -> Double
78 ymin c = (2*j' - 1)*delta / 2
80 j' = fromIntegral (j c) :: Double
83 -- | The back boundary of the cube. See Sorokina and Zeilfelder,
85 ymax :: Cube -> Double
86 ymax c = (2*j' + 1)*delta / 2
88 j' = fromIntegral (j c) :: Double
91 -- | The bottom boundary of the cube. See Sorokina and Zeilfelder,
93 zmin :: Cube -> Double
94 zmin c = (2*k' - 1)*delta / 2
96 k' = fromIntegral (k c) :: Double
99 -- | The top boundary of the cube. See Sorokina and Zeilfelder,
101 zmax :: Cube -> Double
102 zmax c = (2*k' + 1)*delta / 2
104 k' = fromIntegral (k c) :: Double
107 instance ThreeDimensional Cube where
108 -- | The center of Cube_ijk coincides with v_ijk at
109 -- (ih, jh, kh). See Sorokina and Zeilfelder, p. 76.
113 i' = fromIntegral (i c) :: Double
114 j' = fromIntegral (j c) :: Double
115 k' = fromIntegral (k c) :: Double
120 -- | It's easy to tell if a point is within a cube; just make sure
121 -- that it falls on the proper side of each of the cube's faces.
122 contains_point c (x, y, z)
123 | x < (xmin c) = False
124 | x > (xmax c) = False
125 | y < (ymin c) = False
126 | y > (ymax c) = False
127 | z < (zmin c) = False
128 | z > (zmax c) = False
135 -- | The top (in the direction of z) face of the cube.
136 top_face :: Cube -> Face.Face
137 top_face c = Face.Face v0' v1' v2' v3'
140 v0' = (center c) + (delta, -delta, delta)
141 v1' = (center c) + (delta, delta, delta)
142 v2' = (center c) + (-delta, delta, delta)
143 v3' = (center c) + (-delta, -delta, delta)
147 -- | The back (in the direction of x) face of the cube.
148 back_face :: Cube -> Face.Face
149 back_face c = Face.Face v0' v1' v2' v3'
152 v0' = (center c) + (delta, -delta, -delta)
153 v1' = (center c) + (delta, delta, -delta)
154 v2' = (center c) + (delta, delta, delta)
155 v3' = (center c) + (delta, -delta, delta)
158 -- The bottom face (in the direction of -z) of the cube.
159 down_face :: Cube -> Face.Face
160 down_face c = Face.Face v0' v1' v2' v3'
163 v0' = (center c) + (-delta, -delta, -delta)
164 v1' = (center c) + (-delta, delta, -delta)
165 v2' = (center c) + (delta, delta, -delta)
166 v3' = (center c) + (delta, -delta, -delta)
170 -- | The front (in the direction of -x) face of the cube.
171 front_face :: Cube -> Face.Face
172 front_face c = Face.Face v0' v1' v2' v3'
175 v0' = (center c) + (-delta, -delta, delta)
176 v1' = (center c) + (-delta, delta, delta)
177 v2' = (center c) + (-delta, delta, -delta)
178 v3' = (center c) + (-delta, -delta, -delta)
180 -- | The left (in the direction of -y) face of the cube.
181 left_face :: Cube -> Face.Face
182 left_face c = Face.Face v0' v1' v2' v3'
185 v0' = (center c) + (delta, -delta, delta)
186 v1' = (center c) + (-delta, -delta, delta)
187 v2' = (center c) + (-delta, -delta, -delta)
188 v3' = (center c) + (delta, -delta, -delta)
191 -- | The right (in the direction of y) face of the cube.
192 right_face :: Cube -> Face.Face
193 right_face c = Face.Face v0' v1' v2' v3'
196 v0' = (center c) + (-delta, delta, delta)
197 v1' = (center c) + (delta, delta, delta)
198 v2' = (center c) + (delta, delta, -delta)
199 v3' = (center c) + (-delta, delta, -delta)
202 tetrahedron :: Cube -> Int -> Tetrahedron
205 Tetrahedron (Cube.fv c) v0' v1' v2' v3' vol 0
208 v1' = center (front_face c)
209 v2' = Face.v0 (front_face c)
210 v3' = Face.v1 (front_face c)
211 vol = tetrahedra_volume c
214 Tetrahedron fv' v0' v1' v2' v3' vol 1
217 v1' = center (front_face c)
218 v2' = Face.v1 (front_face c)
219 v3' = Face.v2 (front_face c)
220 fv' = rotate ccwx (Cube.fv c)
221 vol = tetrahedra_volume c
224 Tetrahedron fv' v0' v1' v2' v3' vol 2
227 v1' = center (front_face c)
228 v2' = Face.v2 (front_face c)
229 v3' = Face.v3 (front_face c)
230 fv' = rotate ccwx $ rotate ccwx $ Cube.fv c
231 vol = tetrahedra_volume c
234 Tetrahedron fv' v0' v1' v2' v3' vol 3
237 v1' = center (front_face c)
238 v2' = Face.v3 (front_face c)
239 v3' = Face.v0 (front_face c)
240 fv' = rotate cwx (Cube.fv c)
241 vol = tetrahedra_volume c
244 Tetrahedron fv' v0' v1' v2' v3' vol 4
247 v1' = center (top_face c)
248 v2' = Face.v0 (top_face c)
249 v3' = Face.v1 (top_face c)
250 fv' = rotate cwy (Cube.fv c)
251 vol = tetrahedra_volume c
254 Tetrahedron fv' v0' v1' v2' v3' vol 5
257 v1' = center (top_face c)
258 v2' = Face.v1 (top_face c)
259 v3' = Face.v2 (top_face c)
260 fv' = rotate cwy $ rotate cwz $ Tetrahedron.fv (tetrahedron c 0)
261 vol = tetrahedra_volume c
264 Tetrahedron fv' v0' v1' v2' v3' vol 6
267 v1' = center (top_face c)
268 v2' = Face.v2 (top_face c)
269 v3' = Face.v3 (top_face c)
270 fv' = rotate cwy $ rotate cwz
272 $ Tetrahedron.fv (tetrahedron c 0)
273 vol = tetrahedra_volume c
276 Tetrahedron fv' v0' v1' v2' v3' vol 7
279 v1' = center (top_face c)
280 v2' = Face.v3 (top_face c)
281 v3' = Face.v0 (top_face c)
282 fv' = rotate cwy $ rotate ccwz $ Tetrahedron.fv (tetrahedron c 0)
283 vol = tetrahedra_volume c
286 Tetrahedron fv' v0' v1' v2' v3' vol 8
289 v1' = center (back_face c)
290 v2' = Face.v0 (back_face c)
291 v3' = Face.v1 (back_face c)
292 fv' = rotate cwy $ rotate cwy $ Tetrahedron.fv (tetrahedron c 0)
293 vol = tetrahedra_volume c
296 Tetrahedron fv' v0' v1' v2' v3' vol 9
299 v1' = center (back_face c)
300 v2' = Face.v1 (back_face c)
301 v3' = Face.v2 (back_face c)
302 fv' = rotate cwy $ rotate cwy
304 $ Tetrahedron.fv (tetrahedron c 0)
305 vol = tetrahedra_volume c
308 Tetrahedron fv' v0' v1' v2' v3' vol 10
311 v1' = center (back_face c)
312 v2' = Face.v2 (back_face c)
313 v3' = Face.v3 (back_face c)
314 fv' = rotate cwy $ rotate cwy
317 $ Tetrahedron.fv (tetrahedron c 0)
319 vol = tetrahedra_volume c
322 Tetrahedron fv' v0' v1' v2' v3' vol 11
325 v1' = center (back_face c)
326 v2' = Face.v3 (back_face c)
327 v3' = Face.v0 (back_face c)
328 fv' = rotate cwy $ rotate cwy
330 $ Tetrahedron.fv (tetrahedron c 0)
331 vol = tetrahedra_volume c
334 Tetrahedron fv' v0' v1' v2' v3' vol 12
337 v1' = center (down_face c)
338 v2' = Face.v0 (down_face c)
339 v3' = Face.v1 (down_face c)
340 fv' = rotate ccwy (Tetrahedron.fv (tetrahedron c 0))
341 vol = tetrahedra_volume c
344 Tetrahedron fv' v0' v1' v2' v3' vol 13
347 v1' = center (down_face c)
348 v2' = Face.v1 (down_face c)
349 v3' = Face.v2 (down_face c)
350 fv' = rotate ccwy $ rotate ccwz $ Tetrahedron.fv (tetrahedron c 0)
351 vol = tetrahedra_volume c
354 Tetrahedron fv' v0' v1' v2' v3' vol 14
357 v1' = center (down_face c)
358 v2' = Face.v2 (down_face c)
359 v3' = Face.v3 (down_face c)
360 fv' = rotate ccwy $ rotate ccwz
362 $ Tetrahedron.fv (tetrahedron c 0)
363 vol = tetrahedra_volume c
366 Tetrahedron fv' v0' v1' v2' v3' vol 15
369 v1' = center (down_face c)
370 v2' = Face.v3 (down_face c)
371 v3' = Face.v0 (down_face c)
372 fv' = rotate ccwy $ rotate cwz $ Tetrahedron.fv (tetrahedron c 0)
373 vol = tetrahedra_volume c
376 Tetrahedron fv' v0' v1' v2' v3' vol 16
379 v1' = center (right_face c)
380 v2' = Face.v0 (right_face c)
381 v3' = Face.v1 (right_face c)
382 fv' = rotate ccwz (Tetrahedron.fv (tetrahedron c 0))
383 vol = tetrahedra_volume c
386 Tetrahedron fv' v0' v1' v2' v3' vol 17
389 v1' = center (right_face c)
390 v2' = Face.v1 (right_face c)
391 v3' = Face.v2 (right_face c)
392 fv' = rotate ccwz $ rotate cwy $ Tetrahedron.fv (tetrahedron c 0)
393 vol = tetrahedra_volume c
396 Tetrahedron fv' v0' v1' v2' v3' vol 18
399 v1' = center (right_face c)
400 v2' = Face.v2 (right_face c)
401 v3' = Face.v3 (right_face c)
402 fv' = rotate ccwz $ rotate cwy
404 $ Tetrahedron.fv (tetrahedron c 0)
405 vol = tetrahedra_volume c
408 Tetrahedron fv' v0' v1' v2' v3' vol 19
411 v1' = center (right_face c)
412 v2' = Face.v3 (right_face c)
413 v3' = Face.v0 (right_face c)
414 fv' = rotate ccwz $ rotate ccwy
415 $ Tetrahedron.fv (tetrahedron c 0)
416 vol = tetrahedra_volume c
419 Tetrahedron fv' v0' v1' v2' v3' vol 20
422 v1' = center (left_face c)
423 v2' = Face.v0 (left_face c)
424 v3' = Face.v1 (left_face c)
425 fv' = rotate cwz (Tetrahedron.fv (tetrahedron c 0))
426 vol = tetrahedra_volume c
429 Tetrahedron fv' v0' v1' v2' v3' vol 21
432 v1' = center (left_face c)
433 v2' = Face.v1 (left_face c)
434 v3' = Face.v2 (left_face c)
435 fv' = rotate cwz $ rotate ccwy $ Tetrahedron.fv (tetrahedron c 0)
436 vol = tetrahedra_volume c
439 Tetrahedron fv' v0' v1' v2' v3' vol 22
442 v1' = center (left_face c)
443 v2' = Face.v2 (left_face c)
444 v3' = Face.v3 (left_face c)
445 fv' = rotate cwz $ rotate ccwy
447 $ Tetrahedron.fv (tetrahedron c 0)
448 vol = tetrahedra_volume c
451 Tetrahedron fv' v0' v1' v2' v3' vol 23
454 v1' = center (left_face c)
455 v2' = Face.v3 (left_face c)
456 v3' = Face.v0 (left_face c)
457 fv' = rotate cwz $ rotate cwy
458 $ Tetrahedron.fv (tetrahedron c 0)
459 vol = tetrahedra_volume c
461 -- Feels dirty, but whatever.
462 tetrahedron _ _ = error "asked for a nonexistent tetrahedron"
465 tetrahedra :: Cube -> [Tetrahedron]
467 [ tetrahedron c n | n <- [0..23] ]
469 -- | All completely contained in the front half of the cube.
470 front_half_tetrahedra :: Cube -> [Tetrahedron]
471 front_half_tetrahedra c =
472 [ tetrahedron c n | n <- [0,1,2,3,6,12,19,21] ]
474 -- | All tetrahedra completely contained in the top half of the cube.
475 top_half_tetrahedra :: Cube -> [Tetrahedron]
476 top_half_tetrahedra c =
477 [ tetrahedron c n | n <- [4,5,6,7,0,10,16,20] ]
479 -- | All tetrahedra completely contained in the back half of the cube.
480 back_half_tetrahedra :: Cube -> [Tetrahedron]
481 back_half_tetrahedra c =
482 [ tetrahedron c n | n <- [8,9,10,11,4,14,17,23] ]
484 -- | All tetrahedra completely contained in the down half of the cube.
485 down_half_tetrahedra :: Cube -> [Tetrahedron]
486 down_half_tetrahedra c =
487 [ tetrahedron c n | n <- [12,13,14,15,2,8,18,22] ]
489 -- | All tetrahedra completely contained in the right half of the cube.
490 right_half_tetrahedra :: Cube -> [Tetrahedron]
491 right_half_tetrahedra c =
492 [ tetrahedron c n | n <- [16,17,18,19,1,5,9,13] ]
494 -- | All tetrahedra completely contained in the left half of the cube.
495 left_half_tetrahedra :: Cube -> [Tetrahedron]
496 left_half_tetrahedra c =
497 [ tetrahedron c n | n <- [20,21,22,23,3,7,11,15] ]
499 in_top_half :: Cube -> Point -> Bool
500 in_top_half c (_,_,z) =
501 distance_from_top <= distance_from_bottom
503 distance_from_top = abs $ (zmax c) - z
504 distance_from_bottom = abs $ (zmin c) - z
506 in_front_half :: Cube -> Point -> Bool
507 in_front_half c (x,_,_) =
508 distance_from_front <= distance_from_back
510 distance_from_front = abs $ (xmin c) - x
511 distance_from_back = abs $ (xmax c) - x
514 in_left_half :: Cube -> Point -> Bool
515 in_left_half c (_,y,_) =
516 distance_from_left <= distance_from_right
518 distance_from_left = abs $ (ymin c) - y
519 distance_from_right = abs $ (ymax c) - y
522 -- | Takes a 'Cube', and returns the Tetrahedra belonging to it that
523 -- contain the given 'Point'. This should be faster than checking
524 -- every tetrahedron individually, since we determine which half
525 -- (hemisphere?) of the cube the point lies in three times: once in
526 -- each dimension. This allows us to eliminate non-candidates
529 -- This can throw an exception, but the use of 'head' might
530 -- save us some unnecessary computations.
532 find_containing_tetrahedron :: Cube -> Point -> Tetrahedron
533 find_containing_tetrahedron c p =
534 head containing_tetrahedra
536 candidates = tetrahedra c
538 if (in_front_half c p) then
539 back_half_tetrahedra c
541 front_half_tetrahedra c
543 candidates_x = candidates \\ non_candidates_x
546 if (in_left_half c p) then
547 right_half_tetrahedra c
549 left_half_tetrahedra c
551 candidates_xy = candidates_x \\ non_candidates_y
554 if (in_top_half c p) then
555 down_half_tetrahedra c
557 top_half_tetrahedra c
559 candidates_xyz = candidates_xy \\ non_candidates_z
561 contains_our_point = flip contains_point p
562 containing_tetrahedra = filter contains_our_point candidates_xyz