mirror of
https://gitlab.com/sheaf/metabrush.git
synced 2024-11-27 09:24:08 +00:00
use the correct tangent vector for stroke joins
This commit is contained in:
parent
3916fe2656
commit
d4561ad549
14
app/Main.hs
14
app/Main.hs
|
@ -102,7 +102,7 @@ testDocuments = IntMap.fromList
|
|||
{ displayName = "Document 1"
|
||||
, filePath = Nothing
|
||||
, unsavedChanges = False
|
||||
, strokes = [ Stroke ( circle ( PointData Normal ( razor $ BrushPointData Normal ) ) ) "Circle" True ( unsafeUnique 0 )
|
||||
, strokes = [ Stroke ( circle ( PointData Normal ( rect $ BrushPointData Normal ) ) ) "Circle" True ( unsafeUnique 0 )
|
||||
]
|
||||
, bounds = AABB ( Point2D 0 0 ) ( Point2D 100 100 )
|
||||
, viewportCenter = Point2D 50 50
|
||||
|
@ -157,6 +157,18 @@ razor d = Seq.fromList
|
|||
pp p = PathPoint p d
|
||||
cp p = ControlPoint p d
|
||||
|
||||
rect :: forall a. a -> Seq ( StrokePoint a )
|
||||
rect d = Seq.fromList
|
||||
[ pp ( Point2D 20 5 )
|
||||
, pp ( Point2D 20 -5 )
|
||||
, pp ( Point2D -20 -5 )
|
||||
, pp ( Point2D -20 5 )
|
||||
, pp ( Point2D 20 5 )
|
||||
]
|
||||
where
|
||||
pp :: Point2D Double -> StrokePoint a
|
||||
pp p = PathPoint p d
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
main :: IO ()
|
||||
|
|
|
@ -137,7 +137,7 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
_ -> False
|
||||
|
||||
fwd, bwd :: Seq ( StrokePoint () )
|
||||
( fwd, bwd ) = go tgt_start spt0 ( spt1 :<| spts )
|
||||
( fwd, bwd ) = go spt0 ( spt1 :<| spts )
|
||||
|
||||
(<~>)
|
||||
:: ( Monoid a, Monoid b )
|
||||
|
@ -149,6 +149,7 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
-- Connecting paths at a point of discontinuity of the tangent vector direction (G1 discontinuity).
|
||||
-- This happens at corners of the brush path (including endpoints of an open brush path, where the tangent flips direction).
|
||||
joinAndContinue :: Vector2D Double -> StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) )
|
||||
--joinAndContinue tgt sp sps = go sp sps
|
||||
joinAndContinue _ _ Empty
|
||||
-- Closed curve.
|
||||
| isClosed
|
||||
|
@ -164,52 +165,52 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
)
|
||||
joinAndContinue tgt sp0 ( sp1 :<| sps )
|
||||
| tgt' `parallel` tgt
|
||||
= go tgt sp0 ( sp1 :<| sps )
|
||||
= go sp0 ( sp1 :<| sps )
|
||||
| let
|
||||
ptOffset :: Vector2D Double
|
||||
ptOffset = Point2D 0 0 --> coords sp0
|
||||
= ( ptOffset • joinWithBrush ( withTangent tgt brush0 ) ( withTangent tgt' brush0 ) brush0
|
||||
, ptOffset • joinWithBrush ( withTangent ( (-1) *^ tgt' ) brush0 ) ( withTangent ( (-1) *^ tgt ) brush0 ) brush0
|
||||
)
|
||||
<~> go tgt sp0 ( sp1 :<| sps )
|
||||
<~> go sp0 ( sp1 :<| sps )
|
||||
where
|
||||
tgt' :: Vector2D Double
|
||||
tgt' = coords sp0 --> coords sp1
|
||||
brush0 :: Seq ( StrokePoint () )
|
||||
brush0 = removePointData $ brushShape @x sp0
|
||||
|
||||
go :: Vector2D Double -> StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) )
|
||||
go _ _ Empty = ( Empty, Empty )
|
||||
go :: StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) )
|
||||
go _ Empty = ( Empty, Empty )
|
||||
-- Line.
|
||||
go tgt0 sp0 ( sp1 :<| sps )
|
||||
go sp0 ( sp1 :<| sps )
|
||||
| PathPoint {} <- sp1
|
||||
, let
|
||||
p0, p1, fop0, fop1, bop0, bop1 :: Point2D Double
|
||||
p0 = coords sp0
|
||||
p1 = coords sp1
|
||||
fop0 = offset ( withTangent tgt0 ( brushShape @x sp0 ) ) • p0
|
||||
fop1 = offset ( withTangent tgt0 ( brushShape @x sp1 ) ) • p1
|
||||
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) • p0
|
||||
bop1 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp1 ) ) • p1
|
||||
tgt1 :: Vector2D Double
|
||||
tgt1 = p0 --> p1
|
||||
fop0 = offset ( withTangent tgt ( brushShape @x sp0 ) ) • p0
|
||||
fop1 = offset ( withTangent tgt ( brushShape @x sp1 ) ) • p1
|
||||
bop0 = offset ( withTangent ( (-1) *^ tgt ) ( brushShape @x sp0 ) ) • p0
|
||||
bop1 = offset ( withTangent ( (-1) *^ tgt ) ( brushShape @x sp1 ) ) • p1
|
||||
tgt :: Vector2D Double
|
||||
tgt = p0 --> p1
|
||||
brush :: Double -> Seq ( StrokePoint () )
|
||||
brush t = lerpBrush t ( brushShape @x sp0 ) ( brushShape @x sp1 )
|
||||
fwdPts, bwdPts :: [ Point2D Double ]
|
||||
fwdPts
|
||||
= [ ( offset $ withTangent tgt0 $ brush t )
|
||||
= [ ( offset $ withTangent tgt $ brush t )
|
||||
• ( lerp @( Vector2D Double ) t p0 p1 )
|
||||
| t <- [0.1,0.2..0.9]
|
||||
]
|
||||
bwdPts
|
||||
= [ ( offset $ withTangent ( (-1) *^ tgt0 ) $ brush t ) •
|
||||
= [ ( offset $ withTangent ( (-1) *^ tgt ) $ brush t ) •
|
||||
( lerp @( Vector2D Double ) t p0 p1 )
|
||||
| t <- [0.9,0.8..0.1]
|
||||
]
|
||||
= ( fitCurve fop0 tgt0 fwdPts fop1 tgt0, fitCurve bop1 ( (-1) *^ tgt1 ) bwdPts bop0 ( (-1) *^ tgt0 ) )
|
||||
<~> joinAndContinue tgt1 sp1 sps
|
||||
= ( fitCurve fop0 tgt fwdPts fop1 tgt, fitCurve bop1 ( (-1) *^ tgt ) bwdPts bop0 ( (-1) *^ tgt ) )
|
||||
<~> joinAndContinue tgt sp1 sps
|
||||
-- Quadratic Bézier curve.
|
||||
go tgt0 sp0 ( sp1 :<| sp2 :<| sps )
|
||||
go sp0 ( sp1 :<| sp2 :<| sps )
|
||||
| ControlPoint {} <- sp1
|
||||
, PathPoint {} <- sp2
|
||||
, let
|
||||
|
@ -221,7 +222,8 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
fop2 = offset ( withTangent tgt2 ( brushShape @x sp2 ) ) • p2
|
||||
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) • p0
|
||||
bop2 = offset ( withTangent ( (-1) *^ tgt2 ) ( brushShape @x sp2 ) ) • p2
|
||||
tgt2 :: Vector2D Double
|
||||
tgt0, tgt2 :: Vector2D Double
|
||||
tgt0 = p0 --> p1
|
||||
tgt2 = p1 --> p2
|
||||
bez :: Quadratic.Bezier ( Point2D Double )
|
||||
bez = Quadratic.Bezier { .. }
|
||||
|
@ -242,7 +244,7 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
= ( fitCurve fop0 tgt0 fwdPts fop2 tgt2, fitCurve bop2 ( (-1) *^ tgt2 ) bwdPts bop0 ( (-1) *^ tgt0 ) )
|
||||
<~> joinAndContinue tgt2 sp2 sps
|
||||
-- Cubic Bézier curve.
|
||||
go tgt0 sp0 ( sp1 :<| sp2 :<| sp3 :<| sps )
|
||||
go sp0 ( sp1 :<| sp2 :<| sp3 :<| sps )
|
||||
| ControlPoint {} <- sp1
|
||||
, ControlPoint {} <- sp2
|
||||
, PathPoint {} <- sp3
|
||||
|
@ -256,7 +258,8 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
fop3 = offset ( withTangent tgt3 ( brushShape @x sp3 ) ) • p3
|
||||
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) • p0
|
||||
bop3 = offset ( withTangent ( (-1) *^ tgt3 ) ( brushShape @x sp3 ) ) • p3
|
||||
tgt3 :: Vector2D Double
|
||||
tgt0, tgt3 :: Vector2D Double
|
||||
tgt0 = p0 --> p1
|
||||
tgt3 = p2 --> p3
|
||||
bez :: Cubic.Bezier ( Point2D Double )
|
||||
bez = Cubic.Bezier { .. }
|
||||
|
@ -276,7 +279,7 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
|
|||
]
|
||||
= ( fitCurve fop0 tgt0 fwdPts fop3 tgt3, fitCurve bop3 ( (-1) *^ tgt3 ) bwdPts bop0 ( (-1) *^ tgt0 ) )
|
||||
<~> joinAndContinue tgt3 sp3 sps
|
||||
go _ p0 ps = error $ "stroke: unrecognised stroke type\n" <> show ( p0 :<| ps )
|
||||
go p0 ps = error $ "stroke: unrecognised stroke type\n" <> show ( p0 :<| ps )
|
||||
|
||||
-----------------------------------
|
||||
-- Various utility functions
|
||||
|
|
Loading…
Reference in a new issue