Skip to content

Commit

Permalink
SortedList
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffreyrosenbluth committed Jan 3, 2014
1 parent 6d60fce commit be67bc1
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/Diagrams/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ module Diagrams.Core
-- * Traces

, Trace(Trace)
, SortedList(SortedList)
, appTrace, mkTrace
, Traced(..)
, traceV, traceP
Expand Down
90 changes: 55 additions & 35 deletions src/Diagrams/Core/Trace.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
-----------------------------------------------------------------------------

module Diagrams.Core.Trace
( -- * Traces
Trace(Trace)
( -- * SortedList
SortedList(SortedList)

-- * Traces
, Trace(Trace)

, appTrace
, mkTrace
Expand All @@ -47,20 +50,40 @@ module Diagrams.Core.Trace

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

import Data.AffineSpace
import Data.Monoid.Inf
import Data.VectorSpace

import Diagrams.Core.HasOrigin
import Diagrams.Core.Points
import Diagrams.Core.Transform
import Diagrams.Core.V

------------------------------------------------------------
-- SortedList -------------------------------------------------
------------------------------------------------------------

newtype SortedList a = SortedList [a]

instance Wrapped [a] [a] (SortedList a) (SortedList a)
where wrapped = iso SortedList $ \(SortedList x) -> x

instance Ord a => Semigroup (SortedList a) where
sl0 <> sl1 = SortedList $ merge (view unwrapped sl0) (view unwrapped sl1)
where
merge xList@(x:xs) yList@(y:ys) =
if x <= y then x : merge xs yList else y : merge xList ys
merge xList@(_:_) [] = xList
merge [] yList@(_:_) = yList
merge [] [] = []

instance Ord a => Monoid (SortedList a) where
mappend = (<>)
mempty = SortedList []

------------------------------------------------------------
-- Trace -------------------------------------------------
------------------------------------------------------------
Expand All @@ -82,32 +105,37 @@ 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 -> SortedList (Scalar v) }

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

mkTrace :: (Point v -> v -> [PosInf (Scalar v)]) -> Trace v
mkTrace :: (Point v -> v -> SortedList (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@.
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)

--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)

deriving instance (Ord (Scalar v)) =>Semigroup (Trace v)

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 3, 2014

Member

I think it should be possible to attach this deriving clause directly to the definition of Trace.

This comment has been minimized.

Copy link
@jeffreyrosenbluth

jeffreyrosenbluth Jan 3, 2014

Author Member

So newtype Trace v ... becomes newtype (Ord (Scalar v)) => Trace v …

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 3, 2014

Member

I don't think you need the Ord (Scalar v) part, I think if you attach the deriving clause to the declaration it infers the constraint on the Semigroup instance. I could be wrong though. If it's a choice between adding that constraint on the newtype and using a standalone deriving clause we should definitely go with the standalone.

This comment has been minimized.

Copy link
@jeffreyrosenbluth

jeffreyrosenbluth Jan 3, 2014

Author Member

Nope, it does not infer the constraint.
I leave it as standalone.



-- | The identity for the 'Monoid' instance is the constantly infinite
-- trace.

This comment has been minimized.

Copy link
@byorgey

byorgey Jan 3, 2014

Member

This comment doesn't make sense anymore, it should say something like "the empty trace".

instance Ord (Scalar v) => Monoid (Trace v) where
mappend = (<>)
mempty = mkTrace $ \_ _ -> [mempty]
deriving instance (Ord (Scalar v)) => Monoid (Trace v)
--instance Ord (Scalar v) => Monoid (Trace v) where
-- mappend = (<>)
-- mempty = mkTrace $ \_ _ -> []

type instance V (Trace v) = v

Expand Down Expand Up @@ -170,9 +198,9 @@ instance (Traced b) => Traced (S.Set b) where
-- 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 head $ ((getTrace a)^.unwrapping Trace) p v of
Finite s -> Just (s *^ v)
Infinity -> Nothing
traceV p v a = case view unwrapped $ ((getTrace a)^.unwrapping Trace) p v of
(s:_) -> Just (s *^ v)
[] -> Nothing

-- | Given a base point and direction, compute the closest point on
-- the boundary of the given object in the direction or its opposite.
Expand All @@ -194,26 +222,18 @@ maxTraceP p v a = (p .+^) <$> maxTraceV p v a
-- 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
getRayTrace a = Trace $ \p v ->
SortedList $ filter (>= 0) (view unwrapped
$ (((getTrace a)^.unwrapping Trace) p v))

-- | 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
rayTraceV p v a = case view unwrapped $ ((getRayTrace a)^.unwrapping Trace) p v of
(s:_) -> Just (s *^ v)
[] -> Nothing

-- | Given a base point and direction, compute the closest point on
-- the boundary of the given object, or @Nothing@ if there is no
Expand All @@ -227,9 +247,9 @@ rayTraceP p v a = (p .+^) <$> rayTraceV p v a
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
case view unwrapped $ ((getRayTrace a)^.unwrapping Trace) p v of
[] -> Nothing
xs -> Just ((last xs) *^ v)

-- | Like 'rayTraceP', but computes the *furthest* point on the boundary
-- instead of the closest.
Expand Down

0 comments on commit be67bc1

Please sign in to comment.