{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Diagrams.CubicSpline.Boehm
( BSpline
, bsplineToBeziers
, bspline
) where
import Data.List (sort, tails)
import Diagrams.Core (N, Point, V, origin)
import Diagrams.Located (at, loc, unLoc)
import Diagrams.Segment (FixedSegment (..), fromFixedSeg)
import Diagrams.TrailLike (TrailLike, fromLocSegments)
import Diagrams.Util (iterateN)
import Linear.Vector (Additive, lerp)
type BSpline v n = [Point v n]
affineCombo :: (Additive f, Fractional a) => a -> a -> a -> f a -> f a -> f a
affineCombo :: forall (f :: * -> *) a.
(Additive f, Fractional a) =>
a -> a -> a -> f a -> f a -> f a
affineCombo a
a a
b a
t f a
x f a
y = forall (f :: * -> *) a.
(Additive f, Num a) =>
a -> f a -> f a -> f a
lerp ((a
tforall a. Num a => a -> a -> a
-a
a)forall a. Fractional a => a -> a -> a
/(a
bforall a. Num a => a -> a -> a
-a
a)) f a
y f a
x
windows :: Int -> [a] -> [[a]]
windows :: forall a. Int -> [a] -> [[a]]
windows Int
k = forall a. (a -> Bool) -> [a] -> [a]
takeWhile ((forall a. Eq a => a -> a -> Bool
==Int
k) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Int
length) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. Int -> [a] -> [a]
take Int
k) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [[a]]
tails
extend :: Int -> [a] -> [a]
extend :: forall a. Int -> [a] -> [a]
extend Int
k [a]
xs = forall a. Int -> a -> [a]
replicate Int
k (forall a. [a] -> a
head [a]
xs) forall a. [a] -> [a] -> [a]
++ [a]
xs forall a. [a] -> [a] -> [a]
++ forall a. Int -> a -> [a]
replicate Int
k (forall a. [a] -> a
last [a]
xs)
data PolarPt v n = PP { forall (v :: * -> *) n. PolarPt v n -> Point v n
unPP :: Point v n, forall (v :: * -> *) n. PolarPt v n -> [n]
_knots :: [n] }
mkPolarPt :: Ord n => Point v n -> [n] -> PolarPt v n
mkPolarPt :: forall n (v :: * -> *). Ord n => Point v n -> [n] -> PolarPt v n
mkPolarPt Point v n
pt [n]
kts = forall (v :: * -> *) n. Point v n -> [n] -> PolarPt v n
PP Point v n
pt (forall a. Ord a => [a] -> [a]
sort [n]
kts)
combine
:: (Additive v, Fractional n, Ord n)
=> Int -> PolarPt v n -> PolarPt v n -> PolarPt v n
combine :: forall (v :: * -> *) n.
(Additive v, Fractional n, Ord n) =>
Int -> PolarPt v n -> PolarPt v n -> PolarPt v n
combine Int
k (PP Point v n
pt1 [n]
kts1) (PP Point v n
pt2 [n]
kts2)
= forall n (v :: * -> *). Ord n => Point v n -> [n] -> PolarPt v n
mkPolarPt
(forall (f :: * -> *) a.
(Additive f, Fractional a) =>
a -> a -> a -> f a -> f a -> f a
affineCombo (forall a. [a] -> a
head [n]
kts1) (forall a. [a] -> a
last [n]
kts2) n
newKt Point v n
pt1 Point v n
pt2)
(n
newKt forall a. a -> [a] -> [a]
: forall a. Int -> [a] -> [a]
drop Int
1 [n]
kts1)
where
newKt :: n
newKt = [n]
kts2 forall a. [a] -> Int -> a
!! Int
k
bsplineToBeziers
:: (Additive v, Fractional n, Num n, Ord n)
=> BSpline v n
-> [FixedSegment v n]
bsplineToBeziers :: forall (v :: * -> *) n.
(Additive v, Fractional n, Num n, Ord n) =>
BSpline v n -> [FixedSegment v n]
bsplineToBeziers BSpline v n
controls = [FixedSegment v n]
beziers
where
n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length BSpline v n
controls
numKnots :: Int
numKnots = Int
n forall a. Num a => a -> a -> a
+ Int
2
knots :: [n]
knots = forall a. Int -> (a -> a) -> a -> [a]
iterateN Int
numKnots (forall a. Num a => a -> a -> a
+n
1forall a. Fractional a => a -> a -> a
/(forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
numKnots forall a. Num a => a -> a -> a
- n
1)) n
0
controls' :: [PolarPt v n]
controls' = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall n (v :: * -> *). Ord n => Point v n -> [n] -> PolarPt v n
mkPolarPt (forall a. Int -> [a] -> [a]
extend Int
2 BSpline v n
controls) (forall a. Int -> [a] -> [[a]]
windows Int
3 forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
extend Int
2 [n]
knots)
bezierControls :: [(PolarPt v n, PolarPt v n)]
bezierControls = forall a b. (a -> b) -> [a] -> [b]
map forall {v :: * -> *} {n}.
(Additive v, Fractional n, Ord n) =>
[PolarPt v n] -> (PolarPt v n, PolarPt v n)
combineC (forall a. Int -> [a] -> [[a]]
windows Int
2 [PolarPt v n]
controls')
combineC :: [PolarPt v n] -> (PolarPt v n, PolarPt v n)
combineC [PolarPt v n
pabc, PolarPt v n
pbcd] = (forall (v :: * -> *) n.
(Additive v, Fractional n, Ord n) =>
Int -> PolarPt v n -> PolarPt v n -> PolarPt v n
combine Int
0 PolarPt v n
pabc PolarPt v n
pbcd, forall (v :: * -> *) n.
(Additive v, Fractional n, Ord n) =>
Int -> PolarPt v n -> PolarPt v n -> PolarPt v n
combine Int
1 PolarPt v n
pabc PolarPt v n
pbcd)
combineC [PolarPt v n]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"combineC must be called on a list of length 2"
bezierEnds :: [PolarPt v n]
bezierEnds = forall a b. (a -> b) -> [a] -> [b]
map forall {v :: * -> *} {n}.
(Additive v, Fractional n, Ord n) =>
[(PolarPt v n, PolarPt v n)] -> PolarPt v n
combineE (forall a. Int -> [a] -> [[a]]
windows Int
2 [(PolarPt v n, PolarPt v n)]
bezierControls)
combineE :: [(PolarPt v n, PolarPt v n)] -> PolarPt v n
combineE [(PolarPt v n
_,PolarPt v n
pabb),(PolarPt v n
pbbc,PolarPt v n
_)] = forall (v :: * -> *) n.
(Additive v, Fractional n, Ord n) =>
Int -> PolarPt v n -> PolarPt v n -> PolarPt v n
combine Int
0 PolarPt v n
pabb PolarPt v n
pbbc
combineE [(PolarPt v n, PolarPt v n)]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"combineE must be called on a list of length 2"
beziers :: [FixedSegment v n]
beziers = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall {v :: * -> *} {n}.
(PolarPt v n, PolarPt v n) -> [PolarPt v n] -> FixedSegment v n
mkBezier (forall a. Int -> [a] -> [a]
drop Int
1 [(PolarPt v n, PolarPt v n)]
bezierControls) (forall a. Int -> [a] -> [[a]]
windows Int
2 [PolarPt v n]
bezierEnds)
where
mkBezier :: (PolarPt v n, PolarPt v n) -> [PolarPt v n] -> FixedSegment v n
mkBezier (PolarPt v n
paab,PolarPt v n
pabb) [PolarPt v n
paaa,PolarPt v n
pbbb]
= forall (v :: * -> *) n.
Point v n
-> Point v n -> Point v n -> Point v n -> FixedSegment v n
FCubic (forall (v :: * -> *) n. PolarPt v n -> Point v n
unPP PolarPt v n
paaa) (forall (v :: * -> *) n. PolarPt v n -> Point v n
unPP PolarPt v n
paab) (forall (v :: * -> *) n. PolarPt v n -> Point v n
unPP PolarPt v n
pabb) (forall (v :: * -> *) n. PolarPt v n -> Point v n
unPP PolarPt v n
pbbb)
mkBezier (PolarPt v n, PolarPt v n)
_ [PolarPt v n]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"mkBezier must be called on a list of length 2"
bspline :: (TrailLike t, V t ~ v, N t ~ n) => BSpline v n -> t
bspline :: forall t (v :: * -> *) n.
(TrailLike t, V t ~ v, N t ~ n) =>
BSpline v n -> t
bspline = forall t. TrailLike t => Located [Segment Closed (V t) (N t)] -> t
fromLocSegments forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}.
(Additive (V a), Num (N a)) =>
[Located a] -> Located [a]
fixup forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall n (v :: * -> *).
(Num n, Additive v) =>
FixedSegment v n -> Located (Segment Closed v n)
fromFixedSeg forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (v :: * -> *) n.
(Additive v, Fractional n, Num n, Ord n) =>
BSpline v n -> [FixedSegment v n]
bsplineToBeziers
where
fixup :: [Located a] -> Located [a]
fixup [] = [] forall a. a -> Point (V a) (N a) -> Located a
`at` forall (f :: * -> *) a. (Additive f, Num a) => Point f a
origin
fixup (Located a
b1:[Located a]
rest) = (forall a. Located a -> a
unLoc Located a
b1 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map forall a. Located a -> a
unLoc [Located a]
rest) forall a. a -> Point (V a) (N a) -> Located a
`at` forall a. Located a -> Point (V a) (N a)
loc Located a
b1