diff options
| -rw-r--r-- | .travis.yml | 10 | ||||
| -rw-r--r-- | Makefile | 1 | ||||
| -rwxr-xr-x | bin/build-dist | 2 | ||||
| -rw-r--r-- | images/examples/Fill Stitch Starting and Ending Point.svg | 215 | ||||
| -rw-r--r-- | inx/inkstitch_install.inx (renamed from inx/inkstitch_palettes.inx) | 6 | ||||
| -rw-r--r-- | lib/commands.py | 89 | ||||
| -rw-r--r-- | lib/elements/auto_fill.py | 26 | ||||
| -rw-r--r-- | lib/elements/element.py | 41 | ||||
| -rw-r--r-- | lib/elements/stroke.py | 3 | ||||
| -rw-r--r-- | lib/extensions/__init__.py | 2 | ||||
| -rw-r--r-- | lib/extensions/base.py | 4 | ||||
| -rw-r--r-- | lib/extensions/install.py (renamed from lib/extensions/palettes.py) | 61 | ||||
| -rw-r--r-- | lib/extensions/params.py | 3 | ||||
| -rw-r--r-- | lib/stitches/auto_fill.py | 197 | ||||
| -rw-r--r-- | lib/svg/__init__.py | 1 | ||||
| -rw-r--r-- | lib/svg/path.py | 20 | ||||
| -rw-r--r-- | lib/svg/tags.py | 5 | ||||
| -rw-r--r-- | messages.po | 26 | ||||
| -rw-r--r-- | palettes/InkStitch ARC Polyester.gpl (renamed from palettes/ARC Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch ARC Rayon.gpl (renamed from palettes/ARC Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Admelody Polyester.gpl (renamed from palettes/Admelody Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Admelody Rayon.gpl (renamed from palettes/Admelody Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Anchor.gpl (renamed from palettes/Anchor.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Aurifil Lana.gpl (renamed from palettes/Aurifil Lana.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Aurifil Mako.gpl (renamed from palettes/Aurifil Mako.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Aurifil Polyester.gpl (renamed from palettes/Aurifil Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Aurifil Rayon.gpl (renamed from palettes/Aurifil Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Aurifil Royal.gpl (renamed from palettes/Aurifil Royal.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch BFC Polyester.gpl (renamed from palettes/BFC Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brildor AC.gpl (renamed from palettes/Brildor AC.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brildor CO.gpl (renamed from palettes/Brildor CO.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brildor MF.gpl (renamed from palettes/Brildor MF.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brildor NY.gpl (renamed from palettes/Brildor NY.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brildor PB.gpl (renamed from palettes/Brildor PB.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brother Country.gpl (renamed from palettes/Brother Country.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Brother Embroidery.gpl (renamed from palettes/Brother Embroidery.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Coats Alcazar Jazz.gpl (renamed from palettes/Coats Alcazar Jazz.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Coats Alcazar.gpl (renamed from palettes/Coats Alcazar.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Coats Sylko USA.gpl (renamed from palettes/Coats Sylko USA.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Coats Sylko.gpl (renamed from palettes/Coats Sylko.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch DMC.gpl (renamed from palettes/DMC.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Embroidex.gpl (renamed from palettes/Embroidex.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Emmel.gpl (renamed from palettes/Emmel.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Fil-Tec Glide.gpl (renamed from palettes/Fil-Tec Glide.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Floriani Polyester.gpl (renamed from palettes/Floriani Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch FuFu Polyester.gpl (renamed from palettes/FuFu Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch FuFu Rayon.gpl (renamed from palettes/FuFu Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Gunold.gpl (renamed from palettes/Gunold.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Gutermann Creativ Dekor.gpl (renamed from palettes/Gutermann Creativ Dekor.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Hemingworth.gpl (renamed from palettes/Hemingworth.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Isacord Polyester.gpl (renamed from palettes/Isacord Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Isafil Rayon.gpl (renamed from palettes/Isafil Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Isalon Polyester.gpl (renamed from palettes/Isalon Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Janome.gpl (renamed from palettes/Janome.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch King Star.gpl (renamed from palettes/King Star.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch MTB - Embroidex.gpl (renamed from palettes/MTB - Embroidex.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Madeira Burmilana.gpl (renamed from palettes/Madeira Burmilana.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Madeira Matt.gpl (renamed from palettes/Madeira Matt.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Madeira Polyneon.gpl (renamed from palettes/Madeira Polyneon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Madeira Rayon.gpl (renamed from palettes/Madeira Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Marathon Polyester.gpl (renamed from palettes/Marathon Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Marathon Rayon V3.gpl (renamed from palettes/Marathon Rayon V3.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Marathon Rayon.gpl (renamed from palettes/Marathon Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Metro.gpl (renamed from palettes/Metro.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Mettler Embroidery.gpl (renamed from palettes/Mettler Embroidery.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Mettler Poly Sheen.gpl (renamed from palettes/Mettler Poly Sheen.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Outback Embroidery Rayon.gpl (renamed from palettes/Outback Embroidery Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Poly X40.gpl (renamed from palettes/Poly X40.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Princess.gpl (renamed from palettes/Princess.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch RAL.gpl (renamed from palettes/RAL.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Radiant Rayon.gpl (renamed from palettes/Radiant Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Robison-Anton Polyester.gpl (renamed from palettes/Robison-Anton Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Robison-Anton Rayon.gpl (renamed from palettes/Robison-Anton Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Royal Polyester.gpl (renamed from palettes/Royal Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Royal Viscose Rayon.gpl (renamed from palettes/Royal Viscose Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Sigma.gpl (renamed from palettes/Sigma.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Simthread Polyester.gpl (renamed from palettes/Simthread Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Simthread Rayon.gpl (renamed from palettes/Simthread Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Sulky Polyester.gpl (renamed from palettes/Sulky Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Sulky Rayon.gpl (renamed from palettes/Sulky Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Swist Rayon.gpl (renamed from palettes/Swist Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Tristar Polyester.gpl (renamed from palettes/Tristar Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Tristar Rayon.gpl (renamed from palettes/Tristar Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Viking Palette.gpl (renamed from palettes/Viking Palette.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Vyapar Rayon.gpl (renamed from palettes/Vyapar Rayon.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Wonderfil Polyester.gpl (renamed from palettes/Wonderfil Polyester.gpl) | 0 | ||||
| -rw-r--r-- | palettes/InkStitch Wonderfil Rayon.gpl (renamed from palettes/Wonderfil Rayon.gpl) | 0 | ||||
| -rw-r--r-- | symbols/inkstitch.svg | 127 |
88 files changed, 693 insertions, 146 deletions
diff --git a/.travis.yml b/.travis.yml index 3016bb94..0bc49e06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,9 +32,9 @@ install: set -e if [ -n "$BUILD" ]; then # Need this for inkex.py and friends - wget -q https://inkscape.org/en/gallery/item/11254/inkscape-0.92.2.tar.bz2 - tar jxf inkscape-0.92.2.tar.bz2 - rm inkscape-0.92.2.tar.bz2 + wget -q https://inkscape.org/en/gallery/item/12187/inkscape-0.92.3.tar.bz2 + tar jxf inkscape-0.92.3.tar.bz2 + rm inkscape-0.92.3.tar.bz2 fi if [ "$BUILD" = "linux" ]; then # For some bizarre reason, this build has been failing due to the @@ -57,8 +57,8 @@ install: sudo apt-get install python-gi python-gi-cairo libgirepository1.0-dev # wxPython doen't publish linux wheels in pypi - wget -q https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-14.04/wxPython-4.0.0b2-cp27-cp27mu-linux_x86_64.whl - pip install wxPython-4.0.0b2-cp27-cp27mu-linux_x86_64.whl + wget -q https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-14.04/wxPython-4.0.3-cp27-cp27mu-linux_x86_64.whl + pip install wxPython-4.0.3-cp27-cp27mu-linux_x86_64.whl # We can't use the shapely wheel because it includes the geos # library but with a weird file name. Details: @@ -10,6 +10,7 @@ dist: distclean locales cp inx/*.inx dist cp -a images/examples dist/inkstitch cp -a palettes dist/inkstitch + cp -a symbols dist/inkstitch mkdir -p dist/inkstitch/bin/locales cp -a locales/* dist/inkstitch/bin/locales cp -a print dist/inkstitch/bin/ diff --git a/bin/build-dist b/bin/build-dist index 4d73313a..78e42430 100755 --- a/bin/build-dist +++ b/bin/build-dist @@ -29,7 +29,7 @@ else fi # This lets pyinstaller see inkex.py, etc. -pyinstaller_args+="-p inkscape-0.92.2/share/extensions " +pyinstaller_args+="-p inkscape-0.92.3/share/extensions " # output useful debugging info that helps us trace library dependency issues pyinstaller_args+="--log-level DEBUG " diff --git a/images/examples/Fill Stitch Starting and Ending Point.svg b/images/examples/Fill Stitch Starting and Ending Point.svg new file mode 100644 index 00000000..d11a24ae --- /dev/null +++ b/images/examples/Fill Stitch Starting and Ending Point.svg @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="4in" + height="4in" + viewBox="0 0 384 384" + id="svg8375" + version="1.1" + inkscape:version="0.92.3 (unknown)" + sodipodi:docname="fill_markers.svg"> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.979899" + inkscape:cx="169.91776" + inkscape:cy="93.125071" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + units="in" + inkscape:window-width="1366" + inkscape:window-height="705" + inkscape:window-x="-4" + inkscape:window-y="-4" + inkscape:window-maximized="1" + inkscape:snap-global="false" /> + <defs + id="defs8377"> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="marker14673" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(0.6) rotate(180) translate(0,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path14671" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible;" + id="Arrow2Mend" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(0.6) rotate(180) translate(0,0)" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" + id="path14422" /> + </marker> + <symbol + id="inkstitch_fill_start"> + <title + id="title9432-5">Fill stitch ending point</title> + <circle + inkscape:label="outline" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" + id="circle13166-6-3" + cx="85.223907" + cy="106.13256" + r="9.2465534" /> + <path + inkscape:connector-curvature="0" + id="path4183-5" + d="m 91.796747,106.13612 -10.4514,6.03412 v -12.06823 z" + inkscape:transform-center-y="3.0183984e-06" + inkscape:transform-center-x="-1.7419043" + style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.74180555;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + </symbol> + <symbol + id="inkstitch_fill_end"> + <title + id="title9427">Fill stitch starting point</title> + <circle + inkscape:label="outline" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" + id="circle13166" + cx="47.235394" + cy="105.91732" + r="9.2465534" /> + <path + inkscape:connector-curvature="0" + id="rect5371-2" + d="m 42.691395,101.26765 h 9.140878 v 9.14087 h -9.140878 z" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60622311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" /> + </symbol> + </defs> + <metadata + id="metadata8380"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-52.362271)"> + <path + embroider_fill_underlay_inset_mm="0.3" + embroider_fill_underlay="True" + sodipodi:nodetypes="cccccccccccccccccccccccccccc" + inkscape:connector-curvature="0" + d="m 178.7757,288.69033 0.8157,-41.88278 -35.86371,-21.64781 -36.6794,20.23498 -0.81569,41.88278 35.8637,21.64781 z m 48.50895,-81.46949 0.37532,-41.88904 -36.08932,-21.26956 -36.46463,20.61949 -0.37532,41.88904 36.08931,21.26956 z m 47.09578,82.14513 0.0611,-41.89068 -36.24783,-20.99829 -36.30896,20.8924 -0.0611,41.89068 36.24783,20.99828 z M 124.8814,351.39231 59.294526,237.79251 124.8814,124.19271 h 131.17374 l 65.58687,113.5998 -65.58687,113.5998 z" + style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.35955402;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path9699-3-7" /> + <flowRoot + xml:space="preserve" + id="flowRoot14860" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:26.66666603px;line-height:100%;font-family:Digitalt;-inkscape-font-specification:'Digitalt Bold';text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75590551;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + transform="translate(0,52.362271)"><flowRegion + id="flowRegion14862"><rect + id="rect14864" + width="144.45178" + height="68.690369" + x="374.7666" + y="150.14969" /></flowRegion><flowPara + id="flowPara14866" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.66666603px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:sans-serif">fill-stitch starting point</flowPara></flowRoot> <flowRoot + transform="translate(-492,52.362269)" + xml:space="preserve" + id="flowRoot14860-2" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:26.66666603px;line-height:100%;font-family:Digitalt;-inkscape-font-specification:'Digitalt Bold';text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75590551;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"><flowRegion + id="flowRegion14862-6"><rect + id="rect14864-5" + width="144.45178" + height="68.690369" + x="374.7666" + y="150.14969" /></flowRegion><flowPara + id="flowPara14866-2" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.66666603px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:sans-serif">fill-stitch ending point</flowPara></flowRoot> <flowRoot + transform="translate(-360,212.36227)" + xml:space="preserve" + id="flowRoot14860-6" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:26.66666603px;line-height:100%;font-family:Digitalt;-inkscape-font-specification:'Digitalt Bold';text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75590551;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"><flowRegion + id="flowRegion14862-5"><rect + id="rect14864-8" + width="462.14478" + height="569.72601" + x="374.7666" + y="150.14969" /></flowRegion><flowPara + id="flowPara14866-7" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif">The start and end markers above tell Ink/Stitch where to start and end the fill stitch.</flowPara><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14904" /><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14906">To use the markers, first install them using the Ink/Stitch "Install add-ons for Inkscape" extension and restart Inkscape.</flowPara><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14908" /><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14910">Access the markers using the Symbols tool (Object -> Symbols). Select "Ink/Stitch Comm ands" as the symbol set. Drag a marker out onto your canvas (doesn't matter where). Use the Flow-Chart Tool ("create diagram connectors") to draw a connection between the marker and the fill object to which it should apply. This will add a connector path. Adding an arrow on that path as in the above example is not necessary.</flowPara><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:72.70000064%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14912" /><flowPara + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333333px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:sans-serif" + id="flowPara14914"><flowSpan + style="line-height:72.70000064%" + id="flowSpan14916">Moving the marker will change the connector's position to match. You can also move the endpoints of the connector manually. The </flowSpan>connector's endpoint nearest to the fill object is the point at which stitching will start or end.</flowPara></flowRoot> </g> + <path + inkscape:connection-end="#path9699-3-7" + inkscape:connection-start="#use14355" + inkscape:connector-curvature="0" + inkscape:connector-type="polyline" + id="path14391" + d="M 356.92084,186.01367 321.3771,185.88908" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend)" /> + <use + transform="translate(270.34979,79.877542)" + height="100%" + width="100%" + y="0" + x="0" + xlink:href="#inkstitch_fill_start" + id="use14355" /> + <path + inkscape:connection-end="#path9699-3-7" + inkscape:connection-start="#use14379" + inkscape:connector-curvature="0" + inkscape:connector-type="polyline" + id="path14393" + d="m 25.78533,183.40549 34.433762,0.42335" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker14673)" /> + <use + transform="translate(-21.476504,77.567401)" + height="100%" + width="100%" + y="0" + x="0" + xlink:href="#inkstitch_fill_end" + id="use14379" /> +</svg> diff --git a/inx/inkstitch_palettes.inx b/inx/inkstitch_install.inx index 5daa3196..7275e13a 100644 --- a/inx/inkstitch_palettes.inx +++ b/inx/inkstitch_install.inx @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Install thread manufacturer color palettes</_name> - <id>org.inkstitch.palettes</id> + <_name>Install add-ons for Inkscape</_name> + <id>org.inkstitch.install</id> <dependency type="executable" location="extensions">inkstitch.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="extension" type="string" gui-hidden="true">palettes</param> + <param name="extension" type="string" gui-hidden="true">install</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/lib/commands.py b/lib/commands.py new file mode 100644 index 00000000..ec62d716 --- /dev/null +++ b/lib/commands.py @@ -0,0 +1,89 @@ +import inkex +import cubicsuperpath + +from .svg import apply_transforms +from .svg.tags import SVG_USE_TAG, SVG_SYMBOL_TAG, CONNECTION_START, CONNECTION_END, XLINK_HREF + + +class Command(object): + def __init__(self, connector): + self.connector = connector + self.svg = self.connector.getroottree().getroot() + + self.parse_command() + + def get_node_by_url(self, url): + # url will be #path12345. Find the object at the other end. + + if url is None: + raise ValueError("url is None") + + if not url.startswith('#'): + raise ValueError("invalid connection url: %s" % url) + + id = url[1:] + + try: + return self.svg.xpath(".//*[@id='%s']" % id)[0] + except (IndexError, AttributeError): + raise ValueError("could not find node by url %s" % id) + + def parse_connector_path(self): + path = cubicsuperpath.parsePath(self.connector.get('d')) + return apply_transforms(path, self.connector) + + def parse_command(self): + path = self.parse_connector_path() + + neighbors = [ + (self.get_node_by_url(self.connector.get(CONNECTION_START)), path[0][0][1]), + (self.get_node_by_url(self.connector.get(CONNECTION_END)), path[0][-1][1]) + ] + + if neighbors[0][0].tag != SVG_USE_TAG: + neighbors.reverse() + + if neighbors[0][0].tag != SVG_USE_TAG: + raise ValueError("connector does not point to a use tag") + + self.symbol = self.get_node_by_url(neighbors[0][0].get(XLINK_HREF)) + + if self.symbol.tag != SVG_SYMBOL_TAG: + raise ValueError("use points to non-symbol") + + self.command = self.symbol.get('id') + + if self.command.startswith('inkstitch_'): + self.command = self.command[10:] + else: + raise ValueError("symbol is not an Ink/Stitch command") + + self.target = neighbors[1][0] + self.target_point = neighbors[1][1] + + def __repr__(self): + return "Command('%s', %s)" % (self.command, self.target_point) + +def find_commands(node): + """Find the symbols this node is connected to and return them as Commands""" + + # find all paths that have this object as a connection + xpath = ".//*[@inkscape:connection-start='#%(id)s' or @inkscape:connection-end='#%(id)s']" % dict(id=node.get('id')) + connectors = node.getroottree().getroot().xpath(xpath, namespaces=inkex.NSS) + + # try to turn them into commands + commands = [] + for connector in connectors: + try: + commands.append(Command(connector)) + except ValueError: + import sys + import traceback + print >> sys.stderr, "not a Command:", connector.get('id'), traceback.format_exc() + # Parsing the connector failed, meaning it's not actually an Ink/Stitch command. + pass + + return commands + +def is_command(node): + return CONNECTION_START in node.attrib or CONNECTION_END in node.attrib diff --git a/lib/elements/auto_fill.py b/lib/elements/auto_fill.py index 504bae2a..59816878 100644 --- a/lib/elements/auto_fill.py +++ b/lib/elements/auto_fill.py @@ -100,13 +100,28 @@ class AutoFill(Fill): def fill_shape(self): return self.shrink_or_grow_shape(self.expand) + def get_starting_point(self, last_patch): + # If there is a "fill_start" Command, then use that; otherwise pick + # the point closest to the end of the last patch. + + if self.get_command('fill_start'): + return self.get_command('fill_start').target_point + elif last_patch: + return last_patch.stitches[-1] + else: + return None + + def get_ending_point(self): + if self.get_command('fill_end'): + return self.get_command('fill_end').target_point + else: + return None + def to_patches(self, last_patch): stitches = [] - if last_patch is None: - starting_point = None - else: - starting_point = last_patch.stitches[-1] + starting_point = self.get_starting_point(last_patch) + ending_point = self.get_ending_point() if self.fill_underlay: stitches.extend(auto_fill(self.underlay_shape, @@ -126,6 +141,7 @@ class AutoFill(Fill): self.max_stitch_length, self.running_stitch_length, self.staggers, - starting_point)) + starting_point, + ending_point)) return [Patch(stitches=stitches, color=self.color)] diff --git a/lib/elements/element.py b/lib/elements/element.py index 39437c9f..3c31f1b0 100644 --- a/lib/elements/element.py +++ b/lib/elements/element.py @@ -4,7 +4,8 @@ from shapely import geometry as shgeo from ..i18n import _ from ..utils import cache -from ..svg import PIXELS_PER_MM, get_viewbox_transform, convert_length, get_doc_size +from ..svg import PIXELS_PER_MM, convert_length, get_doc_size, apply_transforms +from ..commands import find_commands # inkscape-provided utilities import simpletransform @@ -171,10 +172,6 @@ class EmbroideryElement(object): @property def path(self): - return cubicsuperpath.parsePath(self.node.get("d")) - - @cache - def parse_path(self): # A CSP is a "cubic superpath". # # A "path" is a sequence of strung-together bezier curves. @@ -202,22 +199,32 @@ class EmbroideryElement(object): # In a path, each element in the 3-tuple is itself a tuple of (x, y). # Tuples all the way down. Hasn't anyone heard of using classes? - path = self.path - - # start with the identity transform - transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] + return cubicsuperpath.parsePath(self.node.get("d")) - # combine this node's transform with all parent groups' transforms - transform = simpletransform.composeParents(self.node, transform) + @cache + def parse_path(self): + return apply_transforms(self.path, self.node) - # add in the transform implied by the viewBox - viewbox_transform = get_viewbox_transform(self.node.getroottree().getroot()) - transform = simpletransform.composeTransform(viewbox_transform, transform) + @property + @cache + def commands(self): + return find_commands(self.node) - # apply the combined transform to this node's path - simpletransform.applyTransformToPath(transform, path) + @cache + def get_commands(self, command): + return [c for c in self.commands if c.command == command] - return path + @cache + def get_command(self, command): + commands = self.get_commands(command) + + if len(commands) == 1: + return commands[0] + elif len(commands) > 1: + raise ValueError(_("%(id)s has more than one command of type '%(command)s' linked to it") % + dict(id=self.node.get(id), command=command)) + else: + return None def strip_control_points(self, subpath): return [point for control_before, point, control_after in subpath] diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py index 5239f978..eca9e0ba 100644 --- a/lib/elements/stroke.py +++ b/lib/elements/stroke.py @@ -4,6 +4,7 @@ from .element import param, EmbroideryElement, Patch from ..i18n import _ from ..utils import cache, Point from ..stitches import running_stitch +from ..svg import parse_length_with_units warned_about_legacy_running_stitch = False @@ -57,7 +58,7 @@ class Stroke(EmbroideryElement): def is_running_stitch(self): # using stroke width <= 0.5 pixels to indicate running stitch is deprecated in favor of dashed lines - stroke_width = float(self.get_style("stroke-width", 1)) + stroke_width, units = parse_length_with_units(self.get_style("stroke-width", "1")) if self.dashed: return True diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 6d3e00d8..b8951e12 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -1,5 +1,5 @@ from embroider import Embroider -from palettes import Palettes +from install import Install from params import Params from print_pdf import Print from simulate import Simulate diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 831b6dc6..78f75cf1 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -7,6 +7,7 @@ from collections import MutableMapping from ..svg.tags import * from ..elements import AutoFill, Fill, Stroke, SatinColumn, Polyline, EmbroideryElement from ..utils import cache +from ..commands import is_command SVG_METADATA_TAG = inkex.addNS("metadata", "svg") @@ -165,7 +166,8 @@ class InkstitchExtension(inkex.Effect): classes.append(Fill) if element.get_style("stroke"): - classes.append(Stroke) + if not is_command(element.node): + classes.append(Stroke) if element.get_boolean_param("stroke_first", False): classes.reverse() diff --git a/lib/extensions/palettes.py b/lib/extensions/install.py index f7a6c7a5..d55b96d0 100644 --- a/lib/extensions/palettes.py +++ b/lib/extensions/install.py @@ -1,3 +1,5 @@ +# -*- coding: UTF-8 -*- + import sys import traceback import os @@ -14,26 +16,26 @@ import inkex from ..utils import guess_inkscape_config_path -class InstallPalettesFrame(wx.Frame): +class InstallerFrame(wx.Frame): def __init__(self, *args, **kwargs): wx.Frame.__init__(self, *args, **kwargs) - default_path = os.path.join(guess_inkscape_config_path(), "palettes") + self.path = guess_inkscape_config_path() panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) - text = wx.StaticText(panel, label=_("Directory in which to install palettes:")) - font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL) - text.SetFont(font) - sizer.Add(text, proportion=0, flag=wx.ALL|wx.EXPAND, border=10) + text_sizer = wx.BoxSizer(wx.HORIZONTAL) - path_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.path_input = wx.TextCtrl(panel, wx.ID_ANY, value=default_path) - path_sizer.Add(self.path_input, proportion=3, flag=wx.RIGHT|wx.EXPAND, border=20) - chooser_button = wx.Button(panel, wx.ID_OPEN, _('Choose another directory...')) - path_sizer.Add(chooser_button, proportion=1, flag=wx.EXPAND) - sizer.Add(path_sizer, proportion=0, flag=wx.ALL|wx.EXPAND, border=10) + text = _('Ink/Stitch can install files ("add-ons") that make it easier to use Inkscape to create machine embroidery designs. These add-ons will be installed:') + \ + "\n\n • " + _("thread manufacturer color palettes") + \ + "\n • " + _("Ink/Stitch visual commands (Object -> Symbols...)") + + static_text = wx.StaticText(panel, label=text) + font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL) + static_text.SetFont(font) + text_sizer.Add(static_text, proportion=0, flag=wx.ALL|wx.EXPAND, border=10) + sizer.Add(text_sizer, proportion=3, flag=wx.ALL|wx.EXPAND, border=0) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) install_button = wx.Button(panel, wx.ID_ANY, _("Install")) @@ -41,15 +43,11 @@ class InstallPalettesFrame(wx.Frame): buttons_sizer.Add(install_button, proportion=0, flag=wx.ALIGN_RIGHT|wx.ALL, border=5) cancel_button = wx.Button(panel, wx.ID_CANCEL, _("Cancel")) buttons_sizer.Add(cancel_button, proportion=0, flag=wx.ALIGN_RIGHT|wx.ALL, border=5) - sizer.Add(buttons_sizer, proportion=0, flag=wx.ALIGN_RIGHT) - - outer_sizer = wx.BoxSizer(wx.HORIZONTAL) - outer_sizer.Add(sizer, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + sizer.Add(buttons_sizer, proportion=1, flag=wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM) - panel.SetSizer(outer_sizer) + panel.SetSizer(sizer) panel.Layout() - chooser_button.Bind(wx.EVT_BUTTON, self.chooser_button_clicked) cancel_button.Bind(wx.EVT_BUTTON, self.cancel_button_clicked) install_button.Bind(wx.EVT_BUTTON, self.install_button_clicked) @@ -57,36 +55,37 @@ class InstallPalettesFrame(wx.Frame): self.Destroy() def chooser_button_clicked(self, event): - dialog = wx.DirDialog(self, _("Choose Inkscape palettes directory")) + dialog = wx.DirDialog(self, _("Choose Inkscape directory")) if dialog.ShowModal() != wx.ID_CANCEL: self.path_input.SetValue(dialog.GetPath()) def install_button_clicked(self, event): try: - self.install_palettes() + self.install_addons('palettes') + self.install_addons('symbols') except Exception, e: wx.MessageDialog(self, - _('Thread palette installation failed') + ': \n' + traceback.format_exc(), + _('Inkscape add-on installation failed') + ': \n' + traceback.format_exc(), _('Installation Failed'), wx.OK).ShowModal() else: wx.MessageDialog(self, - _('Thread palette files have been installed. Please restart Inkscape to load the new palettes.'), + _('Inkscape add-on files have been installed. Please restart Inkscape to load the new add-ons.'), _('Installation Completed'), wx.OK).ShowModal() self.Destroy() - def install_palettes(self): - path = self.path_input.GetValue() - palettes_dir = self.get_bundled_palettes_dir() - self.copy_files(glob(os.path.join(palettes_dir, "*")), path) + def install_addons(self, type): + path = os.path.join(self.path, type) + src_dir = self.get_bundled_dir(type) + self.copy_files(glob(os.path.join(src_dir, "*")), path) - def get_bundled_palettes_dir(self): + def get_bundled_dir(self, name): if getattr(sys, 'frozen', None) is not None: - return realpath(os.path.join(sys._MEIPASS, '..', 'palettes')) + return realpath(os.path.join(sys._MEIPASS, '..', name)) else: - return os.path.join(dirname(realpath(__file__)), 'palettes') + return realpath(os.path.join(dirname(realpath(__file__)), '..', '..', name)) if (sys.platform == "win32"): # If we try to just use shutil.copy it says the operation requires elevation. @@ -104,9 +103,9 @@ class InstallPalettesFrame(wx.Frame): for palette_file in files: shutil.copy(palette_file, dest) -class Palettes(inkex.Effect): +class Install(inkex.Effect): def effect(self): app = wx.App() - installer_frame = InstallPalettesFrame(None, title=_("Ink/Stitch Thread Palette Installer"), size=(450, 200)) + installer_frame = InstallerFrame(None, title=_("Ink/Stitch Add-ons Installer"), size=(550, 250)) installer_frame.Show() app.MainLoop() diff --git a/lib/extensions/params.py b/lib/extensions/params.py index 9d8de41b..58fedd6b 100644 --- a/lib/extensions/params.py +++ b/lib/extensions/params.py @@ -19,6 +19,7 @@ from ..stitch_plan import patches_to_stitch_plan from ..elements import EmbroideryElement, Fill, AutoFill, Stroke, SatinColumn from ..utils import save_stderr, restore_stderr from ..simulator import EmbroiderySimulator +from ..commands import is_command def presets_path(): @@ -655,7 +656,7 @@ class Params(InkstitchExtension): classes.append(AutoFill) classes.append(Fill) - if element.get_style("stroke"): + if element.get_style("stroke") and not is_command(node): classes.append(Stroke) if element.get_style("stroke-dasharray") is None: diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 518a2812..6326ced2 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -2,7 +2,7 @@ import sys import shapely import networkx import math -from itertools import groupby +from itertools import groupby, izip from collections import deque from .fill import intersect_region_with_grating, row_num, stitch_row @@ -14,18 +14,38 @@ from ..utils.geometry import Point as InkstitchPoint class MaxQueueLengthExceeded(Exception): pass +class PathEdge(object): + OUTLINE_KEYS = ("outline", "extra", "initial") + SEGMENT_KEY = "segment" -def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, starting_point=None): + def __init__(self, nodes, key): + self.nodes = nodes + self._sorted_nodes = tuple(sorted(self.nodes)) + self.key = key + + def __getitem__(self, item): + return self.nodes[item] + + def __hash__(self): + return hash((self._sorted_nodes, self.key)) + + def __eq__(self, other): + return self._sorted_nodes == other._sorted_nodes and self.key == other.key + + def is_outline(self): + return self.key in self.OUTLINE_KEYS + + def is_segment(self): + return self.key == self.SEGMENT_KEY + +def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, starting_point, ending_point=None): stitches = [] rows_of_segments = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing) segments = [segment for row in rows_of_segments for segment in row] graph = build_graph(shape, segments, angle, row_spacing) - path = find_stitch_path(graph, segments) - - if starting_point: - stitches.extend(connect_points(shape, starting_point, path[0][0], running_stitch_length)) + path = find_stitch_path(graph, segments, starting_point, ending_point) stitches.extend(path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers)) @@ -134,8 +154,6 @@ def build_graph(shape, segments, angle, row_spacing): else: edge_set = 1 - #print >> sys.stderr, outline_index, "es", edge_set, "rn", row_num, inkstitch.Point(*nodes[0]) * self.north(angle), inkstitch.Point(*nodes[1]) * self.north(angle) - # add an edge between each successive node for i, (node1, node2) in enumerate(zip(nodes, nodes[1:] + [nodes[0]])): graph.add_edge(node1, node2, key="outline") @@ -157,14 +175,20 @@ def node_list_to_edge_list(node_list): def bfs_for_loop(graph, starting_node, max_queue_length=2000): to_search = deque() - to_search.appendleft(([starting_node], set(), 0)) + to_search.append((None, set())) while to_search: if len(to_search) > max_queue_length: raise MaxQueueLengthExceeded() - path, visited_edges, visited_segments = to_search.pop() - ending_node = path[-1] + path, visited_edges = to_search.pop() + + if path is None: + # This is the very first time through the loop, so initialize. + path = [] + ending_node = starting_node + else: + ending_node = path[-1][-1] # get a list of neighbors paired with the key of the edge I can follow to get there neighbors = [ @@ -178,26 +202,21 @@ def bfs_for_loop(graph, starting_node, max_queue_length=2000): for next_node, key in neighbors: # skip if I've already followed this edge - edge = (tuple(sorted((ending_node, next_node))), key) + edge = PathEdge((ending_node, next_node), key) if edge in visited_edges: continue - new_path = path + [next_node] - - if key == "segment": - new_visited_segments = visited_segments + 1 - else: - new_visited_segments = visited_segments + new_path = path + [edge] if next_node == starting_node: # ignore trivial loops (down and back a doubled edge) if len(new_path) > 3: - return node_list_to_edge_list(new_path), new_visited_segments + return new_path new_visited_edges = visited_edges.copy() new_visited_edges.add(edge) - to_search.appendleft((new_path, new_visited_edges, new_visited_segments)) + to_search.appendleft((new_path, new_visited_edges)) def find_loop(graph, starting_nodes): @@ -216,14 +235,6 @@ def find_loop(graph, starting_nodes): somewhere else. """ - #loop = self.simple_loop(graph, starting_nodes[-2]) - - #if loop: - # print >> sys.stderr, "simple_loop success" - # starting_nodes.pop() - # starting_nodes.pop() - # return loop - loop = None retry = [] max_queue_length = 2000 @@ -231,7 +242,6 @@ def find_loop(graph, starting_nodes): while not loop: while not loop and starting_nodes: starting_node = starting_nodes.pop() - #print >> sys.stderr, "find loop from", starting_node try: # Note: if bfs_for_loop() returns None, no loop can be @@ -240,12 +250,7 @@ def find_loop(graph, starting_nodes): # case we discard that node and try the next. loop = bfs_for_loop(graph, starting_node, max_queue_length) - #if not loop: - #print >> dbg, "failed on", starting_node - #dbg.flush() except MaxQueueLengthExceeded: - #print >> dbg, "gave up on", starting_node - #dbg.flush() # We're giving up on this node for now. We could try # this node again later, so add it to the bottm of the # stack. @@ -272,7 +277,7 @@ def insert_loop(path, loop): start and end point. The points will be specified in order, such that they will look like this: - ((p1, p2), (p2, p3), (p3, p4) ... (pn, p1)) + ((p1, p2), (p2, p3), (p3, p4), ...) path will be modified in place. """ @@ -282,11 +287,59 @@ def insert_loop(path, loop): for i, (start, end) in enumerate(path): if start == loop_start: break + else: + # if we didn't find the start of the loop in the list at all, it must + # be the endpoint of the last segment + i += 1 path[i:i] = loop +def nearest_node_on_outline(graph, point, outline_index=0): + point = shapely.geometry.Point(*point) + outline_nodes = [node for node, data in graph.nodes(data=True) if data['index'] == outline_index] + nearest = min(outline_nodes, key=lambda node: shapely.geometry.Point(*node).distance(point)) -def find_stitch_path(graph, segments): + return nearest + +def get_outline_nodes(graph, outline_index=0): + outline_nodes = [(node, data['projection']) \ + for node, data \ + in graph.nodes(data=True) \ + if data['index'] == outline_index] + outline_nodes.sort(key=lambda (node, projection): projection) + outline_nodes = [node for node, data in outline_nodes] + + return outline_nodes + +def find_initial_path(graph, starting_point, ending_point=None): + starting_node = nearest_node_on_outline(graph, starting_point) + + if ending_point is None: + # If they didn't give an ending point, pick either neighboring node + # along the outline -- doesn't matter which. We do this because + # the algorithm requires we start with _some_ path. + neighbors = [n for n, keys in graph.adj[starting_node].iteritems() if 'outline' in keys] + return [PathEdge((starting_node, neighbors[0]), "initial")] + else: + ending_node = nearest_node_on_outline(graph, ending_point) + outline_nodes = get_outline_nodes(graph) + + # Multiply the outline_nodes list by 2 (duplicate it) because + # the ending_node may occur first. + outline_nodes *= 2 + start_index = outline_nodes.index(starting_node) + end_index = outline_nodes.index(ending_node, start_index) + nodes = outline_nodes[start_index:end_index + 1] + + # we have a series of sequential points, but we need to + # turn it into an edge list + path = [] + for start, end in izip(nodes[:-1], nodes[1:]): + path.append(PathEdge((start, end), "initial")) + + return path + +def find_stitch_path(graph, segments, starting_point=None, ending_point=None): """find a path that visits every grating segment exactly once Theoretically, we just need to find an Eulerian Path in the graph. @@ -294,13 +347,14 @@ def find_stitch_path(graph, segments): The edges on the outline of the region are only there to help us get from one grating segment to the next. - We'll build a "cycle" (a path that ends where it starts) using - Hierholzer's algorithm. We'll stop once we've visited every grating - segment. + We'll build a Eulerian Path using Hierholzer's algorithm. A true + Eulerian Path would visit every single edge (including all the extras + we inserted in build_graph()),but we'll stop short once we've visited + every grating segment since that's all we really care about. Hierholzer's algorithm says to select an arbitrary starting node at each step. In order to produce a reasonable stitch path, we'll select - the vertex carefully such that we get back-and-forth traversal like + the starting node carefully such that we get back-and-forth traversal like mowing a lawn. To do this, we'll use a simple heuristic: try to start from nodes in @@ -313,40 +367,42 @@ def find_stitch_path(graph, segments): segments_visited = 0 nodes_visited = deque() - # start with a simple loop: down one segment and then back along the - # outer border to the starting point. - path = [segments[0], list(reversed(segments[0]))] + if starting_point is None: + starting_point = segments[0][0] + + path = find_initial_path(graph, starting_point, ending_point) - graph.remove_edges_from(path) + # Our graph is Eulerian: every node has an even degree. An Eulerian graph + # must have an Eulerian Circuit which visits every edge and ends where it + # starts. + # + # However, we're starting with a path and _not_ removing the edges of that + # path from the graph. By doing this, we're implicitly adding those edges + # to the graph, after which the starting and ending point (and only those + # two) will now have odd degree. A graph that's Eulerian except for two + # nodes must have an Eulerian Path that starts and ends at those two nodes. + # That's how we force the starting and ending point. - segments_visited += 1 - nodes_visited.extend(segments[0]) + nodes_visited.append(path[0][0]) while segments_visited < num_segments: - result = find_loop(graph, nodes_visited) + loop = find_loop(graph, nodes_visited) - if not result: + if not loop: print >> sys.stderr, _("Unexpected error while generating fill stitches. Please send your SVG file to lexelby@github.") break - loop, segments = result - - #print >> dbg, "found loop:", loop - #dbg.flush() - - segments_visited += segments - nodes_visited += [edge[0] for edge in loop] + segments_visited += sum(1 for edge in loop if edge.is_segment()) + nodes_visited.extend(edge[0] for edge in loop) graph.remove_edges_from(loop) insert_loop(path, loop) - #if segments_visited >= 12: - # break - - # Now we have a loop that covers every grating segment. It returns to - # where it started, which is unnecessary, so we'll snip the last bit off. - #while original_graph.has_edge(*path[-1], key="outline"): - # path.pop() + if ending_point is None: + # If they didn't specify an ending point, then the end of the path travels + # around the outline back to the start (see find_initial_path()). This + # isn't necessary, so remove it. + trim_end(path) return path @@ -363,10 +419,10 @@ def collapse_sequential_outline_edges(graph, path): new_path = [] for edge in path: - if graph.has_edge(*edge, key="segment"): + if edge.is_segment(): if start_of_run: # close off the last run - new_path.append((start_of_run, edge[0])) + new_path.append(PathEdge((start_of_run, edge[0]), "collapsed")) start_of_run = None new_path.append(edge) @@ -376,7 +432,7 @@ def collapse_sequential_outline_edges(graph, path): if start_of_run: # if we were still in a run, close it off - new_path.append((start_of_run, edge[1])) + new_path.append(PathEdge((start_of_run, edge[1]), "collapsed")) return new_path @@ -416,9 +472,6 @@ def connect_points(shape, start, end, running_stitch_length): direction = math.copysign(1.0, distance) one_stitch = running_stitch_length * direction - #print >> dbg, "connect_points:", outline_index, start, end, distance, stitches, direction - #dbg.flush() - stitches = [InkstitchPoint(*outline.interpolate(pos).coords[0])] for i in xrange(num_stitches): @@ -430,11 +483,11 @@ def connect_points(shape, start, end, running_stitch_length): if (end - stitches[-1]).length() > 0.1 * PIXELS_PER_MM: stitches.append(end) - #print >> dbg, "end connect_points" - #dbg.flush() - return stitches +def trim_end(path): + while path and path[-1].is_outline(): + path.pop() def path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers): path = collapse_sequential_outline_edges(graph, path) @@ -442,7 +495,7 @@ def path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, stitches = [] for edge in path: - if graph.has_edge(*edge, key="segment"): + if edge.is_segment(): stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers) else: stitches.extend(connect_points(shape, edge[0], edge[1], running_stitch_length)) diff --git a/lib/svg/__init__.py b/lib/svg/__init__.py index 1895bba4..50543b1b 100644 --- a/lib/svg/__init__.py +++ b/lib/svg/__init__.py @@ -1,2 +1,3 @@ from .svg import color_block_to_point_lists, render_stitch_plan from .units import * +from .path import apply_transforms diff --git a/lib/svg/path.py b/lib/svg/path.py new file mode 100644 index 00000000..a8012774 --- /dev/null +++ b/lib/svg/path.py @@ -0,0 +1,20 @@ +import simpletransform +import cubicsuperpath + +from .units import get_viewbox_transform + +def apply_transforms(path, node): + # start with the identity transform + transform = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] + + # combine this node's transform with all parent groups' transforms + transform = simpletransform.composeParents(node, transform) + + # add in the transform implied by the viewBox + viewbox_transform = get_viewbox_transform(node.getroottree().getroot()) + transform = simpletransform.composeTransform(viewbox_transform, transform) + + # apply the combined transform to this node's path + simpletransform.applyTransformToPath(transform, path) + + return path diff --git a/lib/svg/tags.py b/lib/svg/tags.py index fee59957..5488608c 100644 --- a/lib/svg/tags.py +++ b/lib/svg/tags.py @@ -5,8 +5,13 @@ SVG_PATH_TAG = inkex.addNS('path', 'svg') SVG_POLYLINE_TAG = inkex.addNS('polyline', 'svg') SVG_DEFS_TAG = inkex.addNS('defs', 'svg') SVG_GROUP_TAG = inkex.addNS('g', 'svg') +SVG_SYMBOL_TAG = inkex.addNS('symbol', 'svg') +SVG_USE_TAG = inkex.addNS('use', 'svg') INKSCAPE_LABEL = inkex.addNS('label', 'inkscape') INKSCAPE_GROUPMODE = inkex.addNS('groupmode', 'inkscape') +CONNECTION_START = inkex.addNS('connection-start', 'inkscape') +CONNECTION_END = inkex.addNS('connection-end', 'inkscape') +XLINK_HREF = inkex.addNS('href', 'xlink') EMBROIDERABLE_TAGS = (SVG_PATH_TAG, SVG_POLYLINE_TAG) diff --git a/messages.po b/messages.po index fb081eb1..d6f156f2 100644 --- a/messages.po +++ b/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2018-06-16 22:33-0400\n" +"POT-Creation-Date: 2018-06-28 20:32-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -47,6 +47,10 @@ msgstr "" msgid "Expand" msgstr "" +#, python-format +msgid "%(id)s has more than one command of type '%(command)s' linked to it" +msgstr "" + msgid "TRIM after" msgstr "" @@ -194,10 +198,16 @@ msgid "" "Seeing a 'no such option' message? Please restart Inkscape to fix." msgstr "" -msgid "Directory in which to install palettes:" +msgid "" +"Ink/Stitch can install files (\"add-ons\") that make it easier to use " +"Inkscape to create machine embroidery designs. These add-ons will be " +"installed:" +msgstr "" + +msgid "thread manufacturer color palettes" msgstr "" -msgid "Choose another directory..." +msgid "Ink/Stitch visual commands (Object -> Symbols...)" msgstr "" msgid "Install" @@ -206,24 +216,24 @@ msgstr "" msgid "Cancel" msgstr "" -msgid "Choose Inkscape palettes directory" +msgid "Choose Inkscape directory" msgstr "" -msgid "Thread palette installation failed" +msgid "Inkscape add-on installation failed" msgstr "" msgid "Installation Failed" msgstr "" msgid "" -"Thread palette files have been installed. Please restart Inkscape to " -"load the new palettes." +"Inkscape add-on files have been installed. Please restart Inkscape to " +"load the new add-ons." msgstr "" msgid "Installation Completed" msgstr "" -msgid "Ink/Stitch Thread Palette Installer" +msgid "Ink/Stitch Add-ons Installer" msgstr "" msgid "These settings will be applied to 1 object." diff --git a/palettes/ARC Polyester.gpl b/palettes/InkStitch ARC Polyester.gpl index a9d2b2cd..a9d2b2cd 100644 --- a/palettes/ARC Polyester.gpl +++ b/palettes/InkStitch ARC Polyester.gpl diff --git a/palettes/ARC Rayon.gpl b/palettes/InkStitch ARC Rayon.gpl index 909aebb2..909aebb2 100644 --- a/palettes/ARC Rayon.gpl +++ b/palettes/InkStitch ARC Rayon.gpl diff --git a/palettes/Admelody Polyester.gpl b/palettes/InkStitch Admelody Polyester.gpl index 1bad74a3..1bad74a3 100644 --- a/palettes/Admelody Polyester.gpl +++ b/palettes/InkStitch Admelody Polyester.gpl diff --git a/palettes/Admelody Rayon.gpl b/palettes/InkStitch Admelody Rayon.gpl index d80ec7fb..d80ec7fb 100644 --- a/palettes/Admelody Rayon.gpl +++ b/palettes/InkStitch Admelody Rayon.gpl diff --git a/palettes/Anchor.gpl b/palettes/InkStitch Anchor.gpl index 96a88b2f..96a88b2f 100644 --- a/palettes/Anchor.gpl +++ b/palettes/InkStitch Anchor.gpl diff --git a/palettes/Aurifil Lana.gpl b/palettes/InkStitch Aurifil Lana.gpl index 81180771..81180771 100644 --- a/palettes/Aurifil Lana.gpl +++ b/palettes/InkStitch Aurifil Lana.gpl diff --git a/palettes/Aurifil Mako.gpl b/palettes/InkStitch Aurifil Mako.gpl index b8ed79af..b8ed79af 100644 --- a/palettes/Aurifil Mako.gpl +++ b/palettes/InkStitch Aurifil Mako.gpl diff --git a/palettes/Aurifil Polyester.gpl b/palettes/InkStitch Aurifil Polyester.gpl index 6a8ead87..6a8ead87 100644 --- a/palettes/Aurifil Polyester.gpl +++ b/palettes/InkStitch Aurifil Polyester.gpl diff --git a/palettes/Aurifil Rayon.gpl b/palettes/InkStitch Aurifil Rayon.gpl index bf608c9a..bf608c9a 100644 --- a/palettes/Aurifil Rayon.gpl +++ b/palettes/InkStitch Aurifil Rayon.gpl diff --git a/palettes/Aurifil Royal.gpl b/palettes/InkStitch Aurifil Royal.gpl index d997298f..d997298f 100644 --- a/palettes/Aurifil Royal.gpl +++ b/palettes/InkStitch Aurifil Royal.gpl diff --git a/palettes/BFC Polyester.gpl b/palettes/InkStitch BFC Polyester.gpl index 766f104f..766f104f 100644 --- a/palettes/BFC Polyester.gpl +++ b/palettes/InkStitch BFC Polyester.gpl diff --git a/palettes/Brildor AC.gpl b/palettes/InkStitch Brildor AC.gpl index 114638e6..114638e6 100644 --- a/palettes/Brildor AC.gpl +++ b/palettes/InkStitch Brildor AC.gpl diff --git a/palettes/Brildor CO.gpl b/palettes/InkStitch Brildor CO.gpl index 4f7e8dc3..4f7e8dc3 100644 --- a/palettes/Brildor CO.gpl +++ b/palettes/InkStitch Brildor CO.gpl diff --git a/palettes/Brildor MF.gpl b/palettes/InkStitch Brildor MF.gpl index 588e3687..588e3687 100644 --- a/palettes/Brildor MF.gpl +++ b/palettes/InkStitch Brildor MF.gpl diff --git a/palettes/Brildor NY.gpl b/palettes/InkStitch Brildor NY.gpl index 68faab6b..68faab6b 100644 --- a/palettes/Brildor NY.gpl +++ b/palettes/InkStitch Brildor NY.gpl diff --git a/palettes/Brildor PB.gpl b/palettes/InkStitch Brildor PB.gpl index 60ccae7f..60ccae7f 100644 --- a/palettes/Brildor PB.gpl +++ b/palettes/InkStitch Brildor PB.gpl diff --git a/palettes/Brother Country.gpl b/palettes/InkStitch Brother Country.gpl index c15e8989..c15e8989 100644 --- a/palettes/Brother Country.gpl +++ b/palettes/InkStitch Brother Country.gpl diff --git a/palettes/Brother Embroidery.gpl b/palettes/InkStitch Brother Embroidery.gpl index 915989ed..915989ed 100644 --- a/palettes/Brother Embroidery.gpl +++ b/palettes/InkStitch Brother Embroidery.gpl diff --git a/palettes/Coats Alcazar Jazz.gpl b/palettes/InkStitch Coats Alcazar Jazz.gpl index f9cd6c9d..f9cd6c9d 100644 --- a/palettes/Coats Alcazar Jazz.gpl +++ b/palettes/InkStitch Coats Alcazar Jazz.gpl diff --git a/palettes/Coats Alcazar.gpl b/palettes/InkStitch Coats Alcazar.gpl index e1891b03..e1891b03 100644 --- a/palettes/Coats Alcazar.gpl +++ b/palettes/InkStitch Coats Alcazar.gpl diff --git a/palettes/Coats Sylko USA.gpl b/palettes/InkStitch Coats Sylko USA.gpl index af220f69..af220f69 100644 --- a/palettes/Coats Sylko USA.gpl +++ b/palettes/InkStitch Coats Sylko USA.gpl diff --git a/palettes/Coats Sylko.gpl b/palettes/InkStitch Coats Sylko.gpl index 50960152..50960152 100644 --- a/palettes/Coats Sylko.gpl +++ b/palettes/InkStitch Coats Sylko.gpl diff --git a/palettes/DMC.gpl b/palettes/InkStitch DMC.gpl index 38d68bc8..38d68bc8 100644 --- a/palettes/DMC.gpl +++ b/palettes/InkStitch DMC.gpl diff --git a/palettes/Embroidex.gpl b/palettes/InkStitch Embroidex.gpl index 06d75f75..06d75f75 100644 --- a/palettes/Embroidex.gpl +++ b/palettes/InkStitch Embroidex.gpl diff --git a/palettes/Emmel.gpl b/palettes/InkStitch Emmel.gpl index 908ab78f..908ab78f 100644 --- a/palettes/Emmel.gpl +++ b/palettes/InkStitch Emmel.gpl diff --git a/palettes/Fil-Tec Glide.gpl b/palettes/InkStitch Fil-Tec Glide.gpl index 7e7d30c0..7e7d30c0 100644 --- a/palettes/Fil-Tec Glide.gpl +++ b/palettes/InkStitch Fil-Tec Glide.gpl diff --git a/palettes/Floriani Polyester.gpl b/palettes/InkStitch Floriani Polyester.gpl index 36f76390..36f76390 100644 --- a/palettes/Floriani Polyester.gpl +++ b/palettes/InkStitch Floriani Polyester.gpl diff --git a/palettes/FuFu Polyester.gpl b/palettes/InkStitch FuFu Polyester.gpl index fe7cb8f6..fe7cb8f6 100644 --- a/palettes/FuFu Polyester.gpl +++ b/palettes/InkStitch FuFu Polyester.gpl diff --git a/palettes/FuFu Rayon.gpl b/palettes/InkStitch FuFu Rayon.gpl index 2f649173..2f649173 100644 --- a/palettes/FuFu Rayon.gpl +++ b/palettes/InkStitch FuFu Rayon.gpl diff --git a/palettes/Gunold.gpl b/palettes/InkStitch Gunold.gpl index efa91272..efa91272 100644 --- a/palettes/Gunold.gpl +++ b/palettes/InkStitch Gunold.gpl diff --git a/palettes/Gutermann Creativ Dekor.gpl b/palettes/InkStitch Gutermann Creativ Dekor.gpl index aec5e3f1..aec5e3f1 100644 --- a/palettes/Gutermann Creativ Dekor.gpl +++ b/palettes/InkStitch Gutermann Creativ Dekor.gpl diff --git a/palettes/Hemingworth.gpl b/palettes/InkStitch Hemingworth.gpl index 23438122..23438122 100644 --- a/palettes/Hemingworth.gpl +++ b/palettes/InkStitch Hemingworth.gpl diff --git a/palettes/Isacord Polyester.gpl b/palettes/InkStitch Isacord Polyester.gpl index a0e14c95..a0e14c95 100644 --- a/palettes/Isacord Polyester.gpl +++ b/palettes/InkStitch Isacord Polyester.gpl diff --git a/palettes/Isafil Rayon.gpl b/palettes/InkStitch Isafil Rayon.gpl index 5e82a6d8..5e82a6d8 100644 --- a/palettes/Isafil Rayon.gpl +++ b/palettes/InkStitch Isafil Rayon.gpl diff --git a/palettes/Isalon Polyester.gpl b/palettes/InkStitch Isalon Polyester.gpl index 5374bba2..5374bba2 100644 --- a/palettes/Isalon Polyester.gpl +++ b/palettes/InkStitch Isalon Polyester.gpl diff --git a/palettes/Janome.gpl b/palettes/InkStitch Janome.gpl index 44113b29..44113b29 100644 --- a/palettes/Janome.gpl +++ b/palettes/InkStitch Janome.gpl diff --git a/palettes/King Star.gpl b/palettes/InkStitch King Star.gpl index bf2020c1..bf2020c1 100644 --- a/palettes/King Star.gpl +++ b/palettes/InkStitch King Star.gpl diff --git a/palettes/MTB - Embroidex.gpl b/palettes/InkStitch MTB - Embroidex.gpl index 378f92fd..378f92fd 100644 --- a/palettes/MTB - Embroidex.gpl +++ b/palettes/InkStitch MTB - Embroidex.gpl diff --git a/palettes/Madeira Burmilana.gpl b/palettes/InkStitch Madeira Burmilana.gpl index 996c9963..996c9963 100644 --- a/palettes/Madeira Burmilana.gpl +++ b/palettes/InkStitch Madeira Burmilana.gpl diff --git a/palettes/Madeira Matt.gpl b/palettes/InkStitch Madeira Matt.gpl index 47973362..47973362 100644 --- a/palettes/Madeira Matt.gpl +++ b/palettes/InkStitch Madeira Matt.gpl diff --git a/palettes/Madeira Polyneon.gpl b/palettes/InkStitch Madeira Polyneon.gpl index 065330eb..065330eb 100644 --- a/palettes/Madeira Polyneon.gpl +++ b/palettes/InkStitch Madeira Polyneon.gpl diff --git a/palettes/Madeira Rayon.gpl b/palettes/InkStitch Madeira Rayon.gpl index 8f85b628..8f85b628 100644 --- a/palettes/Madeira Rayon.gpl +++ b/palettes/InkStitch Madeira Rayon.gpl diff --git a/palettes/Marathon Polyester.gpl b/palettes/InkStitch Marathon Polyester.gpl index 4bae92d1..4bae92d1 100644 --- a/palettes/Marathon Polyester.gpl +++ b/palettes/InkStitch Marathon Polyester.gpl diff --git a/palettes/Marathon Rayon V3.gpl b/palettes/InkStitch Marathon Rayon V3.gpl index 31eb396d..31eb396d 100644 --- a/palettes/Marathon Rayon V3.gpl +++ b/palettes/InkStitch Marathon Rayon V3.gpl diff --git a/palettes/Marathon Rayon.gpl b/palettes/InkStitch Marathon Rayon.gpl index c70f8646..c70f8646 100644 --- a/palettes/Marathon Rayon.gpl +++ b/palettes/InkStitch Marathon Rayon.gpl diff --git a/palettes/Metro.gpl b/palettes/InkStitch Metro.gpl index 9ba6dd2d..9ba6dd2d 100644 --- a/palettes/Metro.gpl +++ b/palettes/InkStitch Metro.gpl diff --git a/palettes/Mettler Embroidery.gpl b/palettes/InkStitch Mettler Embroidery.gpl index 5a7993b9..5a7993b9 100644 --- a/palettes/Mettler Embroidery.gpl +++ b/palettes/InkStitch Mettler Embroidery.gpl diff --git a/palettes/Mettler Poly Sheen.gpl b/palettes/InkStitch Mettler Poly Sheen.gpl index d1d91fa8..d1d91fa8 100644 --- a/palettes/Mettler Poly Sheen.gpl +++ b/palettes/InkStitch Mettler Poly Sheen.gpl diff --git a/palettes/Outback Embroidery Rayon.gpl b/palettes/InkStitch Outback Embroidery Rayon.gpl index 3344ecc5..3344ecc5 100644 --- a/palettes/Outback Embroidery Rayon.gpl +++ b/palettes/InkStitch Outback Embroidery Rayon.gpl diff --git a/palettes/Poly X40.gpl b/palettes/InkStitch Poly X40.gpl index c8336589..c8336589 100644 --- a/palettes/Poly X40.gpl +++ b/palettes/InkStitch Poly X40.gpl diff --git a/palettes/Princess.gpl b/palettes/InkStitch Princess.gpl index 237fcb9e..237fcb9e 100644 --- a/palettes/Princess.gpl +++ b/palettes/InkStitch Princess.gpl diff --git a/palettes/RAL.gpl b/palettes/InkStitch RAL.gpl index 22028e0a..22028e0a 100644 --- a/palettes/RAL.gpl +++ b/palettes/InkStitch RAL.gpl diff --git a/palettes/Radiant Rayon.gpl b/palettes/InkStitch Radiant Rayon.gpl index 428a9d17..428a9d17 100644 --- a/palettes/Radiant Rayon.gpl +++ b/palettes/InkStitch Radiant Rayon.gpl diff --git a/palettes/Robison-Anton Polyester.gpl b/palettes/InkStitch Robison-Anton Polyester.gpl index 4899053e..4899053e 100644 --- a/palettes/Robison-Anton Polyester.gpl +++ b/palettes/InkStitch Robison-Anton Polyester.gpl diff --git a/palettes/Robison-Anton Rayon.gpl b/palettes/InkStitch Robison-Anton Rayon.gpl index d2db91ec..d2db91ec 100644 --- a/palettes/Robison-Anton Rayon.gpl +++ b/palettes/InkStitch Robison-Anton Rayon.gpl diff --git a/palettes/Royal Polyester.gpl b/palettes/InkStitch Royal Polyester.gpl index efc142d6..efc142d6 100644 --- a/palettes/Royal Polyester.gpl +++ b/palettes/InkStitch Royal Polyester.gpl diff --git a/palettes/Royal Viscose Rayon.gpl b/palettes/InkStitch Royal Viscose Rayon.gpl index 375e588a..375e588a 100644 --- a/palettes/Royal Viscose Rayon.gpl +++ b/palettes/InkStitch Royal Viscose Rayon.gpl diff --git a/palettes/Sigma.gpl b/palettes/InkStitch Sigma.gpl index 0c95201c..0c95201c 100644 --- a/palettes/Sigma.gpl +++ b/palettes/InkStitch Sigma.gpl diff --git a/palettes/Simthread Polyester.gpl b/palettes/InkStitch Simthread Polyester.gpl index aae11d37..aae11d37 100644 --- a/palettes/Simthread Polyester.gpl +++ b/palettes/InkStitch Simthread Polyester.gpl diff --git a/palettes/Simthread Rayon.gpl b/palettes/InkStitch Simthread Rayon.gpl index ec166d59..ec166d59 100644 --- a/palettes/Simthread Rayon.gpl +++ b/palettes/InkStitch Simthread Rayon.gpl diff --git a/palettes/Sulky Polyester.gpl b/palettes/InkStitch Sulky Polyester.gpl index 10ebb5f2..10ebb5f2 100644 --- a/palettes/Sulky Polyester.gpl +++ b/palettes/InkStitch Sulky Polyester.gpl diff --git a/palettes/Sulky Rayon.gpl b/palettes/InkStitch Sulky Rayon.gpl index a30e11db..a30e11db 100644 --- a/palettes/Sulky Rayon.gpl +++ b/palettes/InkStitch Sulky Rayon.gpl diff --git a/palettes/Swist Rayon.gpl b/palettes/InkStitch Swist Rayon.gpl index 2e6a90e7..2e6a90e7 100644 --- a/palettes/Swist Rayon.gpl +++ b/palettes/InkStitch Swist Rayon.gpl diff --git a/palettes/Tristar Polyester.gpl b/palettes/InkStitch Tristar Polyester.gpl index f3a9f642..f3a9f642 100644 --- a/palettes/Tristar Polyester.gpl +++ b/palettes/InkStitch Tristar Polyester.gpl diff --git a/palettes/Tristar Rayon.gpl b/palettes/InkStitch Tristar Rayon.gpl index 1b0954be..1b0954be 100644 --- a/palettes/Tristar Rayon.gpl +++ b/palettes/InkStitch Tristar Rayon.gpl diff --git a/palettes/Viking Palette.gpl b/palettes/InkStitch Viking Palette.gpl index f25af56f..f25af56f 100644 --- a/palettes/Viking Palette.gpl +++ b/palettes/InkStitch Viking Palette.gpl diff --git a/palettes/Vyapar Rayon.gpl b/palettes/InkStitch Vyapar Rayon.gpl index 4a846cab..4a846cab 100644 --- a/palettes/Vyapar Rayon.gpl +++ b/palettes/InkStitch Vyapar Rayon.gpl diff --git a/palettes/Wonderfil Polyester.gpl b/palettes/InkStitch Wonderfil Polyester.gpl index 0430d4a1..0430d4a1 100644 --- a/palettes/Wonderfil Polyester.gpl +++ b/palettes/InkStitch Wonderfil Polyester.gpl diff --git a/palettes/Wonderfil Rayon.gpl b/palettes/InkStitch Wonderfil Rayon.gpl index 28e82005..28e82005 100644 --- a/palettes/Wonderfil Rayon.gpl +++ b/palettes/InkStitch Wonderfil Rayon.gpl diff --git a/symbols/inkstitch.svg b/symbols/inkstitch.svg new file mode 100644 index 00000000..2af52d92 --- /dev/null +++ b/symbols/inkstitch.svg @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100mm" + height="100mm" + viewBox="0 0 377.95276 377.95276" + id="svg8375" + version="1.1" + inkscape:version="0.92.3 (unknown)" + sodipodi:docname="inkstitch.svg"> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2" + inkscape:cx="64.500275" + inkscape:cy="322.07765" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="mm" + inkscape:window-width="1366" + inkscape:window-height="705" + inkscape:window-x="-4" + inkscape:window-y="-4" + inkscape:window-maximized="1" + inkscape:measure-start="128.23,226.536" + inkscape:measure-end="114.217,226.536" + inkscape:snap-global="false" + showguides="false"> + <inkscape:grid + empspacing="2" + opacity="0.1254902" + color="#f03fff" + spacingy="18.897638" + spacingx="18.897638" + units="mm" + id="grid5001" + type="xygrid" /> + </sodipodi:namedview> + <title + id="title9425">Ink/Stitch Commands</title> + <defs + id="defs8377"> + <symbol + id="inkstitch_fill_end"> + <title + id="title9427">Fill stitch starting point</title> + <circle + inkscape:label="outline" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" + id="circle13166" + cx="47.235394" + cy="105.91732" + r="9.2465534" /> + <path + inkscape:connector-curvature="0" + id="rect5371-2" + d="m 42.691395,101.26765 h 9.140878 v 9.14087 h -9.140878 z" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60622311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.81866985, 4.81866985;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" /> + </symbol> + <symbol + id="inkstitch_fill_start"> + <title + id="title9432">Fill stitch ending point</title> + <circle + inkscape:label="outline" + style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06501234;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19503705, 3.19503705;stroke-dashoffset:0;stroke-opacity:1" + id="circle13166-6" + cx="85.223907" + cy="106.13256" + r="9.2465534" /> + <path + inkscape:connector-curvature="0" + id="path4183" + d="m 91.796747,106.13612 -10.4514,6.03412 v -12.06823 z" + inkscape:transform-center-y="3.0183984e-06" + inkscape:transform-center-x="-1.7419043" + style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.74180555;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + </symbol> + </defs> + <metadata + id="metadata8380"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + style="display:inline" + transform="translate(0,-58.409503)" + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Layer 1"> + <use + xlink:href="#inkstitch_fill_end" + id="use18860" + x="0" + y="0" + width="100%" + height="100%" /> + <use + xlink:href="#inkstitch_fill_start" + id="use18871" + x="0" + y="0" + width="100%" + height="100%" /> + </g> +</svg> |
