From d4561ad549cd7b491f1501e4cf5df16ed9b296da Mon Sep 17 00:00:00 2001 From: sheaf Date: Sat, 29 Aug 2020 16:34:51 +0200 Subject: [PATCH] use the correct tangent vector for stroke joins --- app/Main.hs | 14 ++++++++++- src/lib/Math/Bezier/Stroke.hs | 45 +++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/app/Main.hs b/app/Main.hs index 86cb113..4ec353d 100644 --- a/app/Main.hs +++ b/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 () diff --git a/src/lib/Math/Bezier/Stroke.hs b/src/lib/Math/Bezier/Stroke.hs index 02eaa61..a3e51de 100644 --- a/src/lib/Math/Bezier/Stroke.hs +++ b/src/lib/Math/Bezier/Stroke.hs @@ -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