diagrams / svg-builder

BSD 3-Clause "New" or "Revised" License
10 stars 14 forks source link

SVG Path Arc largeFlag and sweepFlag are broken? #17

Open mk-emeks opened 1 year ago

mk-emeks commented 1 year ago

I'm not an expert in the field, but I think SVG render engines expects 0 or 1 as possible values for largeFlag and sweepFlag. Unfortunately the library is generating invalid values, given is returning 1.0000, and 0.0000.

Ref.

-- | Arc (absolute)
aA :: RealFloat a =>  a -> a -> a -> a -> a -> a -> a -> Text
aA rx ry xrot largeFlag sweepFlag x y = T.concat
  [ "A ", toText rx, ",", toText ry, " ", toText xrot, " ", toText largeFlag
  , " ", toText sweepFlag, " ", toText x, " ", toText y, " "]

-- | Arc (relative)
aR :: RealFloat a =>  a -> a -> a -> a -> a -> a -> a -> Text
aR rx ry xrot largeFlag sweepFlag x y = T.concat
  [ "a ", toText rx, ",", toText ry, " ", toText xrot, " ", toText largeFlag
  , " ", toText sweepFlag, " ", toText x, " ", toText y, " "]

^ at https://github.com/diagrams/svg-builder/blob/master/src/Graphics/Svg/Path.hs#L100

Those 2 are using the toText implemented here (notice from previous snippet that for all params uses the same):

-- | Convert a number to Text.
toText :: RealFloat a => a -> Text
toText = toStrict . toLazyText . formatRealFloat Fixed (Just 4)

^ at https://github.com/diagrams/svg-builder/blob/master/src/Graphics/Svg/Path.hs#L26

Example

{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-missing-import-lists #-}

module Main where

import System.Environment (getArgs)
import Graphics.Svg
import qualified Data.Text as T

svg :: Element -> Element
svg content =
     doctype
  <> with (svg11_ content) [Version_ <<- "1.1", Width_ <<- "300", Height_ <<- "300"]

initialRadius :: Float
initialRadius = 10

contents :: Element
contents =
   circle_ [Cx_ <<- "150", Cy_ <<- "150", R_ <<- (T.pack $ show initialRadius), Stroke_ <<- "green", Fill_ <<- "red"]
   <> path_ [   
     D_ <<-  mA (150 :: Float) 150 -- center
             <> lA (150 + initialRadius :: Float) 150
             <> aA initialRadius initialRadius 0 0 0 (150 + initialRadius * cos (pi/6) :: Float) (150 - initialRadius * sin (pi/6))
             <> z
     , Stroke_ <<- "blue"
     , Fill_ <<- "orange"
   ]

-- | Example: cabal run -- example.svg
main :: IO ()
main = do
  [filename] <- getArgs
  let filenameInCurrentDirectoryPath :: FilePath
      filenameInCurrentDirectoryPath = "./" ++ filename
      svgContent :: String
      svgContent = show $ svg contents
  -- Obs: Completly overrides the existing file
  writeFile filenameInCurrentDirectoryPath svgContent 

Screenshot(45)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" width="300" xmlns:xlink="http://www.w3.org/1999/xlink" height="300" version="1.11.1"><circle fill="red" stroke="green" cy="150" cx="150" r="10.0"/><path fill="orange" stroke="blue" d="M 150.0000,150.0000 L 160.0000,150.0000 A 10.0000,10.0000 0.0000 0 0 158.6602 145.0000 Z"/></svg>

Screenshot(44)

mk-emeks commented 1 year ago

this PR fix the issue I pointed out: https://github.com/diagrams/svg-builder/pull/14