jort-1.0.0: Objects.hs
module Objects where
import Vectors
import Basics
import Data.List(sort)
import Debug.Trace
newtype ProtoObject = ProtoObject { fromProto :: Int -> Object }
data Object = Object !Int !Shape !Texture deriving Show
object sh tex = ProtoObject (\ id -> Object id sh tex)
--objectTexture (Object _ _ material) = material
data Shape
= Sphere !Vector !Scal -- center, radius
| Plane !Vector !Scal -- normal, distance to origin
| Quadric !Vector !Vector !Scal -- center, director, const
{- Equation of (Quadric c d k) is (norm (x-c) == abs ( d `dotProd` (x-c)) + k)
let e = norm d, then
e = 0 => sphere
0 < e < 1 => ellipsoid
e = 1 => cylinder
e > 1 => hyperboloid (or cone, when k = 0)
-}
| Meta ![MetaPoint] !Scal -- points, threshold
deriving Show
data MetaPoint = MetaPoint !Vector !Scal -- center, strength
deriving Show
eps :: Scal
eps = (1.0e-3)
distance src ray (Object id sh m) = distance' src ray sh
getNormal (Object id sh m) = getNormal' sh
distance' source ray (Sphere center rad) = solution
-- we solve sq t - 2*b*t + * c = 0 (w.r.t. t)
where b = ray `dotProd` (center - source)
c = sqnorm (center - source) - sq rad
d = b * b - c
solution
| d < 0.0 = infinite
| sol1 > 0 = sol1
| sol2 > 0 = sol2
| otherwise = infinite
sol1 = b - sqrt d
sol2 = b + sqrt d
distance' source ray (Plane norm dist) = solution
where solution = if abs v1 > eps && ((v > 0.0) == (v1 > 0.0)) then v / v1 else infinite
v1 = norm `dotProd` ray
v = dist - norm `dotProd` source
distance' source ray (Quadric center dir sqk0) = solution
where
a = 1 - sq (ray .* dir)
b = ray .* ((c0 .* dir) `scale` dir - c0)
c = sqnorm c0 - sqk0 - sq (c0 .* dir)
d = b * b - a * c
sol1 = (b - sqrt d)/a
sol2 = (b + sqrt d)/a
sol = if a > 0 then sol1 else sol2
-- the good solution depends on the concavity/convexy of the curve
solution = if d >= 0 && sol > 0 then sol else infinite
c0 = source - center
distance' source ray (Meta points threshold) = --trace ("Maxs = " ++ show maximums) $
--trace ("Dens = " ++ show (map density maximums)) $
if ubound > 0 then solution else infinite
where ubound = sum [(strength/(c-b*b)) | (b, c, strength) <- pointInfo] - threshold
pointInfo = [(ray .* (center - source),
sqnorm (center - source) + 0.001,
strength) |
MetaPoint center strength <- points]
maximums = [b | (b, _, _) <- pointInfo, b > 0]
density x = sum [(strength/(x*x-2*b*x+c)) | (b, c, strength) <- pointInfo] - threshold
forwardFindSolution (x0:x1:xs)
| density x1 > 0 = dichoFindSolution x0 x1
| otherwise = forwardFindSolution (x1:xs)
forwardFindSolution (x0:[]) = infinite
dichoFindSolution x0 x1
| x1 - x0 < eps = mid
| density mid > 0 = dichoFindSolution x0 mid
| density mid <= 0 = dichoFindSolution mid x1
where mid = (x1 + x0) / 2
solution = forwardFindSolution (0:sort maximums)
sq x = x * x
getNormal' (Sphere center rad) hit = (1.0/rad) `scale` (hit - center)
getNormal' (Plane norm dist) hit = norm
getNormal' (Quadric center dir k) hit = normalized $
v - (c `scale` dir)
where v = hit - center
c = dir `dotProd` v
getNormal' (Meta points threshold) hit =
normalized $ sum [ (strength / sq (sqnorm (hit-center))) `scale`
(hit-center)
| MetaPoint center strength <- points ]