2024-02-23 16:03:28 +00:00
|
|
|
|
{-# LANGUAGE PolyKinds #-}
|
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
|
{-# LANGUAGE UndecidableInstances #-}
|
|
|
|
|
|
|
|
|
|
module Main
|
|
|
|
|
( main
|
|
|
|
|
|
|
|
|
|
-- Testing
|
|
|
|
|
, TestCase(..)
|
|
|
|
|
, testCases
|
|
|
|
|
, testCaseStrokeFunctions
|
|
|
|
|
, eval
|
|
|
|
|
, mkVal, mkBox
|
|
|
|
|
, potentialCusp
|
|
|
|
|
, dEdsdcdt
|
|
|
|
|
)
|
|
|
|
|
where
|
|
|
|
|
|
|
|
|
|
-- base
|
2024-02-24 18:37:34 +00:00
|
|
|
|
import Control.Concurrent.MVar
|
|
|
|
|
( newMVar )
|
2024-02-23 16:03:28 +00:00
|
|
|
|
import Data.Coerce
|
|
|
|
|
( coerce )
|
|
|
|
|
import Data.Foldable
|
|
|
|
|
( for_ )
|
2024-02-24 18:37:34 +00:00
|
|
|
|
import Data.List
|
|
|
|
|
( intercalate )
|
2024-02-23 16:03:28 +00:00
|
|
|
|
import GHC.Exts
|
|
|
|
|
( Proxy#, proxy# )
|
|
|
|
|
import GHC.Generics
|
|
|
|
|
( Generic )
|
|
|
|
|
import GHC.TypeNats
|
|
|
|
|
( type (-) )
|
2024-02-24 18:37:34 +00:00
|
|
|
|
import Numeric
|
|
|
|
|
( showFFloat )
|
2024-02-23 16:03:28 +00:00
|
|
|
|
|
|
|
|
|
-- containers
|
|
|
|
|
import Data.Sequence
|
|
|
|
|
( Seq )
|
|
|
|
|
import qualified Data.Sequence as Seq
|
|
|
|
|
( index )
|
|
|
|
|
import Data.Tree
|
|
|
|
|
( foldTree )
|
|
|
|
|
|
|
|
|
|
-- brush-strokes
|
|
|
|
|
import Calligraphy.Brushes
|
2024-02-24 18:37:34 +00:00
|
|
|
|
import Debug.Utils
|
|
|
|
|
( logToFile )
|
2024-02-23 16:03:28 +00:00
|
|
|
|
import Math.Algebra.Dual
|
|
|
|
|
import Math.Bezier.Spline
|
|
|
|
|
import Math.Bezier.Stroke
|
|
|
|
|
import Math.Bezier.Stroke.EnvelopeEquation
|
|
|
|
|
import Math.Differentiable
|
|
|
|
|
import Math.Interval
|
|
|
|
|
import Math.Linear
|
|
|
|
|
import Math.Module
|
|
|
|
|
import Math.Ring
|
|
|
|
|
( Transcendental )
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
|
main = for_ testCases $ \ testCase@( TestCase { testName, testAlgorithmParams } ) -> do
|
|
|
|
|
let ( _, testStrokeFnI ) = testCaseStrokeFunctions testCase
|
|
|
|
|
( newtTrees, ( dunno, sols ) ) = computeCusps testAlgorithmParams testStrokeFnI
|
|
|
|
|
showedTrees = map ( uncurry showIntervalNewtonTree ) newtTrees
|
|
|
|
|
putStrLn $ unlines $
|
|
|
|
|
[ ""
|
|
|
|
|
, "Test case '" ++ testName ++ "':" ] ++
|
|
|
|
|
map ( " " ++ )
|
|
|
|
|
[ " #sols: " ++ show (length sols)
|
|
|
|
|
, "#dunno: " ++ show (length dunno)
|
|
|
|
|
, "#trees: " ++ show @Int (sum @_ @Int $ map (foldTree ( \ _ bs -> 1 + sum bs )) showedTrees)
|
|
|
|
|
, " dunno: " ++ show dunno
|
|
|
|
|
, " sols: " ++ show sols
|
|
|
|
|
]
|
2024-02-24 18:37:34 +00:00
|
|
|
|
--logFileMVar <- newMVar "logs/trickyCusp.log"
|
|
|
|
|
--logToFile logFileMVar (unlines logLines)
|
|
|
|
|
-- `seq` return ()
|
2024-02-23 16:03:28 +00:00
|
|
|
|
|
|
|
|
|
testCases :: [ TestCase ]
|
|
|
|
|
testCases = [ ellipse , trickyCusp2 ]
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
data TestCase =
|
|
|
|
|
forall nbParams. ParamsCt nbParams =>
|
|
|
|
|
TestCase
|
|
|
|
|
{ testName :: !String
|
|
|
|
|
, testBrush :: !( Brush nbParams )
|
|
|
|
|
, testStroke :: !( Point nbParams, Curve Open () ( Point nbParams ))
|
|
|
|
|
, testAlgorithmParams :: !CuspAlgorithmParams
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
testCaseStrokeFunctions
|
|
|
|
|
:: TestCase
|
|
|
|
|
-> ( ℝ 1 -> Seq ( ℝ 1 -> StrokeDatum 2 () )
|
|
|
|
|
, 𝕀ℝ 1 -> Seq ( 𝕀ℝ 1 -> StrokeDatum 3 𝕀 ) )
|
|
|
|
|
testCaseStrokeFunctions ( TestCase { testStroke = ( sp0, crv ), testBrush } ) =
|
|
|
|
|
getStrokeFunctions testBrush sp0 crv
|
|
|
|
|
|
|
|
|
|
-- Utilities to use in GHCi to help debugging.
|
|
|
|
|
|
|
|
|
|
eval
|
|
|
|
|
:: ( I i ( ℝ 1 ) -> Seq ( I i ( ℝ 1 ) -> StrokeDatum k i ) )
|
|
|
|
|
-> ( I i ( ℝ 1 ), Int, I i ( ℝ 1 ) )
|
|
|
|
|
-> StrokeDatum k i
|
|
|
|
|
eval f ( t, i, s ) = ( f t `Seq.index` i ) s
|
|
|
|
|
|
|
|
|
|
mkVal :: Double -> Int -> Double -> ( ℝ 1, Int, ℝ 1 )
|
|
|
|
|
mkVal t i s = ( ℝ1 t, i, ℝ1 s )
|
|
|
|
|
|
|
|
|
|
mkBox :: ( Double, Double ) -> Int -> ( Double, Double ) -> Box
|
|
|
|
|
mkBox ( t_min, t_max ) i ( s_min, s_max ) =
|
|
|
|
|
( 𝕀 ( ℝ1 t_min ) ( ℝ1 t_max ) , i, 𝕀 ( ℝ1 s_min ) ( ℝ1 s_max ) )
|
|
|
|
|
|
|
|
|
|
potentialCusp :: StrokeDatum 3 𝕀 -> Bool
|
|
|
|
|
potentialCusp
|
|
|
|
|
( StrokeDatum
|
|
|
|
|
{ ee = D22 { _D22_v = 𝕀 ( ℝ1 ee_min ) ( ℝ1 ee_max ) }
|
|
|
|
|
, 𝛿E𝛿sdcdt = D12 { _D12_v = T ( 𝕀 ( ℝ2 vx_min vy_min ) ( ℝ2 vx_max vy_max ) )}
|
|
|
|
|
}
|
|
|
|
|
) = ee_min <= 0 && ee_max >= 0
|
|
|
|
|
&& vx_min <= 0 && vx_max >= 0
|
|
|
|
|
&& vy_min <= 0 && vy_max >= 0
|
|
|
|
|
|
|
|
|
|
dEdsdcdt :: StrokeDatum k i -> D ( k - 2 ) ( I i ( ℝ 2 ) ) ( T ( I i ( ℝ 2 ) ) )
|
|
|
|
|
dEdsdcdt ( StrokeDatum { 𝛿E𝛿sdcdt = v } ) = v
|
|
|
|
|
|
|
|
|
|
{-
|
|
|
|
|
let (f, fI) = testCaseStrokeFunctions trickyCusp2
|
|
|
|
|
|
|
|
|
|
take 10 $ Data.List.sortOn ( \ ( _, ℝ1 e, v) -> abs e + norm v ) [ let { v = mkVal x 3 y; d = eval f v } in ( v, _D12_v $ ee d, _D0_v $ dEdsdcdt d ) | x <- [0.57,0.5701 .. 0.58], y <- [0.29,0.291..0.3] ]
|
|
|
|
|
> ((ℝ1 0.5798800000000057,3,ℝ1 0.267980000000008),ℝ1 -2.8596965543670194e-4,V2 7.79559474412963e-2 2.0389671921293484e-2)
|
|
|
|
|
|
|
|
|
|
potentialCusp $ eval fI $ mkBox (0.5798, 0.5799) 3 (0.26798, 0.26799)
|
|
|
|
|
> True
|
|
|
|
|
|
|
|
|
|
let nbPotentialSols b = let ( _newtTrees, ( dunno, sols ) ) = intervalNewtonGSFrom NoPreconditioning 1e-7 fI b in length dunno + length sols
|
|
|
|
|
|
|
|
|
|
nbPotentialSols $ mkBox (0.5798, 0.5799) 3 (0.26798, 0.26799)
|
|
|
|
|
1
|
|
|
|
|
|
|
|
|
|
nbPotentialSols $ mkBox (0.5798, 0.675) 3 (0.26798, 0.26799)
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
|
let showTrees b = map ( uncurry showIntervalNewtonTree ) $ fst $ intervalNewtonGSFrom NoPreconditioning 1e-7 fI b
|
|
|
|
|
|
|
|
|
|
putStrLn $ unlines $ map Data.Tree.View.showTree $ showTrees $ mkBox (0.5798, 0.675) 3 (0.26798, 0.26799)
|
|
|
|
|
|
|
|
|
|
([ℝ1 0.5798, ℝ1 0.675],3,[ℝ1 0.26798, ℝ1 0.26799]) (area 0.000001) N []
|
|
|
|
|
└─ ([ℝ1 0.5973000285624527, ℝ1 0.6750000000000002],3,[ℝ1 0.26798, ℝ1 0.26799000000000006]) (area 0.000001) NoSolution "ee" ([ℝ1 0.5973000285624527, ℝ1 0.6750000000000002],3,[ℝ1 0.26798, ℝ1 0.26799000000000006])
|
|
|
|
|
|
2024-02-24 18:37:34 +00:00
|
|
|
|
eval fI $ mkBox (0.5798, 0.675) 3 (0.26798, 0.26799)
|
|
|
|
|
> D12 {_D12_v = T[ℝ2 -10088.6674944889 -3281.3820867312834, ℝ2 4124.668381545453 4524.807156085763], _D12_dx = TT[ℝ2 -173746.97965005718 -33281.18494907289, ℝ2 298.2609121556852 23639.772884799597], _D12_dy = TT[ℝ2 -18454.27716258352 -28337.509817580823, ℝ2 1163.6949532017436 -13936.383137525536]}}
|
|
|
|
|
i.e.
|
|
|
|
|
> f = [ℝ2 -10088.6674944889 -3281.3820867312834, ℝ2 4124.668381545453 4524.807156085763]
|
|
|
|
|
> f_t = [ℝ2 -173746.97965005718 -33281.18494907289, ℝ2 298.2609121556852 23639.772884799597]
|
|
|
|
|
> f_s = [ℝ2 -18454.27716258352 -28337.509817580823, ℝ2 1163.6949532017436 -13936.383137525536]
|
|
|
|
|
|
|
|
|
|
(f, fI) = testCaseStrokeFunctions trickyCusp2
|
|
|
|
|
t = 𝕀 (ℝ1 0.5798) (ℝ1 0.675)
|
|
|
|
|
s = 𝕀 (ℝ1 0.26798) (ℝ1 0.26799)
|
|
|
|
|
t_mid = 0.5 * ( 0.5798 + 0.675 )
|
|
|
|
|
s_mid = 0.5 * ( 0.26798 + 0.26799 )
|
|
|
|
|
D12 ( T f ) ( T ( T f_t ) ) ( T ( T f_s ) ) = dEdsdcdt $ eval fI (t, 3, s)
|
|
|
|
|
t' = coerce ( (-) @( 𝕀 Double ) ) t ( singleton ( ℝ1 t_mid ) ) :: 𝕀ℝ 1
|
|
|
|
|
s' = coerce ( (-) @( 𝕀 Double ) ) s ( singleton ( ℝ1 s_mid ) ) :: 𝕀ℝ 1
|
|
|
|
|
a = ( f_t, f_s )
|
|
|
|
|
b = negV2 $ singleton $ midV2 f
|
|
|
|
|
[((t2', s2'), isContr)] = gaussSeidel a b (t', s')
|
|
|
|
|
t2 = coerce ( (+) @( 𝕀 Double ) ) t2' ( singleton ( ℝ1 t_mid ) ) :: 𝕀ℝ 1
|
|
|
|
|
s2 = coerce ( (+) @( 𝕀 Double ) ) s2' ( singleton ( ℝ1 s_mid ) ) :: 𝕀ℝ 1
|
|
|
|
|
|
|
|
|
|
t2
|
|
|
|
|
> [ℝ1 0.6102365832093095, ℝ1 0.6750000000000002]
|
|
|
|
|
s2
|
|
|
|
|
> [ℝ1 0.26798, ℝ1 0.26799000000000006]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let ( 𝕀 ( ℝ2 a11_lo a21_lo ) ( ℝ2 a11_hi a21_hi ), 𝕀 ( ℝ2 a12_lo a22_lo ) ( ℝ2 a12_hi a22_hi ) ) = a
|
|
|
|
|
let ( 𝕀 ( ℝ2 b1_lo b2_lo ) ( ℝ2 b1_hi b2_hi ) ) = b
|
|
|
|
|
let ( 𝕀 ( ℝ1 x1_lo ) ( ℝ1 x1_hi ), 𝕀 ( ℝ1 x2_lo ) ( ℝ1 x2_hi ) ) = ( t', s' )
|
|
|
|
|
|
|
|
|
|
a11 = 𝕀 a11_lo a11_hi
|
|
|
|
|
a12 = 𝕀 a12_lo a12_hi
|
|
|
|
|
a21 = 𝕀 a21_lo a21_hi
|
|
|
|
|
a22 = 𝕀 a22_lo a22_hi
|
|
|
|
|
b1 = 𝕀 b1_lo b1_hi
|
|
|
|
|
b2 = 𝕀 b2_lo b2_hi
|
|
|
|
|
x1 = 𝕀 x1_lo x1_hi
|
|
|
|
|
x2 = 𝕀 x2_lo x2_hi
|
|
|
|
|
|
|
|
|
|
( b1 - a12 * x2 )
|
|
|
|
|
> [2981.90728508591, 2982.0918278575364]
|
|
|
|
|
|
|
|
|
|
extendedRecip a11
|
2024-02-23 16:03:28 +00:00
|
|
|
|
|
|
|
|
|
-}
|
|
|
|
|
|
2024-02-24 18:37:34 +00:00
|
|
|
|
negV2 :: 𝕀ℝ 2 -> 𝕀ℝ 2
|
|
|
|
|
negV2 ( 𝕀 ( ℝ2 x_lo y_lo ) ( ℝ2 x_hi y_hi ) ) =
|
|
|
|
|
let !( 𝕀 x'_lo x'_hi ) = negate $ 𝕀 x_lo x_hi
|
|
|
|
|
!( 𝕀 y'_lo y'_hi ) = negate $ 𝕀 y_lo y_hi
|
|
|
|
|
in 𝕀 ( ℝ2 x'_lo y'_lo ) ( ℝ2 x'_hi y'_hi )
|
|
|
|
|
|
|
|
|
|
midV2 :: 𝕀ℝ 2 -> ℝ 2
|
|
|
|
|
midV2 ( 𝕀 ( ℝ2 x_lo y_lo ) ( ℝ2 x_hi y_hi ) ) =
|
|
|
|
|
ℝ2 ( 0.5 * ( x_lo + x_hi ) ) ( 0.5 * ( y_lo + y_hi ) )
|
|
|
|
|
|
|
|
|
|
logLines :: [ String ]
|
|
|
|
|
logLines =
|
|
|
|
|
[ "f = dE/ds * dc/dt: f, df/dt, df/ds"
|
|
|
|
|
, "{" ++
|
|
|
|
|
(intercalate ","
|
|
|
|
|
[ "{" ++ showD (midPoint t) ++ "," ++ showD (midPoint s) ++ ",{" ++ intercalate "," vals ++ "}}"
|
|
|
|
|
| t <- map ( around 0.5798 ) [-0.05, -0.049.. 0.05]
|
|
|
|
|
, let i = 3
|
|
|
|
|
, s <- map ( around 0.26798 ) [-0.05, -0.049.. 0.05]
|
|
|
|
|
, let StrokeDatum
|
|
|
|
|
{ 𝛿E𝛿sdcdt = D12 (T f) (T (T f_t)) (T (T f_s))
|
|
|
|
|
} = (curvesI t `Seq.index` i) s
|
|
|
|
|
ℝ2 vx vy = midPoint2 f
|
|
|
|
|
ℝ2 vx_t vy_t = midPoint2 f_t
|
|
|
|
|
ℝ2 vx_s vy_s = midPoint2 f_s
|
|
|
|
|
vals = [ "{" ++ showD vx ++ "," ++ showD vy ++ "}"
|
|
|
|
|
, "{" ++ showD vx_t ++ "," ++ showD vy_t ++ "}"
|
|
|
|
|
, "{" ++ showD vx_s ++ "," ++ showD vy_s ++ "}"
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
) ++ "}"
|
|
|
|
|
]
|
|
|
|
|
where
|
|
|
|
|
around :: Double -> Double -> 𝕀ℝ 1
|
|
|
|
|
around z0 z = 𝕀 ( ℝ1 ( z + z0 - 1e-6 ) ) ( ℝ1 ( z + z0 + 1e-6 ) )
|
|
|
|
|
( _, curvesI ) = testCaseStrokeFunctions trickyCusp2
|
|
|
|
|
midPoint (𝕀 (ℝ1 lo) (ℝ1 hi)) = 0.5 * ( lo + hi )
|
|
|
|
|
midPoint2 (𝕀 (ℝ2 lo_x lo_y) (ℝ2 hi_x hi_y))
|
|
|
|
|
= ℝ2 ( 0.5 * ( lo_x + hi_x ) ) ( 0.5 * ( lo_y + hi_y ) )
|
|
|
|
|
|
|
|
|
|
showD :: Double -> String
|
|
|
|
|
showD float = showFFloat (Just 6) float ""
|
|
|
|
|
|
2024-02-23 16:03:28 +00:00
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
ellipse :: TestCase
|
|
|
|
|
ellipse =
|
|
|
|
|
TestCase
|
|
|
|
|
{ testName = "ellipse"
|
|
|
|
|
, testBrush = ellipseBrush
|
|
|
|
|
, testStroke = ( p0, LineTo ( NextPoint p1 ) () )
|
|
|
|
|
, testAlgorithmParams =
|
|
|
|
|
CuspAlgorithmParams
|
|
|
|
|
{ preconditioning = NoPreconditioning
|
|
|
|
|
, maxWidth = 1e-7
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
where
|
|
|
|
|
mkPt x y w h phi =
|
|
|
|
|
Point
|
|
|
|
|
{ pointCoords = ℝ2 x y
|
|
|
|
|
, pointParams = Params $ ℝ3 w h phi
|
|
|
|
|
}
|
|
|
|
|
p0 = mkPt 0 0 10 25 0
|
|
|
|
|
p1 = mkPt 100 0 15 40 pi
|
|
|
|
|
|
|
|
|
|
trickyCusp2 :: TestCase
|
|
|
|
|
trickyCusp2 =
|
|
|
|
|
TestCase
|
|
|
|
|
{ testName = "trickyCusp2"
|
|
|
|
|
, testBrush = circleBrush
|
|
|
|
|
, testStroke = ( p0, Bezier3To p1 p2 ( NextPoint p3 ) () )
|
|
|
|
|
, testAlgorithmParams =
|
|
|
|
|
CuspAlgorithmParams
|
|
|
|
|
{ preconditioning = NoPreconditioning
|
|
|
|
|
, maxWidth = 1e-7
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
where
|
|
|
|
|
mkPt x y =
|
|
|
|
|
Point
|
|
|
|
|
{ pointCoords = ℝ2 x y
|
|
|
|
|
, pointParams = Params $ ℝ1 5.0
|
|
|
|
|
}
|
|
|
|
|
p0 = mkPt 5e+1 -5e+1
|
|
|
|
|
p1 = mkPt -7.72994362904069e+1 -3.124468786098509e+1
|
|
|
|
|
p2 = mkPt -5.1505430313958364e+1 -3.9826386521527986e+1
|
|
|
|
|
p3 = mkPt -5e+1 -5e+1
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
type ParamsCt nbParams
|
|
|
|
|
= ( Show ( ℝ nbParams )
|
|
|
|
|
, HasChainRule Double 2 ( ℝ nbParams )
|
|
|
|
|
, HasChainRule ( 𝕀 Double ) 3 ( 𝕀 ( ℝ nbParams ) )
|
|
|
|
|
, Applicative ( D 2 ( ℝ nbParams ) )
|
|
|
|
|
, Applicative ( D 3 ( ℝ nbParams ) )
|
|
|
|
|
, Traversable ( D 2 ( ℝ nbParams ) )
|
|
|
|
|
, Traversable ( D 3 ( ℝ nbParams ) )
|
|
|
|
|
, Representable Double ( ℝ nbParams )
|
|
|
|
|
, Module Double ( T ( ℝ nbParams ) )
|
|
|
|
|
, Module ( 𝕀 Double ) ( T ( 𝕀 ( ℝ nbParams ) ) )
|
|
|
|
|
, Module ( D 2 ( ℝ nbParams ) Double ) ( D 2 ( ℝ nbParams ) ( ℝ 2 ) )
|
|
|
|
|
, Module ( D 3 ( ℝ nbParams ) ( 𝕀 Double ) ) ( D 3 ( ℝ nbParams ) ( 𝕀 ( ℝ 2 ) ) )
|
|
|
|
|
, Transcendental ( D 2 ( ℝ nbParams ) Double )
|
|
|
|
|
, Transcendental ( D 3 ( ℝ nbParams ) ( 𝕀 Double ) )
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
newtype Params nbParams = Params { getParams :: ( ℝ nbParams ) }
|
|
|
|
|
deriving newtype instance Show ( ℝ nbParams ) => Show ( Params nbParams )
|
|
|
|
|
|
|
|
|
|
data Point nbParams =
|
|
|
|
|
Point
|
|
|
|
|
{ pointCoords :: !( ℝ 2 )
|
|
|
|
|
, pointParams :: !( Params nbParams ) }
|
|
|
|
|
deriving stock Generic
|
|
|
|
|
deriving stock instance Show ( ℝ nbParams ) => Show ( Point nbParams )
|
|
|
|
|
|
|
|
|
|
data CuspAlgorithmParams =
|
|
|
|
|
CuspAlgorithmParams
|
|
|
|
|
{ preconditioning :: !Preconditioner
|
|
|
|
|
, maxWidth :: !Double
|
|
|
|
|
}
|
|
|
|
|
deriving stock Show
|
|
|
|
|
|
|
|
|
|
type Brush nbParams
|
|
|
|
|
= forall {t} k (i :: t)
|
|
|
|
|
. DiffInterp k i ( ℝ nbParams )
|
|
|
|
|
=> Proxy# i
|
|
|
|
|
-> ( forall a. a -> I i a )
|
|
|
|
|
-> C k ( I i ( ℝ nbParams ) )
|
|
|
|
|
( Spline Closed () ( I i ( ℝ 2 ) ) )
|
|
|
|
|
|
|
|
|
|
getStrokeFunctions
|
|
|
|
|
:: forall nbParams
|
|
|
|
|
. ParamsCt nbParams
|
|
|
|
|
=> Brush nbParams
|
|
|
|
|
-- ^ brush shape
|
|
|
|
|
-> Point nbParams
|
|
|
|
|
-- ^ start point
|
|
|
|
|
-> Curve Open () ( Point nbParams )
|
|
|
|
|
-- ^ curve points
|
|
|
|
|
-> ( ℝ 1 -> Seq ( ℝ 1 -> StrokeDatum 2 () )
|
|
|
|
|
, 𝕀ℝ 1 -> Seq ( 𝕀ℝ 1 -> StrokeDatum 3 𝕀 ) )
|
|
|
|
|
getStrokeFunctions brush sp0 crv =
|
|
|
|
|
let
|
|
|
|
|
usedParams :: C 2 ( ℝ 1 ) ( ℝ nbParams )
|
|
|
|
|
path :: C 2 ( ℝ 1 ) ( ℝ 2 )
|
|
|
|
|
( path, usedParams ) =
|
|
|
|
|
pathAndUsedParams @2 @() coerce id ( getParams . pointParams )
|
|
|
|
|
sp0 crv
|
|
|
|
|
usedParamsI :: C 3 ( 𝕀ℝ 1 ) ( 𝕀ℝ nbParams )
|
|
|
|
|
pathI :: C 3 ( 𝕀ℝ 1 ) ( 𝕀ℝ 2 )
|
|
|
|
|
( pathI, usedParamsI ) =
|
|
|
|
|
pathAndUsedParams @3 @𝕀 coerce singleton ( getParams . pointParams )
|
|
|
|
|
sp0 crv
|
|
|
|
|
in ( brushStrokeData @2 @( ℝ nbParams ) coerce coerce
|
|
|
|
|
path usedParams $
|
|
|
|
|
brush @2 @() proxy# id
|
|
|
|
|
, brushStrokeData @3 @( ℝ nbParams ) coerce coerce
|
|
|
|
|
pathI usedParamsI $
|
|
|
|
|
brush @3 @𝕀 proxy# singleton )
|
|
|
|
|
{-# INLINEABLE getStrokeFunctions #-}
|
|
|
|
|
|
|
|
|
|
computeCusps
|
|
|
|
|
:: CuspAlgorithmParams
|
|
|
|
|
-> ( 𝕀ℝ 1 -> Seq ( 𝕀ℝ 1 -> StrokeDatum 3 𝕀 ) )
|
|
|
|
|
-> ( [ ( Box, IntervalNewtonTree Box ) ], ( [ Box ], [ Box ] ) )
|
|
|
|
|
computeCusps params =
|
|
|
|
|
intervalNewtonGS ( preconditioning params ) ( maxWidth params )
|