Skip to content

Commit

Permalink
return list of traces
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffreyrosenbluth committed Jan 2, 2014
1 parent 68d3f38 commit 6d60fce
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 11 deletions.
3 changes: 3 additions & 0 deletions src/Diagrams/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ module Diagrams.Core
, Traced(..)
, traceV, traceP
, maxTraceV, maxTraceP
, getRayTrace
, rayTraceV, rayTraceP
, maxRayTraceV, maxRayTraceP

-- * Things with local origins

Expand Down
78 changes: 67 additions & 11 deletions src/Diagrams/Core/Trace.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ module Diagrams.Core.Trace

, traceV, traceP
, maxTraceV, maxTraceP
, getRayTrace
, rayTraceV, rayTraceP
, maxRayTraceV, maxRayTraceP

) where

import Control.Applicative
import Control.Lens
import Data.List (insert)
import qualified Data.Map as M
import Data.Semigroup
import qualified Data.Set as S
Expand Down Expand Up @@ -78,27 +82,32 @@ import Diagrams.Core.V
-- scalar is @s@, the distance from the base point to the
-- intersection is given by @s * magnitude v@.

newtype Trace v = Trace { appTrace :: Point v -> v -> PosInf (Scalar v) }
newtype Trace v = Trace { appTrace :: Point v -> v -> [PosInf (Scalar v)] }

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 2, 2014

Member

We should remove PosInf. We used to use +infinity to indicate no intersections; that should now be indicated by the empty list.


instance (Scalar v ~ s, Scalar v' ~ s', s ~ s') =>
Wrapped
(Point v -> v -> PosInf s)
(Point v' -> v' -> PosInf s')
(Point v -> v -> [PosInf s])
(Point v' -> v' -> [PosInf s'])
(Trace v) (Trace v')
where wrapped = iso Trace appTrace

mkTrace :: (Point v -> v -> PosInf (Scalar v)) -> Trace v
mkTrace :: (Point v -> v -> [PosInf (Scalar v)]) -> Trace v
mkTrace = Trace

-- | Traces form a semigroup with pointwise minimum as composition.
-- Hence, if @t1@ is the trace for diagram @d1@, and
-- @e2@ is the trace for @d2@, then @e1 \`mappend\` e2@
-- is the trace for @d1 \`atop\` d2@.
deriving instance Ord (Scalar v) => Semigroup (Trace v)
instance Ord (Scalar v) => Semigroup (Trace v) where
ts1 <> ts2 = mkTrace tr
where
tr p v = foldr insert (appTrace ts1 p v) (appTrace ts2 p v)

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 2, 2014

Member

This is an inefficient implementation (O(n^2) rather than O(n)) and will not play nicely with calls to head and so on. We should require as an invariant that both lists are sorted, then we can write a merge operation which walks through both lists in parallel.

In fact, perhaps we should make a SortedList newtype and give it Semigroup and Monoid instances.


-- | The identity for the 'Monoid' instance is the constantly infinite
-- trace.
deriving instance Ord (Scalar v) => Monoid (Trace v)
instance Ord (Scalar v) => Monoid (Trace v) where
mappend = (<>)
mempty = mkTrace $ \_ _ -> [mempty]

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 2, 2014

Member

Should be []


type instance V (Trace v) = v

Expand Down Expand Up @@ -158,16 +167,16 @@ instance (Traced b) => Traced (S.Set b) where
------------------------------------------------------------

-- | Compute the vector from the given point to the boundary of the
-- given object in the given direction, or @Nothing@ if there is no
-- intersection.
-- given object in either the given direction or the opposite direction.
-- Return @Nothing@ if there is no intersection.
traceV :: Traced a => Point (V a) -> V a -> a -> Maybe (V a)
traceV p v a = case ((getTrace a)^.unwrapping Trace) p v of
traceV p v a = case head $ ((getTrace a)^.unwrapping Trace) p v of
Finite s -> Just (s *^ v)
Infinity -> Nothing

-- | Given a base point and direction, compute the closest point on
-- the boundary of the given object, or @Nothing@ if there is no
-- intersection in the given direction.
-- the boundary of the given object in the direction or its opposite.
-- Return @Nothing@ if there is no intersection in either direction.
traceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))
traceP p v a = (p .+^) <$> traceV p v a

Expand All @@ -180,3 +189,50 @@ maxTraceV p = traceV p . negateV
-- instead of the closest.
maxTraceP :: Traced a => Point (V a) -> V a -> a -> Maybe (Point (V a))
maxTraceP p v a = (p .+^) <$> maxTraceV p v a

-- | Get the trace of an object along in the direction of the given vector
-- but not in the opposite direction like `getTrace`. I.e. only return
-- positive traces.
getRayTrace :: (Traced a, Num (Scalar (V a))) => a -> Trace (V a)
getRayTrace a = Trace tr
where
scalars [] = []
scalars (Infinity : xs) = scalars xs
scalars (Finite x : xs) = x : scalars xs
tr p v = let
ts = ((getTrace a)^.unwrapping Trace) p v
ps = filter (>= 0) (scalars ts)
in case ps of
[] -> [Infinity]
qs -> map Finite qs

-- | Compute the vector from the given point to the boundary of the
-- given object in the given direction, or @Nothing@ if there is no
-- intersection. Only positive scale muliples of the direction are returned
rayTraceV :: (Traced a, Num (Scalar (V a)))
=> Point (V a) -> V a -> a -> Maybe (V a)
rayTraceV p v a = case head $ ((getRayTrace a)^.unwrapping Trace) p v of
Finite s -> Just (s *^ v)
Infinity -> Nothing

-- | Given a base point and direction, compute the closest point on
-- the boundary of the given object, or @Nothing@ if there is no
-- intersection in the given direction.
rayTraceP :: (Traced a, Num (Scalar (V a)))
=> Point (V a) -> V a -> a -> Maybe (Point (V a))
rayTraceP p v a = (p .+^) <$> rayTraceV p v a

-- | Like 'rayTraceV', but computes a vector to the *furthest* point on
-- the boundary instead of the closest.
maxRayTraceV :: (Traced a, Num (Scalar (V a)))
=> Point (V a) -> V a -> a -> Maybe (V a)
maxRayTraceV p v a =
case last $ ((getRayTrace a)^.unwrapping Trace) p v of
Finite s -> Just (s *^ v)
Infinity -> Nothing

-- | Like 'rayTraceP', but computes the *furthest* point on the boundary
-- instead of the closest.
maxRayTraceP :: (Traced a, Num (Scalar (V a)))
=> Point (V a) -> V a -> a -> Maybe (Point (V a))
maxRayTraceP p v a = (p .+^) <$> maxRayTraceV p v a

0 comments on commit 6d60fce

Please sign in to comment.