Twinside / Rasterific

A drawing engine in Haskell
BSD 3-Clause "New" or "Revised" License
140 stars 11 forks source link

Oblivious Strokes #56

Closed ibrahimsag closed 4 years ago

ibrahimsag commented 4 years ago

Transformations and stroke commands don't seem to play well together.

This is not a major issue and i did not have time to find the root cause but i just wanted to see if it means something.

In this particular case, I placed the origin at the center of the image with a translation, but the stroke commands still took the top-left corner as the origin.

Great library! Gratitude!

lancelet commented 4 years ago

I have a test case for the bug above. AFAICT, transformations are being ignored completely for strokes.

Here is the test case:

testCase :: IO ()
testCase = do
    let white     = PixelRGBA8 255 255 255 255
        strokeTex = withTexture (uniformTexture (PixelRGBA8 0 0x86 0xc1 255))
        fillTex   = withTexture (uniformTexture (PixelRGBA8 0 0x86 0xc1 80))
        geom      = circle (V2 0 0) 90
        stroked   = strokeTex $ stroke 5.0 JoinRound (CapRound, CapRound) geom
        filled    = fillTex $ fill geom
        xform     = translate (V2 100 100)
    let img = renderDrawing 200 200 white $ do
            withTransformation xform filled
            withTransformation xform stroked
    writePng "test-case.png" img

It results in the following output: test-case

The expected result is that the stroked and filled shape should lie on top of each other. Instead, the stroked shape remains at the origin.

lancelet commented 4 years ago

A simple workaround for the bug is to manually stroke the path first, converting it into a fill-able geometry. For example, in the case described above:

workaround :: IO ()
workaround = do
    let white     = PixelRGBA8 255 255 255 255
        strokeTex = withTexture (uniformTexture (PixelRGBA8 0 0x86 0xc1 255))
        fillTex   = withTexture (uniformTexture (PixelRGBA8 0 0x86 0xc1 80))
        geom      = circle (V2 0 0) 90
        strokized = strokize 5.0 JoinRound (CapRound, CapRound) geom
        stroked   = strokeTex $ fill strokized
        filled    = fillTex $ fill geom
        xform     = translate (V2 100 100)
    let img = renderDrawing 200 200 white $ do
            withTransformation xform filled
            withTransformation xform stroked
    writePng "workaround.png" img

Which indeed produces the expected output: workaround

lancelet commented 4 years ago

Addendum: for easier migration after the bug is fixed, I've defined:

stroke'
  :: Geometry geom
  => Float
  -> Join
  -> (Cap, Cap)
  -> geom
  -> Drawing px ()
stroke' width join caps geometry = fill $ strokize width join caps geometry

Which seems to be behaving the way I expect stroke to behave (AFAICT - I don't know if there are any corner cases I haven't yet encountered).

Twinside commented 4 years ago

I've uploaded the fixed version to Hackage