use the correct tangent vector for stroke joins

This commit is contained in:
sheaf 2020-08-29 16:34:51 +02:00
parent 3916fe2656
commit d4561ad549
2 changed files with 37 additions and 22 deletions

View file

@ -102,7 +102,7 @@ testDocuments = IntMap.fromList
{ displayName = "Document 1" { displayName = "Document 1"
, filePath = Nothing , filePath = Nothing
, unsavedChanges = False , 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 ) , bounds = AABB ( Point2D 0 0 ) ( Point2D 100 100 )
, viewportCenter = Point2D 50 50 , viewportCenter = Point2D 50 50
@ -157,6 +157,18 @@ razor d = Seq.fromList
pp p = PathPoint p d pp p = PathPoint p d
cp p = ControlPoint 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 () main :: IO ()

View file

@ -137,7 +137,7 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
_ -> False _ -> False
fwd, bwd :: Seq ( StrokePoint () ) fwd, bwd :: Seq ( StrokePoint () )
( fwd, bwd ) = go tgt_start spt0 ( spt1 :<| spts ) ( fwd, bwd ) = go spt0 ( spt1 :<| spts )
(<~>) (<~>)
:: ( Monoid a, Monoid b ) :: ( 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). -- 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). -- 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 :: Vector2D Double -> StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) )
--joinAndContinue tgt sp sps = go sp sps
joinAndContinue _ _ Empty joinAndContinue _ _ Empty
-- Closed curve. -- Closed curve.
| isClosed | isClosed
@ -164,52 +165,52 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
) )
joinAndContinue tgt sp0 ( sp1 :<| sps ) joinAndContinue tgt sp0 ( sp1 :<| sps )
| tgt' `parallel` tgt | tgt' `parallel` tgt
= go tgt sp0 ( sp1 :<| sps ) = go sp0 ( sp1 :<| sps )
| let | let
ptOffset :: Vector2D Double ptOffset :: Vector2D Double
ptOffset = Point2D 0 0 --> coords sp0 ptOffset = Point2D 0 0 --> coords sp0
= ( ptOffset joinWithBrush ( withTangent tgt brush0 ) ( withTangent tgt' brush0 ) brush0 = ( ptOffset joinWithBrush ( withTangent tgt brush0 ) ( withTangent tgt' brush0 ) brush0
, ptOffset joinWithBrush ( withTangent ( (-1) *^ tgt' ) brush0 ) ( withTangent ( (-1) *^ tgt ) brush0 ) brush0 , ptOffset joinWithBrush ( withTangent ( (-1) *^ tgt' ) brush0 ) ( withTangent ( (-1) *^ tgt ) brush0 ) brush0
) )
<~> go tgt sp0 ( sp1 :<| sps ) <~> go sp0 ( sp1 :<| sps )
where where
tgt' :: Vector2D Double tgt' :: Vector2D Double
tgt' = coords sp0 --> coords sp1 tgt' = coords sp0 --> coords sp1
brush0 :: Seq ( StrokePoint () ) brush0 :: Seq ( StrokePoint () )
brush0 = removePointData $ brushShape @x sp0 brush0 = removePointData $ brushShape @x sp0
go :: Vector2D Double -> StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) ) go :: StrokePoint d -> Seq ( StrokePoint d ) -> ( Seq ( StrokePoint () ), Seq ( StrokePoint () ) )
go _ _ Empty = ( Empty, Empty ) go _ Empty = ( Empty, Empty )
-- Line. -- Line.
go tgt0 sp0 ( sp1 :<| sps ) go sp0 ( sp1 :<| sps )
| PathPoint {} <- sp1 | PathPoint {} <- sp1
, let , let
p0, p1, fop0, fop1, bop0, bop1 :: Point2D Double p0, p1, fop0, fop1, bop0, bop1 :: Point2D Double
p0 = coords sp0 p0 = coords sp0
p1 = coords sp1 p1 = coords sp1
fop0 = offset ( withTangent tgt0 ( brushShape @x sp0 ) ) p0 fop0 = offset ( withTangent tgt ( brushShape @x sp0 ) ) p0
fop1 = offset ( withTangent tgt0 ( brushShape @x sp1 ) ) p1 fop1 = offset ( withTangent tgt ( brushShape @x sp1 ) ) p1
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) p0 bop0 = offset ( withTangent ( (-1) *^ tgt ) ( brushShape @x sp0 ) ) p0
bop1 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp1 ) ) p1 bop1 = offset ( withTangent ( (-1) *^ tgt ) ( brushShape @x sp1 ) ) p1
tgt1 :: Vector2D Double tgt :: Vector2D Double
tgt1 = p0 --> p1 tgt = p0 --> p1
brush :: Double -> Seq ( StrokePoint () ) brush :: Double -> Seq ( StrokePoint () )
brush t = lerpBrush t ( brushShape @x sp0 ) ( brushShape @x sp1 ) brush t = lerpBrush t ( brushShape @x sp0 ) ( brushShape @x sp1 )
fwdPts, bwdPts :: [ Point2D Double ] fwdPts, bwdPts :: [ Point2D Double ]
fwdPts fwdPts
= [ ( offset $ withTangent tgt0 $ brush t ) = [ ( offset $ withTangent tgt $ brush t )
( lerp @( Vector2D Double ) t p0 p1 ) ( lerp @( Vector2D Double ) t p0 p1 )
| t <- [0.1,0.2..0.9] | t <- [0.1,0.2..0.9]
] ]
bwdPts bwdPts
= [ ( offset $ withTangent ( (-1) *^ tgt0 ) $ brush t ) = [ ( offset $ withTangent ( (-1) *^ tgt ) $ brush t )
( lerp @( Vector2D Double ) t p0 p1 ) ( lerp @( Vector2D Double ) t p0 p1 )
| t <- [0.9,0.8..0.1] | t <- [0.9,0.8..0.1]
] ]
= ( fitCurve fop0 tgt0 fwdPts fop1 tgt0, fitCurve bop1 ( (-1) *^ tgt1 ) bwdPts bop0 ( (-1) *^ tgt0 ) ) = ( fitCurve fop0 tgt fwdPts fop1 tgt, fitCurve bop1 ( (-1) *^ tgt ) bwdPts bop0 ( (-1) *^ tgt ) )
<~> joinAndContinue tgt1 sp1 sps <~> joinAndContinue tgt sp1 sps
-- Quadratic Bézier curve. -- Quadratic Bézier curve.
go tgt0 sp0 ( sp1 :<| sp2 :<| sps ) go sp0 ( sp1 :<| sp2 :<| sps )
| ControlPoint {} <- sp1 | ControlPoint {} <- sp1
, PathPoint {} <- sp2 , PathPoint {} <- sp2
, let , let
@ -221,7 +222,8 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
fop2 = offset ( withTangent tgt2 ( brushShape @x sp2 ) ) p2 fop2 = offset ( withTangent tgt2 ( brushShape @x sp2 ) ) p2
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) p0 bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) p0
bop2 = offset ( withTangent ( (-1) *^ tgt2 ) ( brushShape @x sp2 ) ) p2 bop2 = offset ( withTangent ( (-1) *^ tgt2 ) ( brushShape @x sp2 ) ) p2
tgt2 :: Vector2D Double tgt0, tgt2 :: Vector2D Double
tgt0 = p0 --> p1
tgt2 = p1 --> p2 tgt2 = p1 --> p2
bez :: Quadratic.Bezier ( Point2D Double ) bez :: Quadratic.Bezier ( Point2D Double )
bez = Quadratic.Bezier { .. } 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 ) ) = ( fitCurve fop0 tgt0 fwdPts fop2 tgt2, fitCurve bop2 ( (-1) *^ tgt2 ) bwdPts bop0 ( (-1) *^ tgt0 ) )
<~> joinAndContinue tgt2 sp2 sps <~> joinAndContinue tgt2 sp2 sps
-- Cubic Bézier curve. -- Cubic Bézier curve.
go tgt0 sp0 ( sp1 :<| sp2 :<| sp3 :<| sps ) go sp0 ( sp1 :<| sp2 :<| sp3 :<| sps )
| ControlPoint {} <- sp1 | ControlPoint {} <- sp1
, ControlPoint {} <- sp2 , ControlPoint {} <- sp2
, PathPoint {} <- sp3 , PathPoint {} <- sp3
@ -256,7 +258,8 @@ stroke allPts@( spt0 :<| spt1 :<| spts )
fop3 = offset ( withTangent tgt3 ( brushShape @x sp3 ) ) p3 fop3 = offset ( withTangent tgt3 ( brushShape @x sp3 ) ) p3
bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) p0 bop0 = offset ( withTangent ( (-1) *^ tgt0 ) ( brushShape @x sp0 ) ) p0
bop3 = offset ( withTangent ( (-1) *^ tgt3 ) ( brushShape @x sp3 ) ) p3 bop3 = offset ( withTangent ( (-1) *^ tgt3 ) ( brushShape @x sp3 ) ) p3
tgt3 :: Vector2D Double tgt0, tgt3 :: Vector2D Double
tgt0 = p0 --> p1
tgt3 = p2 --> p3 tgt3 = p2 --> p3
bez :: Cubic.Bezier ( Point2D Double ) bez :: Cubic.Bezier ( Point2D Double )
bez = Cubic.Bezier { .. } 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 ) ) = ( fitCurve fop0 tgt0 fwdPts fop3 tgt3, fitCurve bop3 ( (-1) *^ tgt3 ) bwdPts bop0 ( (-1) *^ tgt0 ) )
<~> joinAndContinue tgt3 sp3 sps <~> 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 -- Various utility functions