juicy-gcode 0.1.0.10 → 0.2.0.1
raw patch · 6 files changed
+99/−85 lines, 6 filesdep +gitrevdep ~optparse-applicative
Dependencies added: gitrev
Dependency ranges changed: optparse-applicative
Files
- ChangeLog.md +6/−0
- README.md +63/−59
- juicy-gcode.cabal +5/−4
- src/GCode.hs +1/−1
- src/Main.hs +18/−13
- src/Render.hs +6/−8
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for juicy-gcode +## 0.2.0.1 -- 2020-08-24 + +- Breaking change: change default DPI to 96 instead of 72 +- Breaking change: the option to mirror the Y axis is removed (it is always mirrored now for correct result) +- Add --version flag + ## 0.1.0.10 -- 2020-08-19 - Improve algorithmic stability at small details
README.md view
@@ -6,11 +6,9 @@ ## Overview -Haskell SVG to G-code converter that aims to support most SVG features. The flavor of the generated G-Code can be influenced providing a configuration file. -Juicy-gcode, in contrast to most SVG to G-Code converters, approximates bezier curves with [biarcs](http://dlacko.org/blog/2016/10/19/approximating-bezier-curves-by-biarcs/) instead of line segments -that results in much better curve fit. +Juicy-gcode is a configurable SVG to G-code converter that approximates bezier curves with [biarcs](http://dlacko.org/blog/2016/10/19/approximating-bezier-curves-by-biarcs/) for maximal curve fitting. -## Installation and usage +## Installation The easiest way is to download one of the pre-built binaries from the [releases page](https://github.com/domoszlai/juicy-gcode/releases). Alternatively, you can build from source code as follows: @@ -21,83 +19,89 @@ - `$ stack install` - `$ juicy-gcode --help` -``` -juicy-gcode - The SVG to G-Code converter +## Usage -Usage: juicy-gcode SVGFILE [-f|--flavor CONFIGFILE] [-o|--output OUTPUTFILE] - [-d|--dpi DPI] [-r|--resolution RESOLUTION] - [-m|--mirror-y-axis] [-b|--generate-bezier] - Convert SVGFILE to G-Code +> :warning: **Breaking change**: Since version 0.2.0.1, default DPI is changed to 96 and the option to mirror the Y axis is removed (it is always mirrored now for correct result) -Available options: - -h,--help Show this help text - SVGFILE The SVG file to be converted - -f,--flavor CONFIGFILE Configuration of G-Code flavor - -o,--output OUTPUTFILE The output G-Code file (default is standard output) - -d,--dpi DPI Used to determine the size of the SVG when it does - not contain any units; dot per inch (default is 72) - -r,--resolution RESOLUTION Shorter paths are replaced by line segments; mm - (default is 0.1) - -m,--mirror-y-axis Mirror Y axis to have the result in G-Code coordinate - system - -b,--generate-bezier Generate bezier curves (G5) instead of arcs (G2,G3) +The easier way to use juicy-gcode is to simply provide an SVG file name. The generated GCode will be written to standard output. + ``` +$ juicy-gcode SVGFILE +``` -## Configuration +Alternativly, you can provide an output file name as well. -The default G-Code flavor configuration file is the following: +``` +$ juicy-gcode SVGFILE -o OUTPUT +``` +Sometimes you want to overwrite some default settings. These are the + +* *--dpi* (default 96 DPI) [the resolution of the SVG file](https://developer.mozilla.org/en-US/docs/Web/CSS/resolution) that is used to determine the size of the SVG when it does not contain explicit units +* *--resolution* (default is 0.1 mm) the resolution of the generated GCode. Paths smaller than this are replaced by line segments instead of further approximated by biarcs + ``` -gcode -{ - begin = "G17;G90;G0 Z10;G0 X0 Y0;M3;G4 P2000.000000" - end = "G0 Z10;M5;M2" - toolon = "G00 Z10" - tooloff = "G01 Z0 F10.00" -} +$ juicy-gcode SVGFILE --dpi 72 --resolution 0.01 ``` -A new configuration file can be set by the `--flavor` or `-f` command line option. +Some firmwares (e.g. [Marlin](https://marlinfw.org/docs/gcode/G005.html)) can handle bezier curves directly. In this case +you can command juicy-gcode not to approximate bezier-curves but emit them unchanged. -Another configurable property is the resolution of the SVG image in DPI (dot per inch). It can be given by the `--dpi` or `-d` command line option. Default value is 72 DPI. +``` +$ juicy-gcode SVGFILE --generate-bezier +``` -## Limitations +## Configuration -Missing features: +The generated GCode is highly dependent on the actual device it will be executed by. In juicy-gcode these settings are called +GCode *flavor* and consists of the following: -- text (easy with e.g. [FontyFruity](https://hackage.haskell.org/package/FontyFruity), maybe once, you can convert text to curves easily anyway) -- filling (moderately difficult) -- clipping (probably not easy, maybe once) -- images (not planned) +- Begin GCode routine (commands that are executed *before* the actual print job) +- End GCode routine (commands that are executed *after* the actual print job) +- Tool on (commands to switch the tool on, e.g. lower pen) +- Tool off (commands to switch the tool off e.g. lift pen) -## Testing and bugs +These settings can be provided by a configuration file. The default settings +are made for being able to test the generated GCode in an emulator e.g. with [LaserWeb](https://laserweb.yurl.ch/) +or [my hanging plotter simulator](https://github.com/domoszlai/hanging-plotter-simulator). -There is a JavaScript [hanging plotter simulator](https://github.com/domoszlai/hanging-plotter-simulator) mainly developed to test the generated gcode. -Please file an issue if you run into a problem (or drop me an email to dlacko @ gmail.com). +``` +gcode +{ + begin = "G17;G90;G0 Z1;G0 X0 Y0" + end = "G0 Z1" + toolon = "G00 Z1" + tooloff = "G01 Z0 F10.00" +} +``` -## Implementation +In the case you want to overwrite it, copy this favor to a text file and modify it according to your need. Then use juicy-gcode as follows: -SVG images are built using the following shapes (all of these are subject of an arbitrary affine transformation): +``` +$ juicy-gcode SVGFILE -f FLAVORFILE +``` -- lines -- circles -- ellipses -- elliptic arcs with optional x axis rotation -- quadratic and cubic bezier curves +## Future development -In contrast G-Code implements only +Juicy-gcode was originally developed as a testbed for my hanging plotter project, but over the years +it reached maturity and became a really usuable tool. My main idea for further development is to turn it +into a tool that can drive CNCs in 2.5 dimensions (e.g. carving, engraving) with just one colored SVG file. -- lines -- non-elliptical arcs +To be able to test and enjoy that software, I need a proper CNC. Please consider donating a small amount for that purpose, +or donate an actual CNC if you have a spare one for whatever reason. -That means that only lines, circles and some arcs (non-elliptic ones without rotation) can be translated to G-Code directly. If transformations are also counted, then -only lines can be translated to G-Code directly as circles are not invariant under affine transformations. Because of this, the converter is implemented in two stages. +**[Donate for a CNC](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UGFZYDQSTF58L&source=https://github.com/domoszlai/juicy-gcode/)** -### Stage 1 +Collected so far: 102.47€ +Target: >= 209€ -All the SVG drawing operations are translated to a list of MoveTo, LineTo and CubicBezierTo operations as these are invariant under affine transformations. -Arcs, circles and ellipses can be easily approximated with bezier curves with a small error. +Thank you so much for all people supporting the development! -### Stage 2 +## Limitations -Cubic bezier curves are approximated with [Biarcs](https://en.wikipedia.org/wiki/Biarc) using the algorithm described in [[1](http://www.itc.ktu.lt/index.php/ITC/article/view/11812)] and explained [here](http://dlacko.org/blog/2016/10/19/approximating-bezier-curves-by-biarcs/). +SVG features that are not supported: + +- texts +- filling +- clipping +- images
juicy-gcode.cabal view
@@ -1,5 +1,5 @@ name: juicy-gcode -version: 0.1.0.10 +version: 0.2.0.1 license: BSD3 license-file: LICENSE author: dlacko @@ -19,17 +19,18 @@ hs-source-dirs: src main-is: Main.hs - other-modules: Approx BiArc CircularArc CubicBezier GCode Line Render SvgArcSegment Transformation Types SVGExt + other-modules: Approx BiArc CircularArc CubicBezier GCode Line Render SvgArcSegment Transformation Types SVGExt Paths_juicy_gcode build-depends: base >=4.8 && <5, lens >=4.15.4 && <4.20, linear >=1.20 && <1.22, - optparse-applicative >=0.13 && <0.16, + optparse-applicative >=0.13 && <0.20, configurator >=0.3 && <0.4, text >=1.2.2 && <1.3, matrix >=0.3.5 && <0.4, - svg-tree >=0.6 && <0.7 + svg-tree >=0.6 && <0.7, + gitrev >=1.3.0 && <1.4 GHC-Options: -Wall default-language: Haskell2010
src/GCode.hs view
@@ -15,7 +15,7 @@ } defaultFlavor :: GCodeFlavor -defaultFlavor = GCodeFlavor "G17\nG90\nG0 Z10\nG0 X0 Y0\nM3\nG4 P2000.000000" "G0 Z10\nM5\nM2" "G01 Z0 F10.00" "G00 Z10" +defaultFlavor = GCodeFlavor "G17\nG90\nG0 Z1\nG0 X0 Y0\n" "G0 Z1" "G01 Z0 F10.00" "G00 Z1" toString :: GCodeFlavor -> Int -> [GCodeOp] -> String toString (GCodeFlavor begin end on off) dpi gops = begin ++ "\n" ++ intercalate "\n" (toString' gops (0,0) True) ++ "\n" ++ end
src/Main.hs view
@@ -1,12 +1,17 @@+{-# LANGUAGE TemplateHaskell #-} + import qualified Graphics.Svg as SVG -import Data.Text +import Options.Applicative +import Paths_juicy_gcode (version) +import Data.Version (showVersion) +import Development.GitRev (gitHash) + +import Data.Text (Text, pack, unpack, replace) import qualified Data.Configurator as C import Data.Monoid -import Options.Applicative - import Render import GCode @@ -15,7 +20,6 @@ , _outfile :: Maybe String , _dpi :: Int , _resolution :: Double - , _mirrorYAxis :: Bool , _generateBezier :: Bool } @@ -36,10 +40,10 @@ <> help "The output G-Code file (default is standard output)" )) <*> (option auto ( long "dpi" - <> value 72 + <> value 96 <> short 'd' <> metavar "DPI" - <> help "Used to determine the size of the SVG when it does not contain any units; dot per inch (default is 72)" )) + <> help "Used to determine the size of the SVG when it does not contain any units; dot per inch (default is 96)" )) <*> (option auto ( long "resolution" <> value 0.1 @@ -47,21 +51,17 @@ <> metavar "RESOLUTION" <> help "Shorter paths are replaced by line segments; mm (default is 0.1)" )) <*> (switch - ( long "mirror-y-axis" - <> short 'm' - <> help "Mirror Y axis to have the result in G-Code coordinate system" )) - <*> (switch ( long "generate-bezier" <> short 'b' <> help "Generate bezier curves (G5) instead of arcs (G2,G3)" )) runWithOptions :: Options -> IO () -runWithOptions (Options svgFile mbCfg mbOut dpi resolution mirrorYAxis generateBezier) = +runWithOptions (Options svgFile mbCfg mbOut dpi resolution generateBezier) = do mbDoc <- SVG.loadSvgFile svgFile flavor <- maybe (return defaultFlavor) readFlavor mbCfg case mbDoc of - (Just doc) -> writer (toString flavor dpi $ renderDoc mirrorYAxis generateBezier dpi resolution doc) + (Just doc) -> writer (toString flavor dpi $ renderDoc generateBezier dpi resolution doc) Nothing -> putStrLn "juicy-gcode: error during opening the SVG file" where writer = maybe putStrLn (\fn -> writeFile fn) mbOut @@ -78,10 +78,15 @@ tooloff <- C.require cfg (pack "gcode.tooloff") return $ GCodeFlavor (toLines begin) (toLines end) (toLines toolon) (toLines tooloff) +versionOption :: Parser (a -> a) +versionOption = infoOption + (concat ["juicy-gcode ", showVersion version, ", git revision ", $(gitHash)]) + (long "version" <> short 'v' <> help "Show version") + main :: IO () main = execParser opts >>= runWithOptions where - opts = info (helper <*> options) + opts = info (helper <*> versionOption <*> options) ( fullDesc <> progDesc "Convert SVGFILE to G-Code" <> header "juicy-gcode - The SVG to G-Code converter" )
src/Render.hs view
@@ -52,23 +52,21 @@ toAbsolute _ SVG.OriginAbsolute p = p toAbsolute (cx,cy) SVG.OriginRelative (dx,dy) = (cx+dx, cy+dy) -docTransform :: Bool -> Int -> SVG.Document -> TransformationMatrix -docTransform mirrorYAxis dpi doc = multiply mirrorTransform (viewBoxTransform $ SVG._viewBox doc) +docTransform :: Int -> SVG.Document -> TransformationMatrix +docTransform dpi doc = multiply mirrorTransform (viewBoxTransform $ SVG._viewBox doc) where viewBoxTransform (Just (vbx,vby,vbw,vbh)) = multiply (scaleTransform (w/vbw) (h/vbh)) (translateTransform (-vbx) (-vby)) viewBoxTransform Nothing = identityTransform - mirrorTransform - | mirrorYAxis = mirrorYTransform w h - | otherwise = identityTransform + mirrorTransform = mirrorYTransform w h (w, h) = (documentSize dpi doc) -renderDoc :: Bool -> Bool -> Int -> Double -> SVG.Document -> [GCodeOp] -renderDoc mirrorYAxis generateBezier dpi resolution doc - = stage2 $ renderTrees (docTransform mirrorYAxis dpi doc) (SVG._elements doc) +renderDoc :: Bool -> Int -> Double -> SVG.Document -> [GCodeOp] +renderDoc generateBezier dpi resolution doc + = stage2 $ renderTrees (docTransform dpi doc) (SVG._elements doc) where pxresolution = (fromIntegral dpi) / 2.45 / 10 * resolution