diff options
Diffstat (limited to 'share/extensions')
208 files changed, 11360 insertions, 3806 deletions
diff --git a/share/extensions/Barcode/Base.py b/share/extensions/Barcode/Base.py index 4ba89d2d6..398e877e9 100644 --- a/share/extensions/Barcode/Base.py +++ b/share/extensions/Barcode/Base.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/Code128.py b/share/extensions/Barcode/Code128.py index 2f0b327ed..3cb79b487 100644 --- a/share/extensions/Barcode/Code128.py +++ b/share/extensions/Barcode/Code128.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/Code39.py b/share/extensions/Barcode/Code39.py index 650d27d95..78c8521f1 100644 --- a/share/extensions/Barcode/Code39.py +++ b/share/extensions/Barcode/Code39.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/Code39Ext.py b/share/extensions/Barcode/Code39Ext.py index d1682a641..23c0d6a46 100644 --- a/share/extensions/Barcode/Code39Ext.py +++ b/share/extensions/Barcode/Code39Ext.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/Code93.py b/share/extensions/Barcode/Code93.py index d5646a1a3..03c31adf1 100644 --- a/share/extensions/Barcode/Code93.py +++ b/share/extensions/Barcode/Code93.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/EAN13.py b/share/extensions/Barcode/EAN13.py index c79b7749d..a7029d982 100644 --- a/share/extensions/Barcode/EAN13.py +++ b/share/extensions/Barcode/EAN13.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/EAN5.py b/share/extensions/Barcode/EAN5.py index 9113566a3..8a93b497b 100644 --- a/share/extensions/Barcode/EAN5.py +++ b/share/extensions/Barcode/EAN5.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens Copyright (C) 2009 Aaron C Spike diff --git a/share/extensions/Barcode/EAN8.py b/share/extensions/Barcode/EAN8.py index e0534ecc5..e51cfa93a 100644 --- a/share/extensions/Barcode/EAN8.py +++ b/share/extensions/Barcode/EAN8.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/RM4CC.py b/share/extensions/Barcode/RM4CC.py index 7b5f54ee1..22902f2e4 100644 --- a/share/extensions/Barcode/RM4CC.py +++ b/share/extensions/Barcode/RM4CC.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/UPCA.py b/share/extensions/Barcode/UPCA.py index 89c97eed6..15d189daa 100644 --- a/share/extensions/Barcode/UPCA.py +++ b/share/extensions/Barcode/UPCA.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/UPCE.py b/share/extensions/Barcode/UPCE.py index b41e94e8c..2065cfae9 100644 --- a/share/extensions/Barcode/UPCE.py +++ b/share/extensions/Barcode/UPCE.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/Barcode/__init__.py b/share/extensions/Barcode/__init__.py index b2257ebcb..281702c1e 100644 --- a/share/extensions/Barcode/__init__.py +++ b/share/extensions/Barcode/__init__.py @@ -1,4 +1,4 @@ - +#!/usr/bin/env python ''' Barcodes SVG Extention diff --git a/share/extensions/Makefile.am b/share/extensions/Makefile.am index 78532f939..f735f2ff2 100644 --- a/share/extensions/Makefile.am +++ b/share/extensions/Makefile.am @@ -62,11 +62,13 @@ extensions = \ fractalize.py \ funcplot.py \ gears.py\ + gcodetools.py\ generate_voronoi.py \ gimp_xcf.py \ grid_cartesian.py \ grid_polar.py \ guides_creator.py \ + guillotine.py \ handles.py \ hpgl_output.py \ ill2svg.pl \ @@ -112,9 +114,11 @@ extensions = \ ps2pdf-ext.py \ pturtle.py \ radiusrand.py \ + replace_font.py \ restack.py \ render_barcode.py \ render_barcode_datamatrix.py \ + render_barcode_qrcode.py \ render_alphabetsoup.py \ render_alphabetsoup_config.py \ rtree.py \ @@ -216,11 +220,21 @@ modules = \ fractalize.inx \ funcplot.inx \ gears.inx\ + gcodetools_all_in_one.inx\ + gcodetools_area.inx\ + gcodetools_check_for_updates.inx\ + gcodetools_dxf_points.inx\ + gcodetools_engraving.inx\ + gcodetools_lathe.inx\ + gcodetools_orientation_points.inx\ + gcodetools_path_to_gcode.inx\ + gcodetools_tools_library.inx\ generate_voronoi.inx \ gimp_xcf.inx \ grid_cartesian.inx \ grid_polar.inx \ guides_creator.inx \ + guillotine.inx \ handles.inx \ hpgl_output.inx \ inkscape_help_askaquestion.inx \ @@ -265,7 +279,9 @@ modules = \ radiusrand.inx \ render_barcode.inx \ render_barcode_datamatrix.inx \ + render_barcode_qrcode.inx \ render_alphabetsoup.inx \ + replace_font.inx \ restack.inx \ rubberstretch.inx \ rtree.inx \ diff --git a/share/extensions/SpSVG.pm b/share/extensions/SpSVG.pm index b3f7ed09f..5976d6d97 100644 --- a/share/extensions/SpSVG.pm +++ b/share/extensions/SpSVG.pm @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl -w # # SpSVG # diff --git a/share/extensions/addnodes.inx b/share/extensions/addnodes.inx index f260f3df4..b61d0a92d 100644 --- a/share/extensions/addnodes.inx +++ b/share/extensions/addnodes.inx @@ -4,12 +4,12 @@ <id>org.ekips.filter.addnodes</id> <dependency type="executable" location="extensions">addnodes.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="method" type="optiongroup" _gui-text="Division method"> - <_option value="bymax">By max. segment length</_option> - <_option value="bynum">By number of segments</_option> + <param name="method" type="enum" _gui-text="Division method:"> + <_item value="bymax">By max. segment length</_item> + <_item value="bynum">By number of segments</_item> </param> - <param name="max" type="float" min="0.1" max="10000.0" _gui-text="Maximum segment length (px)">10.0</param> - <param name="segments" type="int" min="1" max="1000" _gui-text="Number of segments">2</param> + <param name="max" type="float" min="0.1" max="10000.0" _gui-text="Maximum segment length (px):">10.0</param> + <param name="segments" type="int" min="1" max="1000" _gui-text="Number of segments:">2</param> <effect needs-live-preview="false"> <object-type>path</object-type> <effects-menu> diff --git a/share/extensions/addnodes.py b/share/extensions/addnodes.py index 3a8bebe66..d78ab55e7 100644 --- a/share/extensions/addnodes.py +++ b/share/extensions/addnodes.py @@ -113,4 +113,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/aisvg.xslt b/share/extensions/aisvg.xslt index 62a10ee93..2faebc7f3 100644 --- a/share/extensions/aisvg.xslt +++ b/share/extensions/aisvg.xslt @@ -1,36 +1,36 @@ -<?xml version="1.0"?>
-<xsl:stylesheet xml:space="default" version="1.0"
-xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-xmlns="http://www.w3.org/2000/svg"
-xmlns:svg="http://www.w3.org/2000/svg"
-xmlns:xlink="http://www.w3.org/1999/xlink"
-xmlns:x="http://ns.adobe.com/Extensibility/1.0/"
-xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
-xmlns:graph="http://ns.adobe.com/Graphs/1.0/"
-xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
-xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
->
-<xsl:output indent="yes"/>
- <xsl:template match="/">
- <xsl:apply-templates />
- </xsl:template>
- <xsl:template match="svg:svg/svg:switch[count(*)=2][name(*[1])='foreignObject']">
- <xsl:apply-templates select="*[not(name()='foreignObject')]/*"/>
- </xsl:template>
- <xsl:template match="svg:svg/svg:g | svg:g[@i:extraneous='self']/svg:g">
- <xsl:copy>
- <xsl:attribute name="inkscape:groupmode">layer</xsl:attribute>
- <xsl:apply-templates select="@*|*"/>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="*">
- <xsl:copy>
- <xsl:apply-templates select="@*|node()|text"/>
- </xsl:copy>
- </xsl:template>
- <xsl:template match="@*">
- <xsl:copy/>
- </xsl:template>
- <xsl:template match="i:*|@i:*|x:*|@x:*|graph:*|@graph:*|a:*|@a:*">
- </xsl:template>
-</xsl:stylesheet>
+<?xml version="1.0"?> +<xsl:stylesheet xml:space="default" version="1.0" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +xmlns="http://www.w3.org/2000/svg" +xmlns:svg="http://www.w3.org/2000/svg" +xmlns:xlink="http://www.w3.org/1999/xlink" +xmlns:x="http://ns.adobe.com/Extensibility/1.0/" +xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" +xmlns:graph="http://ns.adobe.com/Graphs/1.0/" +xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" +xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +> +<xsl:output indent="yes"/> + <xsl:template match="/"> + <xsl:apply-templates /> + </xsl:template> + <xsl:template match="svg:svg/svg:switch[count(*)=2][name(*[1])='foreignObject']"> + <xsl:apply-templates select="*[not(name()='foreignObject')]/*"/> + </xsl:template> + <xsl:template match="svg:svg/svg:g | svg:g[@i:extraneous='self']/svg:g"> + <xsl:copy> + <xsl:attribute name="inkscape:groupmode">layer</xsl:attribute> + <xsl:apply-templates select="@*|*"/> + </xsl:copy> + </xsl:template> + <xsl:template match="*"> + <xsl:copy> + <xsl:apply-templates select="@*|node()|text"/> + </xsl:copy> + </xsl:template> + <xsl:template match="@*"> + <xsl:copy/> + </xsl:template> + <xsl:template match="i:*|@i:*|x:*|@x:*|graph:*|@graph:*|a:*|@a:*"> + </xsl:template> +</xsl:stylesheet> diff --git a/share/extensions/bezmisc.py b/share/extensions/bezmisc.py index e663fa67f..0c7ad4957 100755 --- a/share/extensions/bezmisc.py +++ b/share/extensions/bezmisc.py @@ -271,4 +271,4 @@ if __name__ == '__main__': print beziertatlength(curve,0.5) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/color_blackandwhite.py b/share/extensions/color_blackandwhite.py index c11b2a127..57e6e2ae8 100644 --- a/share/extensions/color_blackandwhite.py +++ b/share/extensions/color_blackandwhite.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect,sys class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_brighter.py b/share/extensions/color_brighter.py index 741473839..6cec075d4 100644 --- a/share/extensions/color_brighter.py +++ b/share/extensions/color_brighter.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_custom.inx b/share/extensions/color_custom.inx index 78fd504aa..1d18bf47f 100644 --- a/share/extensions/color_custom.inx +++ b/share/extensions/color_custom.inx @@ -5,9 +5,26 @@ <dependency type="executable" location="extensions">coloreffect.py</dependency> <dependency type="executable" location="extensions">color_custom.py</dependency> <dependency type="executable" location="extensions">simplestyle.py</dependency> - <param name="r" type="string" _gui-text="Red Function">r</param> - <param name="g" type="string" _gui-text="Green Function">g</param> - <param name="b" type="string" _gui-text="Blue Function">b</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="r" type="string" _gui-text="Red Function:">r</param> + <param name="g" type="string" _gui-text="Green Function:">g</param> + <param name="b" type="string" _gui-text="Blue Function:">b</param> + <param name="scale" type="optiongroup" _gui-text="Input (r,g,b) Color Range:"> + <option value="1">0 - 1</option> + <option value="255">0 - 255</option> + </param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="instructions" type="description" xml:space="preserve">Allows you to evaluate different functions for each channel. +r, g and b are the normalized values of the red, green and blue channels. The resulting RGB values are automatically clamped. + +Example (half the red, swap green and blue): + Red Function: r*0.5 + Green Function: b + Blue Function: g</_param> + </page> + </param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/color_custom.py b/share/extensions/color_custom.py index 1b866f684..3eefc3f55 100644 --- a/share/extensions/color_custom.py +++ b/share/extensions/color_custom.py @@ -1,25 +1,56 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): - def __init__(self): - coloreffect.ColorEffect.__init__(self) - self.OptionParser.add_option("--r", action="store", type="string", dest="rFunction", default="r",help="red channel function") - self.OptionParser.add_option("--g", action="store", type="string", dest="gFunction", default="g",help="green channel function") - self.OptionParser.add_option("--b", action="store", type="string", dest="bFunction", default="b",help="blue channel function") - def normalize(self, v): - if v<0: - return 0.0 - if v>1: - return 1.0 - return v - def colmod(self,_r,_g,_b): - r=float(_r)/255 - g=float(_g)/255 - b=float(_b)/255 - r2=self.normalize(eval(self.options.rFunction)) - g2=self.normalize(eval(self.options.gFunction)) - b2=self.normalize(eval(self.options.bFunction)) - return '%02x%02x%02x' % (int(round(r2*255)),int(round(g2*255)),int(round(b2*255))) + def __init__(self): + coloreffect.ColorEffect.__init__(self) + self.OptionParser.add_option("--r", + action="store", type="string", + dest="rFunction", default="r", + help="red channel function") + self.OptionParser.add_option("--g", + action="store", type="string", + dest="gFunction", default="g", + help="green channel function") + self.OptionParser.add_option("--b", + action="store", type="string", + dest="bFunction", default="b", + help="blue channel function") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") + self.OptionParser.add_option("--scale", + action="store", type="string", + dest="scale", + help="The input (r,g,b) range") + + def normalize(self, v): + if v<0: + return 0.0 + if v > float(self.options.scale): + return float(self.options.scale) + return v + + def _hexstr(self,r,g,b): + return '%02x%02x%02x' % (int(round(r)),int(round(g)),int(round(b))) + + def colmod(self,_r,_g,_b): + factor = 255.0/float(self.options.scale) + r=float(_r)/factor + g=float(_g)/factor + b=float(_b)/factor + + # add stuff to be accessible from within the custom color function here. + safeenv = {'__builtins__':{},'r':r,'g':g,'b':b} + + try: + r2=self.normalize(eval(self.options.rFunction,safeenv)) + g2=self.normalize(eval(self.options.gFunction,safeenv)) + b2=self.normalize(eval(self.options.bFunction,safeenv)) + except: + return self._hexstr(255.0,0.0,0.0) + return self._hexstr(r2*factor,g2*factor,b2*factor) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_darker.py b/share/extensions/color_darker.py index 40bfb19e6..a8edb07c6 100644 --- a/share/extensions/color_darker.py +++ b/share/extensions/color_darker.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_desaturate.py b/share/extensions/color_desaturate.py index 28f747889..a2350a4d3 100644 --- a/share/extensions/color_desaturate.py +++ b/share/extensions/color_desaturate.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -7,4 +8,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (ig,ig,ig) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_grayscale.py b/share/extensions/color_grayscale.py index ce354b167..727f23570 100644 --- a/share/extensions/color_grayscale.py +++ b/share/extensions/color_grayscale.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -11,4 +12,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (ig,ig,ig) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_lesshue.py b/share/extensions/color_lesshue.py index ec4445641..d34a75019 100644 --- a/share/extensions/color_lesshue.py +++ b/share/extensions/color_lesshue.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_lesslight.py b/share/extensions/color_lesslight.py index 8841490ce..94dfb412d 100644 --- a/share/extensions/color_lesslight.py +++ b/share/extensions/color_lesslight.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_lesssaturation.py b/share/extensions/color_lesssaturation.py index 7b06f98f5..1d3702c76 100644 --- a/share/extensions/color_lesssaturation.py +++ b/share/extensions/color_lesssaturation.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_morehue.py b/share/extensions/color_morehue.py index 816a94c12..7d3406ec0 100644 --- a/share/extensions/color_morehue.py +++ b/share/extensions/color_morehue.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_morelight.py b/share/extensions/color_morelight.py index b930a86df..bbc418c3f 100644 --- a/share/extensions/color_morelight.py +++ b/share/extensions/color_morelight.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_moresaturation.py b/share/extensions/color_moresaturation.py index 5f3ab814f..4ecb4987c 100644 --- a/share/extensions/color_moresaturation.py +++ b/share/extensions/color_moresaturation.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect, inkex class C(coloreffect.ColorEffect): diff --git a/share/extensions/color_negative.py b/share/extensions/color_negative.py index 065586dcf..87a4bdce3 100644 --- a/share/extensions/color_negative.py +++ b/share/extensions/color_negative.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -5,4 +6,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (255-r,255-g,255-b) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_randomize.inx b/share/extensions/color_randomize.inx index a6fdb7256..82691f0f4 100644 --- a/share/extensions/color_randomize.inx +++ b/share/extensions/color_randomize.inx @@ -5,9 +5,16 @@ <dependency type="executable" location="extensions">coloreffect.py</dependency> <dependency type="executable" location="extensions">color_randomize.py</dependency> <dependency type="executable" location="extensions">simplestyle.py</dependency> - <param name="hue" type="boolean" _gui-text="Hue">true</param> - <param name="saturation" type="boolean" _gui-text="Saturation">true</param> - <param name="lightness" type="boolean" _gui-text="Lightness">true</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="hue" type="boolean" _gui-text="Hue">true</param> + <param name="saturation" type="boolean" _gui-text="Saturation">true</param> + <param name="lightness" type="boolean" _gui-text="Lightness">true</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="instructions" type="description" xml:space="preserve">Converts to HSL, randomizes hue and/or saturation and/or lightness and converts it back to RGB.</_param> + </page> + </param> <effect> <object-type>all</object-type> <effects-menu> @@ -17,4 +24,4 @@ <script> <command reldir="extensions" interpreter="python">color_randomize.py</command> </script> -</inkscape-extension>
\ No newline at end of file +</inkscape-extension> diff --git a/share/extensions/color_randomize.py b/share/extensions/color_randomize.py index cfe82a8e3..e939b7b6d 100644 --- a/share/extensions/color_randomize.py +++ b/share/extensions/color_randomize.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect,random,inkex class C(coloreffect.ColorEffect): @@ -15,6 +16,10 @@ class C(coloreffect.ColorEffect): action="store", type="inkbool", dest="lightness", default=True, help="randomize lightness") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def colmod(self,r,g,b): hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) @@ -31,4 +36,4 @@ c = C() c.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/color_removeblue.py b/share/extensions/color_removeblue.py index abba6ba5f..1ea207bdd 100644 --- a/share/extensions/color_removeblue.py +++ b/share/extensions/color_removeblue.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -5,4 +6,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (r,g,0) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_removegreen.py b/share/extensions/color_removegreen.py index 09ba4d5d1..86fdc73e0 100644 --- a/share/extensions/color_removegreen.py +++ b/share/extensions/color_removegreen.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -5,4 +6,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (r,0,b) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_removered.py b/share/extensions/color_removered.py index 5963af426..a6b92fd45 100644 --- a/share/extensions/color_removered.py +++ b/share/extensions/color_removered.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -5,4 +6,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (0,g,b) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/color_replace.inx b/share/extensions/color_replace.inx index f62b2a4e5..289c4424d 100644 --- a/share/extensions/color_replace.inx +++ b/share/extensions/color_replace.inx @@ -5,8 +5,8 @@ <dependency type="executable" location="extensions">coloreffect.py</dependency> <dependency type="executable" location="extensions">color_replace.py</dependency> <dependency type="executable" location="extensions">simplestyle.py</dependency> - <param name="from_color" type="string" max_length="6" _gui-text="Replace color (RRGGBB hex):">000000</param> - <param name="to_color" type="string" max_length="6" _gui-text="By color (RRGGBB hex):">000000</param> + <param name="from_color" type="string" max_length="6" _gui-text="Replace color (RRGGBB hex):" _gui-description="Color to replace">000000</param> + <param name="to_color" type="string" max_length="6" _gui-text="By color (RRGGBB hex):" _gui-description="New color">000000</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/color_replace.py b/share/extensions/color_replace.py index c52d75957..edfd90a76 100644 --- a/share/extensions/color_replace.py +++ b/share/extensions/color_replace.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect import inkex diff --git a/share/extensions/color_rgbbarrel.py b/share/extensions/color_rgbbarrel.py index 3cac39ac5..0fdcd47bc 100644 --- a/share/extensions/color_rgbbarrel.py +++ b/share/extensions/color_rgbbarrel.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import coloreffect class C(coloreffect.ColorEffect): @@ -5,4 +6,4 @@ class C(coloreffect.ColorEffect): return '%02x%02x%02x' % (b,r,g) c = C() -c.affect()
\ No newline at end of file +c.affect() diff --git a/share/extensions/colors.xml b/share/extensions/colors.xml index d877113d7..51167fdd7 100644 --- a/share/extensions/colors.xml +++ b/share/extensions/colors.xml @@ -1,150 +1,150 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<colors>
-<color name="aliceblue" hex="#f0f8ff" rgb="240,248,255" />
-<color name="antiquewhite" hex="#faebd7" rgb="250,235,215" />
-<color name="aqua" hex="#00ffff" rgb="0,255,255" />
-<color name="aquamarine" hex="#7fffd4" rgb="127,255,212" />
-<color name="azure" hex="#f0ffff" rgb="240,255,255" />
-<color name="beige" hex="#f5f5dc" rgb="245,245,220" />
-<color name="bisque" hex="#ffe4c4" rgb="255,228,196" />
-<color name="black" hex="#000000" rgb="0,0,0" />
-<color name="blanchedalmond" hex="#ffebcd" rgb="255,235,205" />
-<color name="blue" hex="#0000ff" rgb="0,0,255" />
-<color name="blueviolet" hex="#8a2be2" rgb="138,43,226" />
-<color name="brown" hex="#a52a2a" rgb="165,42,42" />
-<color name="burlywood" hex="#deb887" rgb="222,184,135" />
-<color name="cadetblue" hex="#5f9ea0" rgb="95,158,160" />
-<color name="chartreuse" hex="#7fff00" rgb="127,255,0" />
-<color name="chocolate" hex="#d2691e" rgb="210,105,30" />
-<color name="coral" hex="#ff7f50" rgb="255,127,80" />
-<color name="cornflowerblue" hex="#6495ed" rgb="100,149,237" />
-<color name="cornsilk" hex="#fff8dc" rgb="255,248,220" />
-<color name="crimson" hex="#dc143c" rgb="220,20,60" />
-<color name="cyan" hex="#00ffff" rgb="0,255,255" />
-<color name="darkblue" hex="#00008b" rgb="0,0,139" />
-<color name="darkcyan" hex="#008b8b" rgb="0,139,139" />
-<color name="darkgoldenrod" hex="#b8860b" rgb="184,134,11" />
-<color name="darkgray" hex="#a9a9a9" rgb="169,169,169" />
-<color name="darkgreen" hex="#006400" rgb="0,100,0" />
-<color name="darkgrey" hex="#a9a9a9" rgb="169,169,169" />
-<color name="darkkhaki" hex="#bdb76b" rgb="189,183,107" />
-<color name="darkmagenta" hex="#8b008b" rgb="139,0,139" />
-<color name="darkolivegreen" hex="#556b2f" rgb="85,107,47" />
-<color name="darkorange" hex="#ff8c00" rgb="255,140,0" />
-<color name="darkorchid" hex="#9932cc" rgb="153,50,204" />
-<color name="darkred" hex="#8b0000" rgb="139,0,0" />
-<color name="darksalmon" hex="#e9967a" rgb="233,150,122" />
-<color name="darkseagreen" hex="#8fbc8f" rgb="143,188,143" />
-<color name="darkslateblue" hex="#483d8b" rgb="72,61,139" />
-<color name="darkslategray" hex="#2f4f4f" rgb="47,79,79" />
-<color name="darkslategrey" hex="#2f4f4f" rgb="47,79,79" />
-<color name="darkturquoise" hex="#00ced1" rgb="0,206,209" />
-<color name="darkviolet" hex="#9400d3" rgb="148,0,211" />
-<color name="deeppink" hex="#ff1493" rgb="255,20,147" />
-<color name="deepskyblue" hex="#00bfff" rgb="0,191,255" />
-<color name="dimgray" hex="#696969" rgb="105,105,105" />
-<color name="dimgrey" hex="#696969" rgb="105,105,105" />
-<color name="dodgerblue" hex="#1e90ff" rgb="30,144,255" />
-<color name="firebrick" hex="#b22222" rgb="178,34,34" />
-<color name="floralwhite" hex="#fffaf0" rgb="255,250,240" />
-<color name="forestgreen" hex="#228b22" rgb="34,139,34" />
-<color name="fuchsia" hex="#ff00ff" rgb="255,0,255" />
-<color name="gainsboro" hex="#dcdcdc" rgb="220,220,220" />
-<color name="ghostwhite" hex="#f8f8ff" rgb="248,248,255" />
-<color name="gold" hex="#ffd700" rgb="255,215,0" />
-<color name="goldenrod" hex="#daa520" rgb="218,165,32" />
-<color name="gray" hex="#808080" rgb="128,128,128" />
-<color name="green" hex="#008000" rgb="0,128,0" />
-<color name="greenyellow" hex="#adff2f" rgb="173,255,47" />
-<color name="grey" hex="#808080" rgb="128,128,128" />
-<color name="honeydew" hex="#f0fff0" rgb="240,255,240" />
-<color name="hotpink" hex="#ff69b4" rgb="255,105,180" />
-<color name="indianred" hex="#cd5c5c" rgb="205,92,92" />
-<color name="indigo" hex="#4b0082" rgb="75,0,130" />
-<color name="ivory" hex="#fffff0" rgb="255,255,240" />
-<color name="khaki" hex="#f0e68c" rgb="240,230,140" />
-<color name="lavender" hex="#e6e6fa" rgb="230,230,250" />
-<color name="lavenderblush" hex="#fff0f5" rgb="255,240,245" />
-<color name="lawngreen" hex="#7cfc00" rgb="124,252,0" />
-<color name="lemonchiffon" hex="#fffacd" rgb="255,250,205" />
-<color name="lightblue" hex="#add8e6" rgb="173,216,230" />
-<color name="lightcoral" hex="#f08080" rgb="240,128,128" />
-<color name="lightcyan" hex="#e0ffff" rgb="224,255,255" />
-<color name="lightgoldenrodyellow" hex="#fafad2" rgb="250,250,210" />
-<color name="lightgray" hex="#d3d3d3" rgb="211,211,211" />
-<color name="lightgreen" hex="#90ee90" rgb="144,238,144" />
-<color name="lightgrey" hex="#d3d3d3" rgb="211,211,211" />
-<color name="lightpink" hex="#ffb6c1" rgb="255,182,193" />
-<color name="lightsalmon" hex="#ffa07a" rgb="255,160,122" />
-<color name="lightseagreen" hex="#20b2aa" rgb="32,178,170" />
-<color name="lightskyblue" hex="#87cefa" rgb="135,206,250" />
-<color name="lightslategray" hex="#778899" rgb="119,136,153" />
-<color name="lightslategrey" hex="#778899" rgb="119,136,153" />
-<color name="lightsteelblue" hex="#b0c4de" rgb="176,196,222" />
-<color name="lightyellow" hex="#ffffe0" rgb="255,255,224" />
-<color name="lime" hex="#00ff00" rgb="0,255,0" />
-<color name="limegreen" hex="#32cd32" rgb="50,205,50" />
-<color name="linen" hex="#faf0e6" rgb="250,240,230" />
-<color name="magenta" hex="#ff00ff" rgb="255,0,255" />
-<color name="maroon" hex="#800000" rgb="128,0,0" />
-<color name="mediumaquamarine" hex="#66cdaa" rgb="102,205,170" />
-<color name="mediumblue" hex="#0000cd" rgb="0,0,205" />
-<color name="mediumorchid" hex="#ba55d3" rgb="186,85,211" />
-<color name="mediumpurple" hex="#9370db" rgb="147,112,219" />
-<color name="mediumseagreen" hex="#3cb371" rgb="60,179,113" />
-<color name="mediumslateblue" hex="#7b68ee" rgb="123,104,238" />
-<color name="mediumspringgreen" hex="#00fa9a" rgb="0,250,154" />
-<color name="mediumturquoise" hex="#48d1cc" rgb="72,209,204" />
-<color name="mediumvioletred" hex="#c71585" rgb="199,21,133" />
-<color name="midnightblue" hex="#191970" rgb="25,25,112" />
-<color name="mintcream" hex="#f5fffa" rgb="245,255,250" />
-<color name="mistyrose" hex="#ffe4e1" rgb="255,228,225" />
-<color name="moccasin" hex="#ffe4b5" rgb="255,228,181" />
-<color name="navajowhite" hex="#ffdead" rgb="255,222,173" />
-<color name="navy" hex="#000080" rgb="0,0,128" />
-<color name="oldlace" hex="#fdf5e6" rgb="253,245,230" />
-<color name="olive" hex="#808000" rgb="128,128,0" />
-<color name="olivedrab" hex="#6b8e23" rgb="107,142,35" />
-<color name="orange" hex="#ffa500" rgb="255,165,0" />
-<color name="orangered" hex="#ff4500" rgb="255,69,0" />
-<color name="orchid" hex="#da70d6" rgb="218,112,214" />
-<color name="palegoldenrod" hex="#eee8aa" rgb="238,232,170" />
-<color name="palegreen" hex="#98fb98" rgb="152,251,152" />
-<color name="paleturquoise" hex="#afeeee" rgb="175,238,238" />
-<color name="palevioletred" hex="#db7093" rgb="219,112,147" />
-<color name="papayawhip" hex="#ffefd5" rgb="255,239,213" />
-<color name="peachpuff" hex="#ffdab9" rgb="255,218,185" />
-<color name="peru" hex="#cd853f" rgb="205,133,63" />
-<color name="pink" hex="#ffc0cb" rgb="255,192,203" />
-<color name="plum" hex="#dda0dd" rgb="221,160,221" />
-<color name="powderblue" hex="#b0e0e6" rgb="176,224,230" />
-<color name="purple" hex="#800080" rgb="128,0,128" />
-<color name="red" hex="#ff0000" rgb="255,0,0" />
-<color name="rosybrown" hex="#bc8f8f" rgb="188,143,143" />
-<color name="royalblue" hex="#4169e1" rgb="65,105,225" />
-<color name="saddlebrown" hex="#8b4513" rgb="139,69,19" />
-<color name="salmon" hex="#fa8072" rgb="250,128,114" />
-<color name="sandybrown" hex="#f4a460" rgb="244,164,96" />
-<color name="seagreen" hex="#2e8b57" rgb="46,139,87" />
-<color name="seashell" hex="#fff5ee" rgb="255,245,238" />
-<color name="sienna" hex="#a0522d" rgb="160,82,45" />
-<color name="silver" hex="#c0c0c0" rgb="192,192,192" />
-<color name="skyblue" hex="#87ceeb" rgb="135,206,235" />
-<color name="slateblue" hex="#6a5acd" rgb="106,90,205" />
-<color name="slategray" hex="#708090" rgb="112,128,144" />
-<color name="slategrey" hex="#708090" rgb="112,128,144" />
-<color name="snow" hex="#fffafa" rgb="255,250,250" />
-<color name="springgreen" hex="#00ff7f" rgb="0,255,127" />
-<color name="steelblue" hex="#4682b4" rgb="70,130,180" />
-<color name="tan" hex="#d2b48c" rgb="210,180,140" />
-<color name="teal" hex="#008080" rgb="0,128,128" />
-<color name="thistle" hex="#d8bfd8" rgb="216,191,216" />
-<color name="tomato" hex="#ff6347" rgb="255,99,71" />
-<color name="turquoise" hex="#40e0d0" rgb="64,224,208" />
-<color name="violet" hex="#ee82ee" rgb="238,130,238" />
-<color name="wheat" hex="#f5deb3" rgb="245,222,179" />
-<color name="white" hex="#ffffff" rgb="255,255,255" />
-<color name="whitesmoke" hex="#f5f5f5" rgb="245,245,245" />
-<color name="yellow" hex="#ffff00" rgb="255,255,0" />
-<color name="yellowgreen" hex="#9acd32" rgb="154,205,50" />
-</colors>
+<?xml version="1.0" encoding="UTF-8"?> +<colors> +<color name="aliceblue" hex="#f0f8ff" rgb="240,248,255" /> +<color name="antiquewhite" hex="#faebd7" rgb="250,235,215" /> +<color name="aqua" hex="#00ffff" rgb="0,255,255" /> +<color name="aquamarine" hex="#7fffd4" rgb="127,255,212" /> +<color name="azure" hex="#f0ffff" rgb="240,255,255" /> +<color name="beige" hex="#f5f5dc" rgb="245,245,220" /> +<color name="bisque" hex="#ffe4c4" rgb="255,228,196" /> +<color name="black" hex="#000000" rgb="0,0,0" /> +<color name="blanchedalmond" hex="#ffebcd" rgb="255,235,205" /> +<color name="blue" hex="#0000ff" rgb="0,0,255" /> +<color name="blueviolet" hex="#8a2be2" rgb="138,43,226" /> +<color name="brown" hex="#a52a2a" rgb="165,42,42" /> +<color name="burlywood" hex="#deb887" rgb="222,184,135" /> +<color name="cadetblue" hex="#5f9ea0" rgb="95,158,160" /> +<color name="chartreuse" hex="#7fff00" rgb="127,255,0" /> +<color name="chocolate" hex="#d2691e" rgb="210,105,30" /> +<color name="coral" hex="#ff7f50" rgb="255,127,80" /> +<color name="cornflowerblue" hex="#6495ed" rgb="100,149,237" /> +<color name="cornsilk" hex="#fff8dc" rgb="255,248,220" /> +<color name="crimson" hex="#dc143c" rgb="220,20,60" /> +<color name="cyan" hex="#00ffff" rgb="0,255,255" /> +<color name="darkblue" hex="#00008b" rgb="0,0,139" /> +<color name="darkcyan" hex="#008b8b" rgb="0,139,139" /> +<color name="darkgoldenrod" hex="#b8860b" rgb="184,134,11" /> +<color name="darkgray" hex="#a9a9a9" rgb="169,169,169" /> +<color name="darkgreen" hex="#006400" rgb="0,100,0" /> +<color name="darkgrey" hex="#a9a9a9" rgb="169,169,169" /> +<color name="darkkhaki" hex="#bdb76b" rgb="189,183,107" /> +<color name="darkmagenta" hex="#8b008b" rgb="139,0,139" /> +<color name="darkolivegreen" hex="#556b2f" rgb="85,107,47" /> +<color name="darkorange" hex="#ff8c00" rgb="255,140,0" /> +<color name="darkorchid" hex="#9932cc" rgb="153,50,204" /> +<color name="darkred" hex="#8b0000" rgb="139,0,0" /> +<color name="darksalmon" hex="#e9967a" rgb="233,150,122" /> +<color name="darkseagreen" hex="#8fbc8f" rgb="143,188,143" /> +<color name="darkslateblue" hex="#483d8b" rgb="72,61,139" /> +<color name="darkslategray" hex="#2f4f4f" rgb="47,79,79" /> +<color name="darkslategrey" hex="#2f4f4f" rgb="47,79,79" /> +<color name="darkturquoise" hex="#00ced1" rgb="0,206,209" /> +<color name="darkviolet" hex="#9400d3" rgb="148,0,211" /> +<color name="deeppink" hex="#ff1493" rgb="255,20,147" /> +<color name="deepskyblue" hex="#00bfff" rgb="0,191,255" /> +<color name="dimgray" hex="#696969" rgb="105,105,105" /> +<color name="dimgrey" hex="#696969" rgb="105,105,105" /> +<color name="dodgerblue" hex="#1e90ff" rgb="30,144,255" /> +<color name="firebrick" hex="#b22222" rgb="178,34,34" /> +<color name="floralwhite" hex="#fffaf0" rgb="255,250,240" /> +<color name="forestgreen" hex="#228b22" rgb="34,139,34" /> +<color name="fuchsia" hex="#ff00ff" rgb="255,0,255" /> +<color name="gainsboro" hex="#dcdcdc" rgb="220,220,220" /> +<color name="ghostwhite" hex="#f8f8ff" rgb="248,248,255" /> +<color name="gold" hex="#ffd700" rgb="255,215,0" /> +<color name="goldenrod" hex="#daa520" rgb="218,165,32" /> +<color name="gray" hex="#808080" rgb="128,128,128" /> +<color name="green" hex="#008000" rgb="0,128,0" /> +<color name="greenyellow" hex="#adff2f" rgb="173,255,47" /> +<color name="grey" hex="#808080" rgb="128,128,128" /> +<color name="honeydew" hex="#f0fff0" rgb="240,255,240" /> +<color name="hotpink" hex="#ff69b4" rgb="255,105,180" /> +<color name="indianred" hex="#cd5c5c" rgb="205,92,92" /> +<color name="indigo" hex="#4b0082" rgb="75,0,130" /> +<color name="ivory" hex="#fffff0" rgb="255,255,240" /> +<color name="khaki" hex="#f0e68c" rgb="240,230,140" /> +<color name="lavender" hex="#e6e6fa" rgb="230,230,250" /> +<color name="lavenderblush" hex="#fff0f5" rgb="255,240,245" /> +<color name="lawngreen" hex="#7cfc00" rgb="124,252,0" /> +<color name="lemonchiffon" hex="#fffacd" rgb="255,250,205" /> +<color name="lightblue" hex="#add8e6" rgb="173,216,230" /> +<color name="lightcoral" hex="#f08080" rgb="240,128,128" /> +<color name="lightcyan" hex="#e0ffff" rgb="224,255,255" /> +<color name="lightgoldenrodyellow" hex="#fafad2" rgb="250,250,210" /> +<color name="lightgray" hex="#d3d3d3" rgb="211,211,211" /> +<color name="lightgreen" hex="#90ee90" rgb="144,238,144" /> +<color name="lightgrey" hex="#d3d3d3" rgb="211,211,211" /> +<color name="lightpink" hex="#ffb6c1" rgb="255,182,193" /> +<color name="lightsalmon" hex="#ffa07a" rgb="255,160,122" /> +<color name="lightseagreen" hex="#20b2aa" rgb="32,178,170" /> +<color name="lightskyblue" hex="#87cefa" rgb="135,206,250" /> +<color name="lightslategray" hex="#778899" rgb="119,136,153" /> +<color name="lightslategrey" hex="#778899" rgb="119,136,153" /> +<color name="lightsteelblue" hex="#b0c4de" rgb="176,196,222" /> +<color name="lightyellow" hex="#ffffe0" rgb="255,255,224" /> +<color name="lime" hex="#00ff00" rgb="0,255,0" /> +<color name="limegreen" hex="#32cd32" rgb="50,205,50" /> +<color name="linen" hex="#faf0e6" rgb="250,240,230" /> +<color name="magenta" hex="#ff00ff" rgb="255,0,255" /> +<color name="maroon" hex="#800000" rgb="128,0,0" /> +<color name="mediumaquamarine" hex="#66cdaa" rgb="102,205,170" /> +<color name="mediumblue" hex="#0000cd" rgb="0,0,205" /> +<color name="mediumorchid" hex="#ba55d3" rgb="186,85,211" /> +<color name="mediumpurple" hex="#9370db" rgb="147,112,219" /> +<color name="mediumseagreen" hex="#3cb371" rgb="60,179,113" /> +<color name="mediumslateblue" hex="#7b68ee" rgb="123,104,238" /> +<color name="mediumspringgreen" hex="#00fa9a" rgb="0,250,154" /> +<color name="mediumturquoise" hex="#48d1cc" rgb="72,209,204" /> +<color name="mediumvioletred" hex="#c71585" rgb="199,21,133" /> +<color name="midnightblue" hex="#191970" rgb="25,25,112" /> +<color name="mintcream" hex="#f5fffa" rgb="245,255,250" /> +<color name="mistyrose" hex="#ffe4e1" rgb="255,228,225" /> +<color name="moccasin" hex="#ffe4b5" rgb="255,228,181" /> +<color name="navajowhite" hex="#ffdead" rgb="255,222,173" /> +<color name="navy" hex="#000080" rgb="0,0,128" /> +<color name="oldlace" hex="#fdf5e6" rgb="253,245,230" /> +<color name="olive" hex="#808000" rgb="128,128,0" /> +<color name="olivedrab" hex="#6b8e23" rgb="107,142,35" /> +<color name="orange" hex="#ffa500" rgb="255,165,0" /> +<color name="orangered" hex="#ff4500" rgb="255,69,0" /> +<color name="orchid" hex="#da70d6" rgb="218,112,214" /> +<color name="palegoldenrod" hex="#eee8aa" rgb="238,232,170" /> +<color name="palegreen" hex="#98fb98" rgb="152,251,152" /> +<color name="paleturquoise" hex="#afeeee" rgb="175,238,238" /> +<color name="palevioletred" hex="#db7093" rgb="219,112,147" /> +<color name="papayawhip" hex="#ffefd5" rgb="255,239,213" /> +<color name="peachpuff" hex="#ffdab9" rgb="255,218,185" /> +<color name="peru" hex="#cd853f" rgb="205,133,63" /> +<color name="pink" hex="#ffc0cb" rgb="255,192,203" /> +<color name="plum" hex="#dda0dd" rgb="221,160,221" /> +<color name="powderblue" hex="#b0e0e6" rgb="176,224,230" /> +<color name="purple" hex="#800080" rgb="128,0,128" /> +<color name="red" hex="#ff0000" rgb="255,0,0" /> +<color name="rosybrown" hex="#bc8f8f" rgb="188,143,143" /> +<color name="royalblue" hex="#4169e1" rgb="65,105,225" /> +<color name="saddlebrown" hex="#8b4513" rgb="139,69,19" /> +<color name="salmon" hex="#fa8072" rgb="250,128,114" /> +<color name="sandybrown" hex="#f4a460" rgb="244,164,96" /> +<color name="seagreen" hex="#2e8b57" rgb="46,139,87" /> +<color name="seashell" hex="#fff5ee" rgb="255,245,238" /> +<color name="sienna" hex="#a0522d" rgb="160,82,45" /> +<color name="silver" hex="#c0c0c0" rgb="192,192,192" /> +<color name="skyblue" hex="#87ceeb" rgb="135,206,235" /> +<color name="slateblue" hex="#6a5acd" rgb="106,90,205" /> +<color name="slategray" hex="#708090" rgb="112,128,144" /> +<color name="slategrey" hex="#708090" rgb="112,128,144" /> +<color name="snow" hex="#fffafa" rgb="255,250,250" /> +<color name="springgreen" hex="#00ff7f" rgb="0,255,127" /> +<color name="steelblue" hex="#4682b4" rgb="70,130,180" /> +<color name="tan" hex="#d2b48c" rgb="210,180,140" /> +<color name="teal" hex="#008080" rgb="0,128,128" /> +<color name="thistle" hex="#d8bfd8" rgb="216,191,216" /> +<color name="tomato" hex="#ff6347" rgb="255,99,71" /> +<color name="turquoise" hex="#40e0d0" rgb="64,224,208" /> +<color name="violet" hex="#ee82ee" rgb="238,130,238" /> +<color name="wheat" hex="#f5deb3" rgb="245,222,179" /> +<color name="white" hex="#ffffff" rgb="255,255,255" /> +<color name="whitesmoke" hex="#f5f5f5" rgb="245,245,245" /> +<color name="yellow" hex="#ffff00" rgb="255,255,0" /> +<color name="yellowgreen" hex="#9acd32" rgb="154,205,50" /> +</colors> diff --git a/share/extensions/convert2dashes.inx b/share/extensions/convert2dashes.inx index 9f3ff365e..1230ff2d8 100644 --- a/share/extensions/convert2dashes.inx +++ b/share/extensions/convert2dashes.inx @@ -1,16 +1,16 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Convert to Dashes</_name>
- <id>com.vaxxine.filter.dashes</id>
- <dependency type="executable" location="extensions">convert2dashes.py</dependency>
- <dependency type="executable" location="extensions">inkex.py</dependency>
- <effect>
- <object-type>path</object-type>
- <effects-menu>
- <submenu _name="Modify Path"/>
- </effects-menu>
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">convert2dashes.py</command>
- </script>
-</inkscape-extension>
+<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Convert to Dashes</_name> + <id>com.vaxxine.filter.dashes</id> + <dependency type="executable" location="extensions">convert2dashes.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <effect> + <object-type>path</object-type> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">convert2dashes.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/convert2dashes.py b/share/extensions/convert2dashes.py index b77961740..f88734baf 100644 --- a/share/extensions/convert2dashes.py +++ b/share/extensions/convert2dashes.py @@ -86,4 +86,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/cspsubdiv.py b/share/extensions/cspsubdiv.py index 20817d8cf..f05068df9 100644 --- a/share/extensions/cspsubdiv.py +++ b/share/extensions/cspsubdiv.py @@ -38,4 +38,4 @@ def subdiv(sp,flat,i=1): subdiv(sp,flat,i) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/cubicsuperpath.py b/share/extensions/cubicsuperpath.py index af61acb3a..da46f8080 100755 --- a/share/extensions/cubicsuperpath.py +++ b/share/extensions/cubicsuperpath.py @@ -166,4 +166,4 @@ def formatPath(p): return simplepath.formatPath(unCubicSuperPath(p)) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dimension.inx b/share/extensions/dimension.inx index cce244d4a..343ad27bf 100644 --- a/share/extensions/dimension.inx +++ b/share/extensions/dimension.inx @@ -5,11 +5,11 @@ <dependency type="executable" location="extensions">dimension.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> <dependency type="executable" location="extensions">pathmodifier.py</dependency> - <param name="xoffset" type="float" min="0" max="1000" _gui-text="X Offset">50</param> - <param name="yoffset" type="float" min="0" max="1000" _gui-text="Y Offset">50</param> - <param name="type" type="optiongroup" _gui-text="Bounding box type : "> - <_option value="geometric">Geometric</_option> - <_option value="visual">Visual</_option> + <param name="xoffset" type="float" min="0" max="1000" _gui-text="X Offset:">50</param> + <param name="yoffset" type="float" min="0" max="1000" _gui-text="Y Offset:">50</param> + <param name="type" type="enum" _gui-text="Bounding box type :"> + <_item value="geometric">Geometric</_item> + <_item value="visual">Visual</_item> </param> <effect> <object-type>path</object-type> diff --git a/share/extensions/dimension.py b/share/extensions/dimension.py index 1b84642ea..9156fdc2c 100644 --- a/share/extensions/dimension.py +++ b/share/extensions/dimension.py @@ -177,4 +177,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dots.inx b/share/extensions/dots.inx index 4655f838b..190418cac 100644 --- a/share/extensions/dots.inx +++ b/share/extensions/dots.inx @@ -4,8 +4,22 @@ <id>org.ekips.filter.dots</id> <dependency type="executable" location="extensions">dots.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="fontsize" type="string" _gui-text="Font size">20</param> - <param name="dotsize" type="string" _gui-text="Dot size">10px</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="fontsize" type="string" _gui-text="Font size:">20px</param> + <param name="dotsize" type="string" _gui-text="Dot size:">10px</param> + <param name="start" type="int" min="0" max="1000" _gui-text="Starting dot number:">1</param> + <param name="step" type="int" min="0" max="1000" _gui-text="Step:">1</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="instructions" type="description" xml:space="preserve">This extension replaces the selection's nodes with numbered dots according to the following options: + * Font size: size of the node number labels (20px, 12pt...). + * Dot size: diameter of the dots placed at path nodes (10px, 2mm...). + * Starting dot number: first number in the sequence, assigned to the first node of the path. + * Step: numbering step between two nodes.</_param> + </page> + </param> + <effect> <object-type>path</object-type> <effects-menu> diff --git a/share/extensions/dots.py b/share/extensions/dots.py index aa33b39ac..7b88dd1b1 100755 --- a/share/extensions/dots.py +++ b/share/extensions/dots.py @@ -30,7 +30,27 @@ class Dots(inkex.Effect): action="store", type="string", dest="fontsize", default="20", help="Size of node label numbers") + self.OptionParser.add_option("-s", "--start", + action="store", type="int", + dest="start", default="1", + help="First number in the sequence, assigned to the first node") + self.OptionParser.add_option("-t", "--step", + action="store", type="int", + dest="step", default="1", + help="Numbering step between two nodes") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") + def effect(self): + selection = self.selected + if (selection): + for id, node in selection.iteritems(): + if node.tag == inkex.addNS('path','svg'): + self.addDot(node) + else: + inkex.errormsg("Please select an object.") def separateLastAndFirst(self, p): # Separate the last and first dot if they are togheter @@ -52,47 +72,43 @@ class Dots(inkex.Effect): p[lastDot][1][-2] += x * inkex.unittouu(self.options.dotsize) p[lastDot][1][-1] += y * inkex.unittouu(self.options.dotsize) - - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - self.group = inkex.etree.SubElement( node.getparent(), inkex.addNS('g','svg') ) - self.dotGroup = inkex.etree.SubElement( self.group, inkex.addNS('g','svg') ) - self.numGroup = inkex.etree.SubElement( self.group, inkex.addNS('g','svg') ) - - try: - t = node.get('transform') - self.group.set('transform', t) - except: - pass - - style = simplestyle.formatStyle({ 'stroke': 'none', 'fill': '#000' }) - a = [] - p = simplepath.parsePath(node.get('d')) - - self.separateLastAndFirst(p) - - num = 1 - for cmd,params in p: - if cmd != 'Z' and cmd != 'z': - dot_att = { - 'style': style, - 'r': str( inkex.unittouu(self.options.dotsize) / 2 ), - 'cx': str( params[-2] ), - 'cy': str( params[-1] ) - } - inkex.etree.SubElement( - self.dotGroup, - inkex.addNS('circle','svg'), - dot_att ) - self.addText( - self.numGroup, - params[-2] + ( inkex.unittouu(self.options.dotsize) / 2 ), - params[-1] - ( inkex.unittouu(self.options.dotsize) / 2 ), - num ) - num += 1 - node.getparent().remove( node ) - + def addDot(self, node): + self.group = inkex.etree.SubElement( node.getparent(), inkex.addNS('g','svg') ) + self.dotGroup = inkex.etree.SubElement( self.group, inkex.addNS('g','svg') ) + self.numGroup = inkex.etree.SubElement( self.group, inkex.addNS('g','svg') ) + + try: + t = node.get('transform') + self.group.set('transform', t) + except: + pass + + style = simplestyle.formatStyle({ 'stroke': 'none', 'fill': '#000' }) + a = [] + p = simplepath.parsePath(node.get('d')) + + self.separateLastAndFirst(p) + + num = self.options.start + for cmd,params in p: + if cmd != 'Z' and cmd != 'z': + dot_att = { + 'style': style, + 'r': str( inkex.unittouu(self.options.dotsize) / 2 ), + 'cx': str( params[-2] ), + 'cy': str( params[-1] ) + } + inkex.etree.SubElement( + self.dotGroup, + inkex.addNS('circle','svg'), + dot_att ) + self.addText( + self.numGroup, + params[-2] + ( inkex.unittouu(self.options.dotsize) / 2 ), + params[-1] - ( inkex.unittouu(self.options.dotsize) / 2 ), + num ) + num += self.options.step + node.getparent().remove( node ) def addText(self,node,x,y,text): new = inkex.etree.SubElement(node,inkex.addNS('text','svg')) @@ -108,4 +124,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/draw_from_triangle.inx b/share/extensions/draw_from_triangle.inx index 5b57e2c49..5c645bf26 100644 --- a/share/extensions/draw_from_triangle.inx +++ b/share/extensions/draw_from_triangle.inx @@ -29,14 +29,14 @@ <param name="nagel_pt" type="boolean" _gui-text="Nagel Point"></param> </page> <page name="Custom" _gui-text="Custom Points and Options"> - <param name="mode" type="optiongroup" _gui-text="Custom Point Specified By:"> - <_option value="trilin">Trilinear Coordinates</_option> - <_option value="tcf">Triangle Function</_option> + <param name="mode" type="enum" _gui-text="Custom Point Specified By:"> + <_item value="trilin">Trilinear Coordinates</_item> + <_item value="tcf">Triangle Function</_item> </param> - <param name="cust_str" type="string" _gui-text="Point At">cos(a_a):cos(a_b):cos(a_c)</param> + <param name="cust_str" type="string" _gui-text="Point At:">cos(a_a):cos(a_b):cos(a_c)</param> <param name="cust_pt" type="boolean" _gui-text="Draw Marker At This Point"></param> <param name="cust_radius" type="boolean" _gui-text="Draw Circle Around This Point"></param> - <param name="radius" type="string" _gui-text="Radius / px">s_a*s_b*s_c/(4*area)</param> + <param name="radius" type="string" _gui-text="Radius (px):">s_a*s_b*s_c/(4*area)</param> <param name="isogonal_conj" type="boolean" _gui-text="Draw Isogonal Conjugate"></param> <param name="isotomic_conj" type="boolean" _gui-text="Draw Isotomic Conjugate"></param> <param name="report" type="boolean" _gui-text="Report this triangle's properties"></param> @@ -68,9 +68,9 @@ You can specify the radius of a circle around a custom point using a formula, wh </param> <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">draw_from_triangle.py</command> diff --git a/share/extensions/draw_from_triangle.py b/share/extensions/draw_from_triangle.py index 38843210c..124824528 100644 --- a/share/extensions/draw_from_triangle.py +++ b/share/extensions/draw_from_triangle.py @@ -172,14 +172,14 @@ def cot(x):#cotangent(x) return 1/tan(x) def report_properties( params ):#report to the Inkscape console using errormsg - inkex.errormsg(_("Side Length 'a'/px: " + str( params[0][0] ) )) - inkex.errormsg(_("Side Length 'b'/px: " + str( params[0][1] ) )) - inkex.errormsg(_("Side Length 'c'/px: " + str( params[0][2] ) )) - inkex.errormsg(_("Angle 'A'/radians: " + str( params[1][0] ) )) - inkex.errormsg(_("Angle 'B'/radians: " + str( params[1][1] ) )) - inkex.errormsg(_("Angle 'C'/radians: " + str( params[1][2] ) )) - inkex.errormsg(_("Semiperimeter/px: " + str( params[4][1] ) )) - inkex.errormsg(_("Area /px^2: " + str( params[4][0] ) )) + inkex.errormsg(_("Side Length 'a' (px): " + str( params[0][0] ) )) + inkex.errormsg(_("Side Length 'b' (px): " + str( params[0][1] ) )) + inkex.errormsg(_("Side Length 'c' (px): " + str( params[0][2] ) )) + inkex.errormsg(_("Angle 'A' (radians): " + str( params[1][0] ) )) + inkex.errormsg(_("Angle 'B' (radians): " + str( params[1][1] ) )) + inkex.errormsg(_("Angle 'C' (radians): " + str( params[1][2] ) )) + inkex.errormsg(_("Semiperimeter (px): " + str( params[4][1] ) )) + inkex.errormsg(_("Area (px^2): " + str( params[4][0] ) )) return diff --git a/share/extensions/dxf_input.py b/share/extensions/dxf_input.py index f92b1ee82..b46477de1 100644 --- a/share/extensions/dxf_input.py +++ b/share/extensions/dxf_input.py @@ -121,7 +121,7 @@ def export_LWPOLYLINE(): # optional group codes : (42) (bulge) iseqs = 0 ibulge = 0 - if vals[groups['70']][0] == 1: # closed path + if vals[groups['70']][0]: # closed path seqs.append('20') vals[groups['10']].append(vals[groups['10']][0]) vals[groups['20']].append(vals[groups['20']][0]) @@ -153,7 +153,7 @@ def export_LWPOLYLINE(): path += ' L %f,%f' % (vals[groups['10']][i], vals[groups['20']][i]) xold = vals[groups['10']][i] yold = vals[groups['20']][i] - if vals[groups['70']][0] == 1: # closed path + if vals[groups['70']][0]: # closed path path += ' z' attribs = {'d': path, 'style': style} inkex.etree.SubElement(layer, 'path', attribs) @@ -307,7 +307,7 @@ def get_group(group): # define DXF Entities and specify which Group Codes to monitor -entities = {'MTEXT': export_MTEXT, 'TEXT': export_MTEXT, 'POINT': export_POINT, 'LINE': export_LINE, 'SPLINE': export_SPLINE, 'CIRCLE': export_CIRCLE, 'ARC': export_ARC, 'ELLIPSE': export_ELLIPSE, 'LEADER': export_LEADER, 'LWPOLYLINE': export_LWPOLYLINE, 'HATCH': export_HATCH, 'DIMENSION': export_DIMENSION, 'INSERT': export_INSERT, 'BLOCK': export_BLOCK, 'ENDBLK': export_ENDBLK, 'ATTDEF': export_ATTDEF, 'DICTIONARY': False} +entities = {'MTEXT': export_MTEXT, 'TEXT': export_MTEXT, 'POINT': export_POINT, 'LINE': export_LINE, 'SPLINE': export_SPLINE, 'CIRCLE': export_CIRCLE, 'ARC': export_ARC, 'ELLIPSE': export_ELLIPSE, 'LEADER': export_LEADER, 'LWPOLYLINE': export_LWPOLYLINE, 'HATCH': export_HATCH, 'DIMENSION': export_DIMENSION, 'INSERT': export_INSERT, 'BLOCK': export_BLOCK, 'ENDBLK': export_ENDBLK, 'ATTDEF': export_ATTDEF, 'VIEWPORT': False, 'DICTIONARY': False} groups = {'1': 0, '2': 1, '3': 2, '6': 3, '8': 4, '10': 5, '11': 6, '13': 7, '14': 8, '20': 9, '21': 10, '23': 11, '24': 12, '40': 13, '41': 14, '42': 15, '50': 16, '51': 17, '62': 18, '70': 19, '72': 20, '73': 21, '92': 22, '93': 23, '370': 24} colors = { 1: '#FF0000', 2: '#FFFF00', 3: '#00FF00', 4: '#00FFFF', 5: '#0000FF', 6: '#FF00FF', 8: '#414141', 9: '#808080', 12: '#BD0000', 30: '#FF7F00', @@ -452,11 +452,12 @@ while line[0] and line[1] != 'DICTIONARY': if vals[groups['6']]: # Common Linetype if linetypes.has_key(vals[groups['6']][0]): style += ';' + linetypes[vals[groups['6']][0]] - entities[entity]() + if entities[entity]: + entities[entity]() entity = line[1] vals = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]] seqs = [] doc.write(inkex.sys.stdout) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dxf_outlines.py b/share/extensions/dxf_outlines.py index 219ee1dda..b2f777ae6 100755 --- a/share/extensions/dxf_outlines.py +++ b/share/extensions/dxf_outlines.py @@ -236,4 +236,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dxf_templates.py b/share/extensions/dxf_templates.py index 5c027456f..11be0fc85 100644 --- a/share/extensions/dxf_templates.py +++ b/share/extensions/dxf_templates.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python r14_header = ''' 0 SECTION 2 diff --git a/share/extensions/edge3d.inx b/share/extensions/edge3d.inx index 9b287359f..bc5f073ed 100644 --- a/share/extensions/edge3d.inx +++ b/share/extensions/edge3d.inx @@ -1,30 +1,23 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Edge 3D</_name> - <id>org.greygreen.inkscape.effects.edge3d</id> - <dependency type="executable" location="extensions">edge3d.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="angle" type="float" min="0.0" max="360.0" - _gui-text="Illumination Angle">45</param> - <param name="shades" type="int" min="2" max="360" - _gui-text="Shades">2</param> - <param name="bw" type="boolean" - _gui-text="Only black and white">0</param> - <param name="thick" type="float" min="1.0" max="50.0" - _gui-text="Stroke width">10</param> - <param name="stddev" type="float" min="1.0" max="100.0" - _gui-text="Blur stdDeviation">5</param> - <param name="blurwidth" type="float" min="1.0" max="10.0" - _gui-text="Blur width">2</param> - <param name="blurheight" type="float" min="1.0" max="10.0" - _gui-text="Blur height">2</param> - <effect> + <_name>Edge 3D</_name> + <id>org.greygreen.inkscape.effects.edge3d</id> + <dependency type="executable" location="extensions">edge3d.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Illumination Angle:">45</param> + <param name="shades" type="int" min="2" max="360" _gui-text="Shades:">2</param> + <param name="bw" type="boolean" _gui-text="Only black and white:">0</param> + <param name="thick" type="float" min="1.0" max="50.0" _gui-text="Stroke width:">10</param> + <param name="stddev" type="float" min="1.0" max="100.0" _gui-text="Blur stdDeviation:">5</param> + <param name="blurwidth" type="float" min="1.0" max="10.0" _gui-text="Blur width:">2</param> + <param name="blurheight" type="float" min="1.0" max="10.0" _gui-text="Blur height:">2</param> + <effect> <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">edge3d.py</command> - </script> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">edge3d.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/edge3d.py b/share/extensions/edge3d.py index 2deff9b67..d2d8ead5c 100644 --- a/share/extensions/edge3d.py +++ b/share/extensions/edge3d.py @@ -146,4 +146,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/embedimage.py b/share/extensions/embedimage.py index f73ceb358..882455cb0 100644 --- a/share/extensions/embedimage.py +++ b/share/extensions/embedimage.py @@ -106,4 +106,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/eps_input.inx b/share/extensions/eps_input.inx index 14f33764d..411d82cd8 100644 --- a/share/extensions/eps_input.inx +++ b/share/extensions/eps_input.inx @@ -5,6 +5,7 @@ <dependency type="extension">org.inkscape.input.pdf</dependency> <dependency type="executable" location="path">ps2pdf</dependency> <dependency type="executable" location="extensions">ps2pdf-ext.py</dependency> + <param name="dEPSCrop" type="boolean" gui-hidden="true">true</param> <input> <extension>.eps</extension> <mimetype>image/x-encapsulated-postscript</mimetype> diff --git a/share/extensions/eqtexsvg.py b/share/extensions/eqtexsvg.py index 8e2e70a10..bf2874ef9 100644 --- a/share/extensions/eqtexsvg.py +++ b/share/extensions/eqtexsvg.py @@ -156,4 +156,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/export_gimp_palette.py b/share/extensions/export_gimp_palette.py index f1b4086c0..b9d6a1059 100644 --- a/share/extensions/export_gimp_palette.py +++ b/share/extensions/export_gimp_palette.py @@ -47,4 +47,4 @@ for k,v in sorted(colors.items()): print k+v -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/extractimage.py b/share/extensions/extractimage.py index 4093b94a7..d5cf285c8 100644 --- a/share/extensions/extractimage.py +++ b/share/extensions/extractimage.py @@ -77,4 +77,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/extrude.inx b/share/extensions/extrude.inx index b282fe0d9..dfae5d825 100644 --- a/share/extensions/extrude.inx +++ b/share/extensions/extrude.inx @@ -4,15 +4,15 @@ <id>org.greygreen.inkscape.effects.extrude</id> <dependency type="executable" location="extensions">extrude.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="mode" type="optiongroup" _gui-text="Mode:"> - <_option>Lines</_option> - <_option>Polygons</_option> - </param> + <param name="mode" type="enum" _gui-text="Mode:"> + <_item>Lines</_item> + <_item>Polygons</_item> + </param> <effect> <object-type>path</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> + <effects-menu> + <submenu _name="Generate from Path"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">extrude.py</command> diff --git a/share/extensions/ffgeom.py b/share/extensions/ffgeom.py index 198358672..ef8799b97 100644 --- a/share/extensions/ffgeom.py +++ b/share/extensions/ffgeom.py @@ -138,4 +138,4 @@ def dot(s1, s2): return s1.delta_x() * s2.delta_x() + s1.delta_y() * s2.delta_y() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/fig2dev-ext.py b/share/extensions/fig2dev-ext.py index 0e32a941d..ac51b00ef 100644 --- a/share/extensions/fig2dev-ext.py +++ b/share/extensions/fig2dev-ext.py @@ -27,4 +27,4 @@ from run_command import run run('fig2dev -L svg "%s" "%%s"' % sys.argv[1].replace("%","%%"), "fig2dev") -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/flatten.inx b/share/extensions/flatten.inx index 8167175d8..4c8298623 100644 --- a/share/extensions/flatten.inx +++ b/share/extensions/flatten.inx @@ -4,7 +4,7 @@ <id>org.ekips.filter.flatten</id> <dependency type="executable" location="extensions">flatten.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="flatness" type="float" min="0.0" max="1000.0" _gui-text="Flatness">10.0</param> + <param name="flatness" type="float" min="0.0" max="1000.0" _gui-text="Flatness:">10.0</param> <effect> <object-type>path</object-type> <effects-menu> diff --git a/share/extensions/flatten.py b/share/extensions/flatten.py index 48044936b..ce6915086 100755 --- a/share/extensions/flatten.py +++ b/share/extensions/flatten.py @@ -47,4 +47,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/foldablebox.inx b/share/extensions/foldablebox.inx index e984e6509..72475ca3f 100644 --- a/share/extensions/foldablebox.inx +++ b/share/extensions/foldablebox.inx @@ -1,29 +1,29 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Foldable Box</_name> - <id>org.inkscape.render.foldable-box</id> - <dependency type="executable" location="extensions">foldablebox.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="width" type="float" min="0.1" max="1000.0" _gui-text="Width">10.0</param> - <param name="height" type="float" min="0.1" max="1000.0" _gui-text="Height">15.0</param> - <param name="depth" type="float" min="0.1" max="1000.0" _gui-text="Depth">3.0</param> - <param name="paper-thickness" type="float" min="0.0" max="100.0" _gui-text="Paper Thickness">0.01</param> - <param name="tab-proportion" type="float" min="0.1" max="1.0" _gui-text="Tab Proportion">0.6</param> - <param name="unit" _gui-text="Unit" type="optiongroup" appearance="minimal"> - <option value="px">px</option> - <option value="pt">pt</option> - <option value="in">in</option> - <option value="cm">cm</option> - <option value="mm">mm</option> - </param> - <param name="guide-line" type="boolean" _gui-text="Add Guide Lines">true</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">foldablebox.py</command> - </script> + <_name>Foldable Box</_name> + <id>org.inkscape.render.foldable-box</id> + <dependency type="executable" location="extensions">foldablebox.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="width" type="float" min="0.1" max="1000.0" _gui-text="Width:">10.0</param> + <param name="height" type="float" min="0.1" max="1000.0" _gui-text="Height:">15.0</param> + <param name="depth" type="float" min="0.1" max="1000.0" _gui-text="Depth:">3.0</param> + <param name="paper-thickness" type="float" min="0.0" max="100.0" _gui-text="Paper Thickness:">0.01</param> + <param name="tab-proportion" type="float" min="0.1" max="1.0" _gui-text="Tab Proportion:">0.6</param> + <param name="unit" _gui-text="Unit:" type="enum"> + <item value="px">px</item> + <item value="pt">pt</item> + <item value="in">in</item> + <item value="cm">cm</item> + <item value="mm">mm</item> + </param> + <param name="guide-line" type="boolean" _gui-text="Add Guide Lines">true</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">foldablebox.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/foldablebox.py b/share/extensions/foldablebox.py index 47f3ad59c..21de10565 100755 --- a/share/extensions/foldablebox.py +++ b/share/extensions/foldablebox.py @@ -262,4 +262,4 @@ if __name__ == '__main__': #pragma: no cover e = FoldableBox() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/fractalize.inx b/share/extensions/fractalize.inx index 189bb2afa..4893189e8 100755 --- a/share/extensions/fractalize.inx +++ b/share/extensions/fractalize.inx @@ -4,13 +4,13 @@ <id>org.ekips.filter.fractalize</id> <dependency type="executable" location="extensions">fractalize.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="subdivs" type="int" _gui-text="Subdivisions">6</param> - <param name="smooth" type="float" _gui-text="Smoothness">4.0</param> + <param name="subdivs" type="int" _gui-text="Subdivisions:">6</param> + <param name="smooth" type="float" _gui-text="Smoothness:">4.0</param> <effect> <object-type>path</object-type> <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">fractalize.py</command> diff --git a/share/extensions/fractalize.py b/share/extensions/fractalize.py index ec92064d1..901a8f761 100755 --- a/share/extensions/fractalize.py +++ b/share/extensions/fractalize.py @@ -94,4 +94,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/funcplot.inx b/share/extensions/funcplot.inx index 6af6595c9..8eaf33f01 100644 --- a/share/extensions/funcplot.inx +++ b/share/extensions/funcplot.inx @@ -1,32 +1,33 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Function Plotter</_name> - <id>org.inkscape.effect.funcplot</id> - <dependency type="executable" location="extensions">funcplot.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="sampling" _gui-text="Range and sampling"> - <param name="xstart" type="float" min="-1000.0" max="1000.0" _gui-text="Start X value">0.0</param> - <param name="xend" type="float" min="-1000.0" max="1000.0" _gui-text="End X value">1.0</param> - <param name="times2pi" type="boolean" _gui-text="Multiply X range by 2*pi">false</param> - <param name="ybottom" type="float" min="-1000.0" max="1000.0" _gui-text="Y value of rectangle's bottom">0.0</param> - <param name="ytop" type="float" min="-1000.0" max="1000.0" _gui-text="Y value of rectangle's top">1.0</param> - <param name="samples" type="int" min="2" max="1000" _gui-text="Number of samples">8</param> - <param name="isoscale" type="boolean" _gui-text="Isotropic scaling (uses smallest of width/xrange or height/yrange)">false</param> - <param name="polar" type="boolean" _gui-text="Use polar coordinates">true</param> - </page> - <page name="use" _gui-text="Use"> - <_param name="funcplotuse" type="description" xml:space="preserve">Select a rectangle before calling the extension, -it will determine X and Y scales. + <_name>Function Plotter</_name> + <id>org.inkscape.effect.funcplot</id> + <dependency type="executable" location="extensions">funcplot.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="sampling" _gui-text="Range and sampling"> + <param name="xstart" type="float" min="-1000.0" max="1000.0" _gui-text="Start X value:">0.0</param> + <param name="xend" type="float" min="-1000.0" max="1000.0" _gui-text="End X value:">1.0</param> + <param name="times2pi" type="boolean" _gui-text="Multiply X range by 2*pi">false</param> + <param name="ybottom" type="float" min="-1000.0" max="1000.0" _gui-text="Y value of rectangle's bottom:">0.0</param> + <param name="ytop" type="float" min="-1000.0" max="1000.0" _gui-text="Y value of rectangle's top:">1.0</param> + <param name="samples" type="int" min="2" max="1000" _gui-text="Number of samples:">8</param> + <param name="isoscale" type="boolean" _gui-text="Isotropic scaling">false</param> + <_param name="isoscaledesc" type="description">When set, Isotropic scaling uses smallest of width/xrange or height/yrange</_param> + <param name="polar" type="boolean" _gui-text="Use polar coordinates">true</param> + </page> + <page name="use" _gui-text="Use"> + <_param name="funcplotuse" type="description" xml:space="preserve">Select a rectangle before calling the extension, +it will determine X and Y scales. If you wish to fill the area, then add x-axis endpoints. With polar coordinates: Start and end X values define the angle range in radians. X scale is set so that left and right edges of rectangle are at +/-1. Isotropic scaling is disabled. First derivative is always determined numerically.</_param> - </page> - <page name="desc" _gui-text="Functions"> - <_param name="pythonfunctions" type="description" xml:space="preserve">Standard Python math functions are available: + </page> + <page name="desc" _gui-text="Functions"> + <_param name="pythonfunctions" type="description" xml:space="preserve">Standard Python math functions are available: ceil(x); fabs(x); floor(x); fmod(x,y); frexp(x); ldexp(x,i); modf(x); exp(x); log(x [, base]); log10(x); pow(x,y); sqrt(x); @@ -35,20 +36,21 @@ cos(x); sin(x); tan(x); degrees(x); radians(x); cosh(x); sinh(x); tanh(x). The constants pi and e are also available.</_param> - </page> - </param> - <param name="fofx" type="string" _gui-text="Function">exp(-x*x)</param> - <param name="fponum" type="boolean" _gui-text="Calculate first derivative numerically">true</param> - <param name="fpofx" type="string" _gui-text="First derivative">x</param> - <param name="remove" type="boolean" _gui-text="Remove rectangle">true</param> - <param name="drawaxis" type="boolean" _gui-text="Draw Axes">false</param> - <effect> - <object-type>rect</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">funcplot.py</command> - </script> + </page> + </param> + <param name="fofx" type="string" _gui-text="Function:">exp(-x*x)</param> + <param name="fponum" type="boolean" _gui-text="Calculate first derivative numerically">true</param> + <param name="fpofx" type="string" _gui-text="First derivative:">x</param> + <param name="remove" type="boolean" _gui-text="Remove rectangle">true</param> + <param name="drawaxis" type="boolean" _gui-text="Draw Axes">false</param> + <param name="endpts" type="boolean" _gui-text="Add x-axis endpoints">false</param> + <effect> + <object-type>rect</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">funcplot.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/funcplot.py b/share/extensions/funcplot.py index 126429853..0beaf3946 100644 --- a/share/extensions/funcplot.py +++ b/share/extensions/funcplot.py @@ -30,7 +30,7 @@ from math import * from random import * def drawfunction(xstart, xend, ybottom, ytop, samples, width, height, left, bottom, - fx = "sin(x)", fpx = "cos(x)", fponum = True, times2pi = False, polar = False, isoscale = True, drawaxis = True): + fx = "sin(x)", fpx = "cos(x)", fponum = True, times2pi = False, polar = False, isoscale = True, drawaxis = True, endpts = False): if times2pi == True: xstart = 2 * pi * xstart @@ -122,7 +122,11 @@ def drawfunction(xstart, xend, ybottom, ytop, samples, width, height, left, bott dy0 = fp(xstart) # Start curve - a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto + if endpts: + a.append([' M ',[left, coordy(0)]]) + a.append([' L ',[coordx(x0), coordy(y0)]]) + else: + a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto for i in range(int(samples-1)): x1 = (i+1) * step + xstart @@ -153,7 +157,9 @@ def drawfunction(xstart, xend, ybottom, ytop, samples, width, height, left, bott x0 = x1 # Next segment's start is this segments end y0 = y1 dx0 = dx1 # Assume the function is smooth everywhere, so carry over the derivative too - dy0 = dy1 + dy0 = dy1 + if endpts: + a.append([' L ',[left + width, coordy(0)]]) return a class FuncPlot(inkex.Effect): @@ -211,6 +217,10 @@ class FuncPlot(inkex.Effect): action="store", type="inkbool", dest="drawaxis", default=True, help="If True, axis are drawn") + self.OptionParser.add_option("--endpts", + action="store", type="inkbool", + dest="endpts", default=False, + help="If True, end points are added") self.OptionParser.add_option("--tab", action="store", type="string", dest="tab", default="sampling", @@ -257,7 +267,8 @@ class FuncPlot(inkex.Effect): self.options.times2pi, self.options.polar, self.options.isoscale, - self.options.drawaxis))) + self.options.drawaxis, + self.options.endpts))) newpath.set('title', self.options.fofx) #newpath.setAttribute('desc', '!func;' + self.options.fofx + ';' @@ -278,4 +289,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/gcodetools.py b/share/extensions/gcodetools.py new file mode 100644 index 000000000..37e89b318 --- /dev/null +++ b/share/extensions/gcodetools.py @@ -0,0 +1,4603 @@ +#!/usr/bin/env python +""" +Copyright (C) 2009 Nick Drobchenko, nick@cnc-club.ru +based on gcode.py (C) 2007 hugomatic... +based on addnodes.py (C) 2005,2007 Aaron Spike, aaron@ekips.org +based on dots.py (C) 2005 Aaron Spike, aaron@ekips.org +based on interp.py (C) 2005 Aaron Spike, aaron@ekips.org +based on bezmisc.py (C) 2005 Aaron Spike, aaron@ekips.org +based on cubicsuperpath.py (C) 2005 Aaron Spike, aaron@ekips.org + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +### +### Gcodetools v 1.6.03 +### +gcodetools_current_version = "1.6.03" + +import inkex, simplestyle, simplepath +import cubicsuperpath, simpletransform, bezmisc + +import os +import math +import bezmisc +import re +import copy +import sys +import time +import cmath +import numpy +import codecs +import random +import gettext +_ = gettext.gettext + + +### Check if inkex has errormsg (0.46 version doesnot have one.) Could be removed later. +if "errormsg" not in dir(inkex): + inkex.errormsg = lambda msg: sys.stderr.write((unicode(msg) + "\n").encode("UTF-8")) + + +def bezierslopeatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t): + ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) + dx=3*ax*(t**2)+2*bx*t+cx + dy=3*ay*(t**2)+2*by*t+cy + if dx==dy==0 : + dx = 6*ax*t+2*bx + dy = 6*ay*t+2*by + if dx==dy==0 : + dx = 6*ax + dy = 6*ay + if dx==dy==0 : + print_("Slope error x = %s*t^3+%s*t^2+%s*t+%s, y = %s*t^3+%s*t^2+%s*t+%s, t = %s, dx==dy==0" % (ax,bx,cx,dx,ay,by,cy,dy,t)) + print_(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) + dx, dy = 1, 1 + + return dx,dy +bezmisc.bezierslopeatt = bezierslopeatt + + +def ireplace(self,old,new,count=0): + pattern = re.compile(re.escape(old),re.I) + return re.sub(pattern,new,self,count) + +################################################################################ +### +### Styles and additional parameters +### +################################################################################ + +math.pi2 = math.pi*2 +straight_tolerance = 0.0001 +straight_distance_tolerance = 0.0001 +engraving_tolerance = 0.0001 +loft_lengths_tolerance = 0.0000001 +options = {} +defaults = { +'header': """% +(Header) +(Generated by gcodetools from Inkscape.) +(Using default header. To add your own header create file "header" in the output dir.) +M3 +(Header end.) +""", +'footer': """ +(Footer) +M5 +G00 X0.0000 Y0.0000 +M2 +(Using default footer. To add your own footer create file "footer" in the output dir.) +(end) +%""" +} + +intersection_recursion_depth = 10 +intersection_tolerance = 0.00001 + +styles = { + "loft_style" : { + 'main curve': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', 'stroke-width':'1', 'marker-end':'url(#Arrow2Mend)' }), + }, + "biarc_style" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#88f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#8f8', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'line': simplestyle.formatStyle({ 'stroke': '#f88', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'area': simplestyle.formatStyle({ 'stroke': '#777', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }), + }, + "biarc_style_dark" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_dark_area" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#33a', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#3a3', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }), + 'line': simplestyle.formatStyle({ 'stroke': '#a33', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.1' }), + 'area': simplestyle.formatStyle({ 'stroke': '#222', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_i" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#880', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#808', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'line': simplestyle.formatStyle({ 'stroke': '#088', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'area': simplestyle.formatStyle({ 'stroke': '#999', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_dark_i" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#dd5', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#d5d', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'line': simplestyle.formatStyle({ 'stroke': '#5dd', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'1' }), + 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_lathe_feed" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_lathe_passing feed" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#07f', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#0f7', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'line': simplestyle.formatStyle({ 'stroke': '#f44', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "biarc_style_lathe_fine feed" : { + 'biarc0': simplestyle.formatStyle({ 'stroke': '#7f0', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'biarc1': simplestyle.formatStyle({ 'stroke': '#f70', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'line': simplestyle.formatStyle({ 'stroke': '#744', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'.4' }), + 'area': simplestyle.formatStyle({ 'stroke': '#aaa', 'fill': 'none', "marker-end":"url(#DrawCurveMarker)", 'stroke-width':'0.3' }), + }, + "area artefact": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }), + "area artefact arrow": simplestyle.formatStyle({ 'stroke': '#ff0000', 'fill': '#ffff00', 'stroke-width':'1' }), + "dxf_points": simplestyle.formatStyle({ "stroke": "#ff0000", "fill": "#ff0000"}), + + } + + +################################################################################ +### Cubic Super Path additional functions +################################################################################ + +def csp_simple_bound(csp): + minx,miny,maxx,maxy = None,None,None,None + for subpath in csp: + for sp in subpath : + for p in sp: + minx = min(minx,p[0]) if minx!=None else p[0] + miny = min(miny,p[1]) if miny!=None else p[1] + maxx = max(maxx,p[0]) if maxx!=None else p[0] + maxy = max(maxy,p[1]) if maxy!=None else p[1] + return minx,miny,maxx,maxy + + +def csp_segment_to_bez(sp1,sp2) : + return sp1[1:]+sp2[:2] + + +def bound_to_bound_distance(sp1,sp2,sp3,sp4) : + min_dist = 1e100 + max_dist = 0 + points1 = csp_segment_to_bez(sp1,sp2) + points2 = csp_segment_to_bez(sp3,sp4) + for i in range(4) : + for j in range(4) : + min_, max_ = line_to_line_min_max_distance_2(points1[i-1], points1[i], points2[j-1], points2[j]) + min_dist = min(min_dist,min_) + max_dist = max(max_dist,max_) + print_("bound_to_bound", min_dist, max_dist) + return min_dist, max_dist + +def csp_to_point_distance(csp, p, dist_bounds = [0,1e100], tolerance=.01) : + min_dist = [1e100,0,0,0] + for j in range(len(csp)) : + for i in range(1,len(csp[j])) : + d = csp_seg_to_point_distance(csp[j][i-1],csp[j][i],p,sample_points = 5, tolerance = .01) + if d[0] < dist_bounds[0] : +# draw_pointer( list(csp_at_t(subpath[dist[2]-1],subpath[dist[2]],dist[3])) +# +list(csp_at_t(csp[dist[4]][dist[5]-1],csp[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0])) + return [d[0],j,i,d[1]] + else : + if d[0] < min_dist[0] : min_dist = [d[0],j,i,d[1]] + return min_dist + +def csp_seg_to_point_distance(sp1,sp2,p,sample_points = 5, tolerance = .01) : + ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2) + dx, dy = dx-p[0], dy-p[1] + if sample_points < 2 : sample_points = 2 + d = min( [(p[0]-sp1[1][0])**2 + (p[1]-sp1[1][1])**2,0.], [(p[0]-sp2[1][0])**2 + (p[1]-sp2[1][1])**2,1.] ) + for k in range(sample_points) : + t = float(k)/(sample_points-1) + i = 0 + while i==0 or abs(f)>0.000001 and i<20 : + t2,t3 = t**2,t**3 + f = (ax*t3+bx*t2+cx*t+dx)*(3*ax*t2+2*bx*t+cx) + (ay*t3+by*t2+cy*t+dy)*(3*ay*t2+2*by*t+cy) + df = (6*ax*t+2*bx)*(ax*t3+bx*t2+cx*t+dx) + (3*ax*t2+2*bx*t+cx)**2 + (6*ay*t+2*by)*(ay*t3+by*t2+cy*t+dy) + (3*ay*t2+2*by*t+cy)**2 + if df!=0 : + t = t - f/df + else : + break + i += 1 + if 0<=t<=1 : + p1 = csp_at_t(sp1,sp2,t) + d1 = (p1[0]-p[0])**2 + (p1[1]-p[1])**2 + if d1 < d[0] : + d = [d1,t] + return d + + +def csp_seg_to_csp_seg_distance(sp1,sp2,sp3,sp4, dist_bounds = [0,1e100], sample_points = 5, tolerance=.01) : + # check the ending points first + dist = csp_seg_to_point_distance(sp1,sp2,sp3[1],sample_points, tolerance) + dist += [0.] + if dist[0] <= dist_bounds[0] : return dist + d = csp_seg_to_point_distance(sp1,sp2,sp4[1],sample_points, tolerance) + if d[0]<dist[0] : + dist = d+[1.] + if dist[0] <= dist_bounds[0] : return dist + d = csp_seg_to_point_distance(sp3,sp4,sp1[1],sample_points, tolerance) + if d[0]<dist[0] : + dist = [d[0],0.,d[1]] + if dist[0] <= dist_bounds[0] : return dist + d = csp_seg_to_point_distance(sp3,sp4,sp2[1],sample_points, tolerance) + if d[0]<dist[0] : + dist = [d[0],1.,d[1]] + if dist[0] <= dist_bounds[0] : return dist + sample_points -= 2 + if sample_points < 1 : sample_points = 1 + ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2) + ax2,ay2,bx2,by2,cx2,cy2,dx2,dy2 = csp_parameterize(sp3,sp4) + # try to find closes points using Newtons method + for k in range(sample_points) : + for j in range(sample_points) : + t1,t2 = float(k+1)/(sample_points+1), float(j)/(sample_points+1) + t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2 + i = 0 + F1, F2, F = [0,0], [[0,0],[0,0]], 1e100 + x,y = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2) + while i<2 or abs(F-Flast)>tolerance and i<30 : + #draw_pointer(csp_at_t(sp1,sp2,t1)) + f1x = 3*ax1*t12+2*bx1*t1+cx1 + f1y = 3*ay1*t12+2*by1*t1+cy1 + f2x = 3*ax2*t22+2*bx2*t2+cx2 + f2y = 3*ay2*t22+2*by2*t2+cy2 + F1[0] = 2*f1x*x + 2*f1y*y + F1[1] = -2*f2x*x - 2*f2y*y + F2[0][0] = 2*(6*ax1*t1+2*bx1)*x + 2*f1x*f1x + 2*(6*ay1*t1+2*by1)*y +2*f1y*f1y + F2[0][1] = -2*f1x*f2x - 2*f1y*f2y + F2[1][0] = -2*f2x*f1x - 2*f2y*f1y + F2[1][1] = -2*(6*ax2*t2+2*bx2)*x + 2*f2x*f2x - 2*(6*ay2*t2+2*by2)*y + 2*f2y*f2y + F2 = inv_2x2(F2) + if F2!=None : + t1 -= ( F2[0][0]*F1[0] + F2[0][1]*F1[1] ) + t2 -= ( F2[1][0]*F1[0] + F2[1][1]*F1[1] ) + t12, t13, t22, t23 = t1*t1, t1*t1*t1, t2*t2, t2*t2*t2 + x,y = ax1*t13+bx1*t12+cx1*t1+dx1 - (ax2*t23+bx2*t22+cx2*t2+dx2), ay1*t13+by1*t12+cy1*t1+dy1 - (ay2*t23+by2*t22+cy2*t2+dy2) + Flast = F + F = x*x+y*y + else : + break + i += 1 + if F < dist[0] and 0<=t1<=1 and 0<=t2<=1: + dist = [F,t1,t2] + if dist[0] <= dist_bounds[0] : + return dist + return dist + + +def csp_to_csp_distance(csp1,csp2, dist_bounds = [0,1e100], tolerance=.01) : + dist = [1e100,0,0,0,0,0,0] + for i1 in range(len(csp1)) : + for j1 in range(1,len(csp1[i1])) : + for i2 in range(len(csp2)) : + for j2 in range(1,len(csp2[i2])) : + d = csp_seg_bound_to_csp_seg_bound_max_min_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2]) + if d[0] >= dist_bounds[1] : continue + if d[1] < dist_bounds[0] : return [d[1],i1,j1,1,i2,j2,1] + d = csp_seg_to_csp_seg_distance(csp1[i1][j1-1],csp1[i1][j1],csp2[i2][j2-1],csp2[i2][j2], dist_bounds, tolerance=tolerance) + if d[0] < dist[0] : + dist = [d[0], i1,j1,d[1], i2,j2,d[2]] + if dist[0] <= dist_bounds[0] : + return dist + if dist[0] >= dist_bounds[1] : + return dist + return dist +# draw_pointer( list(csp_at_t(csp1[dist[1]][dist[2]-1],csp1[dist[1]][dist[2]],dist[3])) +# + list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])), "#507","line") + + +def csp_split(sp1,sp2,t=.5) : + [x1,y1],[x2,y2],[x3,y3],[x4,y4] = sp1[1], sp1[2], sp2[0], sp2[1] + x12 = x1+(x2-x1)*t + y12 = y1+(y2-y1)*t + x23 = x2+(x3-x2)*t + y23 = y2+(y3-y2)*t + x34 = x3+(x4-x3)*t + y34 = y3+(y4-y3)*t + x1223 = x12+(x23-x12)*t + y1223 = y12+(y23-y12)*t + x2334 = x23+(x34-x23)*t + y2334 = y23+(y34-y23)*t + x = x1223+(x2334-x1223)*t + y = y1223+(y2334-y1223)*t + return [sp1[0],sp1[1],[x12,y12]], [[x1223,y1223],[x,y],[x2334,y2334]], [[x34,y34],sp2[1],sp2[2]] + +def csp_true_bounds(csp) : + # Finds minx,miny,maxx,maxy of the csp and return their (x,y,i,j,t) + minx = [float("inf"), 0, 0, 0] + maxx = [float("-inf"), 0, 0, 0] + miny = [float("inf"), 0, 0, 0] + maxy = [float("-inf"), 0, 0, 0] + for i in range(len(csp)): + for j in range(1,len(csp[i])): + ax,ay,bx,by,cx,cy,x0,y0 = bezmisc.bezierparameterize((csp[i][j-1][1],csp[i][j-1][2],csp[i][j][0],csp[i][j][1])) + roots = cubic_solver(0, 3*ax, 2*bx, cx) + [0,1] + for root in roots : + if type(root) is complex and abs(root.imag)<1e-10: + root = root.real + if type(root) is not complex and 0<=root<=1: + y = ay*(root**3)+by*(root**2)+cy*root+y0 + x = ax*(root**3)+bx*(root**2)+cx*root+x0 + maxx = max([x,y,i,j,root],maxx) + minx = min([x,y,i,j,root],minx) + + roots = cubic_solver(0, 3*ay, 2*by, cy) + [0,1] + for root in roots : + if type(root) is complex and root.imag==0: + root = root.real + if type(root) is not complex and 0<=root<=1: + y = ay*(root**3)+by*(root**2)+cy*root+y0 + x = ax*(root**3)+bx*(root**2)+cx*root+x0 + maxy = max([y,x,i,j,root],maxy) + miny = min([y,x,i,j,root],miny) + maxy[0],maxy[1] = maxy[1],maxy[0] + miny[0],miny[1] = miny[1],miny[0] + + return minx,miny,maxx,maxy + + +############################################################################ +### csp_segments_intersection(sp1,sp2,sp3,sp4) +### +### Returns array containig all intersections between two segmets of cubic +### super path. Results are [ta,tb], or [ta0, ta1, tb0, tb1, "Overlap"] +### where ta, tb are values of t for the intersection point. +############################################################################ +def csp_segments_intersection(sp1,sp2,sp3,sp4) : + a, b = csp_segment_to_bez(sp1,sp2), csp_segment_to_bez(sp3,sp4) + + def polish_intersection(a,b,ta,tb, tolerance = intersection_tolerance) : + ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize(a) + ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = bezmisc.bezierparameterize(b) + i = 0 + F, F1 = [.0,.0], [[.0,.0],[.0,.0]] + while i==0 or (abs(F[0])**2+abs(F[1])**2 > tolerance and i<10): + ta3, ta2, tb3, tb2 = ta**3, ta**2, tb**3, tb**2 + F[0] = ax*ta3+bx*ta2+cx*ta+dx-ax1*tb3-bx1*tb2-cx1*tb-dx1 + F[1] = ay*ta3+by*ta2+cy*ta+dy-ay1*tb3-by1*tb2-cy1*tb-dy1 + F1[0][0] = 3*ax *ta2 + 2*bx *ta + cx + F1[0][1] = -3*ax1*tb2 - 2*bx1*tb - cx1 + F1[1][0] = 3*ay *ta2 + 2*by *ta + cy + F1[1][1] = -3*ay1*tb2 - 2*by1*tb - cy1 + det = F1[0][0]*F1[1][1] - F1[0][1]*F1[1][0] + if det!=0 : + F1 = [ [ F1[1][1]/det, -F1[0][1]/det], [-F1[1][0]/det, F1[0][0]/det] ] + ta = ta - ( F1[0][0]*F[0] + F1[0][1]*F[1] ) + tb = tb - ( F1[1][0]*F[0] + F1[1][1]*F[1] ) + else: break + i += 1 + + return ta, tb + + + def recursion(a,b, ta0,ta1,tb0,tb1, depth_a,depth_b) : + global bezier_intersection_recursive_result + if a==b : + bezier_intersection_recursive_result += [[ta0,tb0,ta1,tb1,"Overlap"]] + return + tam, tbm = (ta0+ta1)/2, (tb0+tb1)/2 + if depth_a>0 and depth_b>0 : + a1,a2 = bez_split(a,0.5) + b1,b2 = bez_split(b,0.5) + if bez_bounds_intersect(a1,b1) : recursion(a1,b1, ta0,tam,tb0,tbm, depth_a-1,depth_b-1) + if bez_bounds_intersect(a2,b1) : recursion(a2,b1, tam,ta1,tb0,tbm, depth_a-1,depth_b-1) + if bez_bounds_intersect(a1,b2) : recursion(a1,b2, ta0,tam,tbm,tb1, depth_a-1,depth_b-1) + if bez_bounds_intersect(a2,b2) : recursion(a2,b2, tam,ta1,tbm,tb1, depth_a-1,depth_b-1) + elif depth_a>0 : + a1,a2 = bez_split(a,0.5) + if bez_bounds_intersect(a1,b) : recursion(a1,b, ta0,tam,tb0,tb1, depth_a-1,depth_b) + if bez_bounds_intersect(a2,b) : recursion(a2,b, tam,ta1,tb0,tb1, depth_a-1,depth_b) + elif depth_b>0 : + b1,b2 = bez_split(b,0.5) + if bez_bounds_intersect(a,b1) : recursion(a,b1, ta0,ta1,tb0,tbm, depth_a,depth_b-1) + if bez_bounds_intersect(a,b2) : recursion(a,b2, ta0,ta1,tbm,tb1, depth_a,depth_b-1) + else : # Both segments have been subdevided enougth. Let's get some intersections :). + intersection, t1, t2 = straight_segments_intersection([a[0]]+[a[3]],[b[0]]+[b[3]]) + if intersection : + if intersection == "Overlap" : + t1 = ( max(0,min(1,t1[0]))+max(0,min(1,t1[1])) )/2 + t2 = ( max(0,min(1,t2[0]))+max(0,min(1,t2[1])) )/2 + bezier_intersection_recursive_result += [[ta0+t1*(ta1-ta0),tb0+t2*(tb1-tb0)]] + + global bezier_intersection_recursive_result + bezier_intersection_recursive_result = [] + recursion(a,b,0.,1.,0.,1.,intersection_recursion_depth,intersection_recursion_depth) + intersections = bezier_intersection_recursive_result + for i in range(len(intersections)) : + if len(intersections[i])<5 or intersections[i][4] != "Overlap" : + intersections[i] = polish_intersection(a,b,intersections[i][0],intersections[i][1]) + return intersections + + +def csp_segments_true_intersection(sp1,sp2,sp3,sp4) : + intersections = csp_segments_intersection(sp1,sp2,sp3,sp4) + res = [] + for intersection in intersections : + if ( + (len(intersection)==5 and intersection[4] == "Overlap" and (0<=intersection[0]<=1 or 0<=intersection[1]<=1) and (0<=intersection[2]<=1 or 0<=intersection[3]<=1) ) + or ( 0<=intersection[0]<=1 and 0<=intersection[1]<=1 ) + ) : + res += [intersection] + return res + + +def csp_get_t_at_curvature(sp1,sp2,c, sample_points = 16): + # returns a list containning [t1,t2,t3,...,tn], 0<=ti<=1... + if sample_points < 2 : sample_points = 2 + tolerance = .0000000001 + res = [] + ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2) + for k in range(sample_points) : + t = float(k)/(sample_points-1) + i, F = 0, 1e100 + while i<2 or abs(F)>tolerance and i<17 : + try : # some numerical calculation could exceed the limits + t2 = t*t + #slopes... + f1x = 3*ax*t2+2*bx*t+cx + f1y = 3*ay*t2+2*by*t+cy + f2x = 6*ax*t+2*bx + f2y = 6*ay*t+2*by + f3x = 6*ax + f3y = 6*ay + d = (f1x**2+f1y**2)**1.5 + F1 = ( + ( (f1x*f3y-f3x*f1y)*d - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*((f1x**2+f1y**2)**.5) ) / + ((f1x**2+f1y**2)**3) + ) + F = (f1x*f2y-f1y*f2x)/d - c + t -= F/F1 + except: + break + i += 1 + if 0<=t<=1 and F<=tolerance: + if len(res) == 0 : + res.append(t) + for i in res : + if abs(t-i)<=0.001 : + break + if not abs(t-i)<=0.001 : + res.append(t) + return res + + +def csp_max_curvature(sp1,sp2): + ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2) + tolerance = .0001 + F = 0. + i = 0 + while i<2 or F-Flast<tolerance and i<10 : + t = .5 + f1x = 3*ax*t**2 + 2*bx*t + cx + f1y = 3*ay*t**2 + 2*by*t + cy + f2x = 6*ax*t + 2*bx + f2y = 6*ay*t + 2*by + f3x = 6*ax + f3y = 6*ay + d = pow(f1x**2+f1y**2,1.5) + if d != 0 : + Flast = F + F = (f1x*f2y-f1y*f2x)/d + F1 = ( + ( d*(f1x*f3y-f3x*f1y) - (f1x*f2y-f2x*f1y)*3.*(f2x*f1x+f2y*f1y)*pow(f1x**2+f1y**2,.5) ) / + (f1x**2+f1y**2)**3 + ) + i+=1 + if F1!=0: + t -= F/F1 + else: + break + else: break + return t + + +def csp_curvature_at_t(sp1,sp2,t, depth = 3) : + ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2)) + + #curvature = (x'y''-y'x'') / (x'^2+y'^2)^1.5 + + f1x = 3*ax*t**2 + 2*bx*t + cx + f1y = 3*ay*t**2 + 2*by*t + cy + f2x = 6*ax*t + 2*bx + f2y = 6*ay*t + 2*by + d = (f1x**2+f1y**2)**1.5 + if d != 0 : + return (f1x*f2y-f1y*f2x)/d + else : + t1 = f1x*f2y-f1y*f2x + if t1 > 0 : return 1e100 + if t1 < 0 : return -1e100 + # Use the Lapitals rule to solve 0/0 problem for 2 times... + t1 = 2*(bx*ay-ax*by)*t+(ay*cx-ax*cy) + if t1 > 0 : return 1e100 + if t1 < 0 : return -1e100 + t1 = bx*ay-ax*by + if t1 > 0 : return 1e100 + if t1 < 0 : return -1e100 + if depth>0 : + # little hack ;^) hope it wont influence anything... + return csp_curvature_at_t(sp1,sp2,t*1.004, depth-1) + return 1e100 + + +def csp_curvature_radius_at_t(sp1,sp2,t) : + c = csp_curvature_at_t(sp1,sp2,t) + if c == 0 : return 1e100 + else: return 1/c + + +def csp_special_points(sp1,sp2) : + # special points = curvature == 0 + ax,ay,bx,by,cx,cy,dx,dy = bezmisc.bezierparameterize((sp1[1],sp1[2],sp2[0],sp2[1])) + a = 3*ax*by-3*ay*bx + b = 3*ax*cy-3*cx*ay + c = bx*cy-cx*by + roots = cubic_solver(0, a, b, c) + res = [] + for i in roots : + if type(i) is complex and i.imag==0: + i = i.real + if type(i) is not complex and 0<=i<=1: + res.append(i) + return res + + +def csp_subpath_ccw(subpath): + # Remove all zerro length segments + s = 0 + #subpath = subpath[:] + if (P(subpath[-1][1])-P(subpath[0][1])).l2() > 1e-10 : + subpath[-1][2] = subpath[-1][1] + subpath[0][0] = subpath[0][1] + subpath += [ [subpath[0][1],subpath[0][1],subpath[0][1]] ] + pl = subpath[-1][2] + for sp1 in subpath: + for p in sp1 : + s += (p[0]-pl[0])*(p[1]+pl[1]) + pl = p + return s<0 + + +def csp_at_t(sp1,sp2,t): + ax,bx,cx,dx = sp1[1][0], sp1[2][0], sp2[0][0], sp2[1][0] + ay,by,cy,dy = sp1[1][1], sp1[2][1], sp2[0][1], sp2[1][1] + + x1, y1 = ax+(bx-ax)*t, ay+(by-ay)*t + x2, y2 = bx+(cx-bx)*t, by+(cy-by)*t + x3, y3 = cx+(dx-cx)*t, cy+(dy-cy)*t + + x4,y4 = x1+(x2-x1)*t, y1+(y2-y1)*t + x5,y5 = x2+(x3-x2)*t, y2+(y3-y2)*t + + x,y = x4+(x5-x4)*t, y4+(y5-y4)*t + return [x,y] + + +def csp_splitatlength(sp1, sp2, l = 0.5, tolerance = 0.01): + bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) + t = bezmisc.beziertatlength(bez, l, tolerance) + return csp_split(sp1, sp2, t) + + +def cspseglength(sp1,sp2, tolerance = 0.001): + bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) + return bezmisc.bezierlength(bez, tolerance) + + +def csplength(csp): + total = 0 + lengths = [] + for sp in csp: + for i in xrange(1,len(sp)): + l = cspseglength(sp[i-1],sp[i]) + lengths.append(l) + total += l + return lengths, total + + +def csp_segments(csp): + l, seg = 0, [0] + for sp in csp: + for i in xrange(1,len(sp)): + l += cspseglength(sp[i-1],sp[i]) + seg += [ l ] + + if l>0 : + seg = [seg[i]/l for i in xrange(len(seg))] + return seg,l + + +def rebuild_csp (csp, segs, s=None): + # rebuild_csp() adds to csp control points making it's segments looks like segs + if s==None : s, l = csp_segments(csp) + + if len(s)>len(segs) : return None + segs = segs[:] + segs.sort() + for i in xrange(len(s)): + d = None + for j in xrange(len(segs)): + d = min( [abs(s[i]-segs[j]),j], d) if d!=None else [abs(s[i]-segs[j]),j] + del segs[d[1]] + for i in xrange(len(segs)): + for j in xrange(0,len(s)): + if segs[i]<s[j] : break + if s[j]-s[j-1] != 0 : + t = (segs[i] - s[j-1])/(s[j]-s[j-1]) + sp1,sp2,sp3 = csp_split(csp[j-1],csp[j], t) + csp = csp[:j-1] + [sp1,sp2,sp3] + csp[j+1:] + s = s[:j] + [ s[j-1]*(1-t)+s[j]*t ] + s[j:] + return csp, s + + +def csp_slope(sp1,sp2,t): + bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) + return bezmisc.bezierslopeatt(bez,t) + + +def csp_line_intersection(l1,l2,sp1,sp2): + dd=l1[0] + cc=l2[0]-l1[0] + bb=l1[1] + aa=l2[1]-l1[1] + if aa==cc==0 : return [] + if aa: + coef1=cc/aa + coef2=1 + else: + coef1=1 + coef2=aa/cc + bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) + ax,ay,bx,by,cx,cy,x0,y0=bezmisc.bezierparameterize(bez) + a=coef1*ay-coef2*ax + b=coef1*by-coef2*bx + c=coef1*cy-coef2*cx + d=coef1*(y0-bb)-coef2*(x0-dd) + roots = cubic_solver(a,b,c,d) + retval = [] + for i in roots : + if type(i) is complex and abs(i.imag)<1e-7: + i = i.real + if type(i) is not complex and -1e-10<=i<=1.+1e-10: + retval.append(i) + return retval + + +def csp_split_by_two_points(sp1,sp2,t1,t2) : + if t1>t2 : t1, t2 = t2, t1 + if t1 == t2 : + sp1,sp2,sp3 = csp_split(sp1,sp2,t) + return [sp1,sp2,sp2,sp3] + elif t1 <= 1e-10 and t2 >= 1.-1e-10 : + return [sp1,sp1,sp2,sp2] + elif t1 <= 1e-10: + sp1,sp2,sp3 = csp_split(sp1,sp2,t2) + return [sp1,sp1,sp2,sp3] + elif t2 >= 1.-1e-10 : + sp1,sp2,sp3 = csp_split(sp1,sp2,t1) + return [sp1,sp2,sp3,sp3] + else: + sp1,sp2,sp3 = csp_split(sp1,sp2,t1) + sp2,sp3,sp4 = csp_split(sp2,sp3,(t2-t1)/(1-t1) ) + return [sp1,sp2,sp3,sp4] + + +def csp_subpath_split_by_points(subpath, points) : + # points are [[i,t]...] where i-segment's number + points.sort() + points = [[1,0.]] + points + [[len(subpath)-1,1.]] + parts = [] + for int1,int2 in zip(points,points[1:]) : + if int1==int2 : + continue + if int1[1] == 1. : + int1[0] += 1 + int1[1] = 0. + if int1==int2 : + continue + if int2[1] == 0. : + int2[0] -= 1 + int2[1] = 1. + if int1[0] == 0 and int2[0]==len(subpath)-1:# and small(int1[1]) and small(int2[1]-1) : + continue + if int1[0]==int2[0] : # same segment + sp = csp_split_by_two_points(subpath[int1[0]-1],subpath[int1[0]],int1[1], int2[1]) + if sp[1]!=sp[2] : + parts += [ [sp[1],sp[2]] ] + else : + sp5,sp1,sp2 = csp_split(subpath[int1[0]-1],subpath[int1[0]],int1[1]) + sp3,sp4,sp5 = csp_split(subpath[int2[0]-1],subpath[int2[0]],int2[1]) + if int1[0]==int2[0]-1 : + parts += [ [sp1, [sp2[0],sp2[1],sp3[2]], sp4] ] + else : + parts += [ [sp1,sp2]+subpath[int1[0]+1:int2[0]-1]+[sp3,sp4] ] + return parts + + +def csp_from_arc(start, end, center, r, slope_st) : + # Creates csp that approximise specified arc + r = abs(r) + alpha = (atan2(end[0]-center[0],end[1]-center[1]) - atan2(start[0]-center[0],start[1]-center[1])) % math.pi2 + + sectors = int(abs(alpha)*2/math.pi)+1 + alpha_start = atan2(start[0]-center[0],start[1]-center[1]) + cos_,sin_ = math.cos(alpha_start), math.sin(alpha_start) + k = (4.*math.tan(alpha/sectors/4.)/3.) + if dot(slope_st , [- sin_*k*r, cos_*k*r]) < 0 : + if alpha>0 : alpha -= math.pi2 + else: alpha += math.pi2 + if abs(alpha*r)<0.001 : + return [] + + sectors = int(abs(alpha)*2/math.pi)+1 + k = (4.*math.tan(alpha/sectors/4.)/3.) + result = [] + for i in range(sectors+1) : + cos_,sin_ = math.cos(alpha_start + alpha*i/sectors), math.sin(alpha_start + alpha*i/sectors) + sp = [ [], [center[0] + cos_*r, center[1] + sin_*r], [] ] + sp[0] = [sp[1][0] + sin_*k*r, sp[1][1] - cos_*k*r ] + sp[2] = [sp[1][0] - sin_*k*r, sp[1][1] + cos_*k*r ] + result += [sp] + result[0][0] = result[0][1][:] + result[-1][2] = result[-1][1] + + return result + + +def point_to_arc_distance(p, arc): + ### Distance calculattion from point to arc + P0,P2,c,a = arc + dist = None + p = P(p) + r = (P0-c).mag() + if r>0 : + i = c + (p-c).unit()*r + alpha = ((i-c).angle() - (P0-c).angle()) + if a*alpha<0: + if alpha>0: alpha = alpha-math.pi2 + else: alpha = math.pi2+alpha + if between(alpha,0,a) or min(abs(alpha),abs(alpha-a))<straight_tolerance : + return (p-i).mag(), [i.x, i.y] + else : + d1, d2 = (p-P0).mag(), (p-P2).mag() + if d1<d2 : + return (d1, [P0.x,P0.y]) + else : + return (d2, [P2.x,P2.y]) + + +def csp_to_arc_distance(sp1,sp2, arc1, arc2, tolerance = 0.01 ): # arc = [start,end,center,alpha] + n, i = 10, 0 + d, d1, dl = (0,(0,0)), (0,(0,0)), 0 + while i<1 or (abs(d1[0]-dl[0])>tolerance and i<4): + i += 1 + dl = d1*1 + for j in range(n+1): + t = float(j)/n + p = csp_at_t(sp1,sp2,t) + d = min(point_to_arc_distance(p,arc1), point_to_arc_distance(p,arc2)) + d1 = max(d1,d) + n=n*2 + return d1[0] + + +def csp_simple_bound_to_point_distance(p, csp): + minx,miny,maxx,maxy = None,None,None,None + for subpath in csp: + for sp in subpath: + for p_ in sp: + minx = min(minx,p_[0]) if minx!=None else p_[0] + miny = min(miny,p_[1]) if miny!=None else p_[1] + maxx = max(maxx,p_[0]) if maxx!=None else p_[0] + maxy = max(maxy,p_[1]) if maxy!=None else p_[1] + return math.sqrt(max(minx-p[0],p[0]-maxx,0)**2+max(miny-p[1],p[1]-maxy,0)**2) + + +def csp_point_inside_bound(sp1, sp2, p): + bez = [sp1[1],sp1[2],sp2[0],sp2[1]] + x,y = p + c = 0 + for i in range(4): + [x0,y0], [x1,y1] = bez[i-1], bez[i] + if x0-x1!=0 and (y-y0)*(x1-x0)>=(x-x0)*(y1-y0) and x>min(x0,x1) and x<=max(x0,x1) : + c +=1 + return c%2==0 + + +def csp_bound_to_point_distance(sp1, sp2, p): + if csp_point_inside_bound(sp1, sp2, p) : + return 0. + bez = csp_segment_to_bez(sp1,sp2) + min_dist = 1e100 + for i in range(0,4): + d = point_to_line_segment_distance_2(p, bez[i-1],bez[i]) + if d <= min_dist : min_dist = d + return min_dist + + +def line_line_intersect(p1,p2,p3,p4) : # Return only true intersection. + if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return False + x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0]) + if x==0 : # Lines are parallel + if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) : + if p3[0]!=p4[0] : + t11 = (p1[0]-p3[0])/(p4[0]-p3[0]) + t12 = (p2[0]-p3[0])/(p4[0]-p3[0]) + t21 = (p3[0]-p1[0])/(p2[0]-p1[0]) + t22 = (p4[0]-p1[0])/(p2[0]-p1[0]) + else: + t11 = (p1[1]-p3[1])/(p4[1]-p3[1]) + t12 = (p2[1]-p3[1])/(p4[1]-p3[1]) + t21 = (p3[1]-p1[1])/(p2[1]-p1[1]) + t22 = (p4[1]-p1[1])/(p2[1]-p1[1]) + return ("Overlap" if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or 0<=t22<=1) else False) + else: return False + else : + return ( + 0<=((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x<=1 and + 0<=((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x<=1 ) + + +def line_line_intersection_points(p1,p2,p3,p4) : # Return only points [ (x,y) ] + if (p1[0]==p2[0] and p1[1]==p2[1]) or (p3[0]==p4[0] and p3[1]==p4[1]) : return [] + x = (p2[0]-p1[0])*(p4[1]-p3[1]) - (p2[1]-p1[1])*(p4[0]-p3[0]) + if x==0 : # Lines are parallel + if (p3[0]-p1[0])*(p2[1]-p1[1]) == (p3[1]-p1[1])*(p2[0]-p1[0]) : + if p3[0]!=p4[0] : + t11 = (p1[0]-p3[0])/(p4[0]-p3[0]) + t12 = (p2[0]-p3[0])/(p4[0]-p3[0]) + t21 = (p3[0]-p1[0])/(p2[0]-p1[0]) + t22 = (p4[0]-p1[0])/(p2[0]-p1[0]) + else: + t11 = (p1[1]-p3[1])/(p4[1]-p3[1]) + t12 = (p2[1]-p3[1])/(p4[1]-p3[1]) + t21 = (p3[1]-p1[1])/(p2[1]-p1[1]) + t22 = (p4[1]-p1[1])/(p2[1]-p1[1]) + res = [] + if (0<=t11<=1 or 0<=t12<=1) and (0<=t21<=1 or 0<=t22<=1) : + if 0<=t11<=1 : res += [p1] + if 0<=t12<=1 : res += [p2] + if 0<=t21<=1 : res += [p3] + if 0<=t22<=1 : res += [p4] + return res + else: return [] + else : + t1 = ((p4[0]-p3[0])*(p1[1]-p3[1]) - (p4[1]-p3[1])*(p1[0]-p3[0]))/x + t2 = ((p2[0]-p1[0])*(p1[1]-p3[1]) - (p2[1]-p1[1])*(p1[0]-p3[0]))/x + if 0<=t1<=1 and 0<=t2<=1 : return [ [p1[0]*(1-t1)+p2[0]*t1, p1[1]*(1-t1)+p2[1]*t1] ] + else : return [] + + +def point_to_point_d2(a,b): + return (a[0]-b[0])**2 + (a[1]-b[1])**2 + + +def point_to_point_d(a,b): + return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2) + + +def point_to_line_segment_distance_2(p1, p2,p3) : + # p1 - point, p2,p3 - line segment + #draw_pointer(p1) + w0 = [p1[0]-p2[0], p1[1]-p2[1]] + v = [p3[0]-p2[0], p3[1]-p2[1]] + c1 = w0[0]*v[0] + w0[1]*v[1] + if c1 <= 0 : + return w0[0]*w0[0]+w0[1]*w0[1] + c2 = v[0]*v[0] + v[1]*v[1] + if c2 <= c1 : + return (p1[0]-p3[0])**2 + (p1[1]-p3[1])**2 + return (p1[0]- p2[0]-v[0]*c1/c2)**2 + (p1[1]- p2[1]-v[1]*c1/c2) + + +def line_to_line_distance_2(p1,p2,p3,p4): + if line_line_intersect(p1,p2,p3,p4) : return 0 + return min( + point_to_line_segment_distance_2(p1,p3,p4), + point_to_line_segment_distance_2(p2,p3,p4), + point_to_line_segment_distance_2(p3,p1,p2), + point_to_line_segment_distance_2(p4,p1,p2)) + + +def csp_seg_bound_to_csp_seg_bound_max_min_distance(sp1,sp2,sp3,sp4) : + bez1 = csp_segment_to_bez(sp1,sp2) + bez2 = csp_segment_to_bez(sp3,sp4) + min_dist = 1e100 + max_dist = 0. + for i in range(4) : + if csp_point_inside_bound(sp1, sp2, bez2[i]) or csp_point_inside_bound(sp3, sp4, bez1[i]) : + min_dist = 0. + break + for i in range(4) : + for j in range(4) : + d = line_to_line_distance_2(bez1[i-1],bez1[i],bez2[j-1],bez2[j]) + if d < min_dist : min_dist = d + d = (bez2[j][0]-bez1[i][0])**2 + (bez2[j][1]-bez1[i][1])**2 + if max_dist < d : max_dist = d + return min_dist, max_dist + + +def csp_reverse(csp) : + for i in range(len(csp)) : + n = [] + for j in csp[i] : + n = [ [j[2][:],j[1][:],j[0][:]] ] + n + csp[i] = n[:] + return csp + + +def csp_normalized_slope(sp1,sp2,t) : + ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize((sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])) + if sp1[1]==sp2[1]==sp1[2]==sp2[0] : return [1.,0.] + f1x = 3*ax*t*t+2*bx*t+cx + f1y = 3*ay*t*t+2*by*t+cy + if abs(f1x*f1x+f1y*f1y) > 1e-20 : + l = math.sqrt(f1x*f1x+f1y*f1y) + return [f1x/l, f1y/l] + + if t == 0 : + f1x = sp2[0][0]-sp1[1][0] + f1y = sp2[0][1]-sp1[1][1] + if abs(f1x*f1x+f1y*f1y) > 1e-20 : + l = math.sqrt(f1x*f1x+f1y*f1y) + return [f1x/l, f1y/l] + else : + f1x = sp2[1][0]-sp1[1][0] + f1y = sp2[1][1]-sp1[1][1] + if f1x*f1x+f1y*f1y != 0 : + l = math.sqrt(f1x*f1x+f1y*f1y) + return [f1x/l, f1y/l] + elif t == 1 : + f1x = sp2[1][0]-sp1[2][0] + f1y = sp2[1][1]-sp1[2][1] + if abs(f1x*f1x+f1y*f1y) > 1e-20 : + l = math.sqrt(f1x*f1x+f1y*f1y) + return [f1x/l, f1y/l] + else : + f1x = sp2[1][0]-sp1[1][0] + f1y = sp2[1][1]-sp1[1][1] + if f1x*f1x+f1y*f1y != 0 : + l = math.sqrt(f1x*f1x+f1y*f1y) + return [f1x/l, f1y/l] + else : + return [1.,0.] + + +def csp_normalized_normal(sp1,sp2,t) : + nx,ny = csp_normalized_slope(sp1,sp2,t) + return [-ny, nx] + + +def csp_parameterize(sp1,sp2): + return bezmisc.bezierparameterize(csp_segment_to_bez(sp1,sp2)) + + +def csp_concat_subpaths(*s): + + def concat(s1,s2) : + if s1 == [] : return s2 + if s2 == [] : return s1 + if (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2 > 0.00001 : + return s1[:-1]+[ [s1[-1][0],s1[-1][1],s1[-1][1]], [s2[0][1],s2[0][1],s2[0][2]] ] + s2[1:] + else : + return s1[:-1]+[ [s1[-1][0],s2[0][1],s2[0][2]] ] + s2[1:] + + if len(s) == 0 : return [] + if len(s) ==1 : return s[0] + result = s[0] + for s1 in s[1:]: + result = concat(result,s1) + return result + + +def csp_draw(csp, color="#05f", group = None, style="fill:none;", width = .1, comment = "") : + if csp!=[] and csp!=[[]] : + if group == None : group = options.doc_root + style += "stroke:"+color+";"+ "stroke-width:%0.4fpx;"%width + args = {"d": cubicsuperpath.formatPath(csp), "style":style} + if comment!="" : args["comment"] = str(comment) + inkex.etree.SubElement( group, inkex.addNS('path','svg'), args ) + + +def csp_subpaths_end_to_start_distance2(s1,s2): + return (s1[-1][1][0]-s2[0][1][0])**2 + (s1[-1][1][1]-s2[0][1][1])**2 + + +def csp_clip_by_line(csp,l1,l2) : + result = [] + for i in range(len(csp)): + s = csp[i] + intersections = [] + for j in range(1,len(s)) : + intersections += [ [j,int_] for int_ in csp_line_intersection(l1,l2,s[j-1],s[j])] + splitted_s = csp_subpath_split_by_points(s, intersections) + for s in splitted_s[:] : + clip = False + for p in csp_true_bounds([s]) : + if (l1[1]-l2[1])*p[0] + (l2[0]-l1[0])*p[1] + (l1[0]*l2[1]-l2[0]*l1[1])<-0.01 : + clip = True + break + if clip : + splitted_s.remove(s) + result += splitted_s + return result + + +def csp_subpath_line_to(subpath, points) : + # Appends subpath with line or polyline. + if len(points)>0 : + if len(subpath)>0: + subpath[-1][2] = subpath[-1][1][:] + if type(points[0]) == type([1,1]) : + for p in points : + subpath += [ [p[:],p[:],p[:]] ] + else: + subpath += [ [points,points,points] ] + return subpath + + +def csp_join_subpaths(csp) : + result = csp[:] + done_smf = True + joined_result = [] + while done_smf : + done_smf = False + while len(result)>0: + s1 = result[-1][:] + del(result[-1]) + j = 0 + joined_smf = False + while j<len(joined_result) : + if csp_subpaths_end_to_start_distance2(joined_result[j],s1) <0.000001 : + joined_result[j] = csp_concat_subpaths(joined_result[j],s1) + done_smf = True + joined_smf = True + break + if csp_subpaths_end_to_start_distance2(s1,joined_result[j]) <0.000001 : + joined_result[j] = csp_concat_subpaths(s1,joined_result[j]) + done_smf = True + joined_smf = True + break + j += 1 + if not joined_smf : joined_result += [s1[:]] + if done_smf : + result = joined_result[:] + joined_result = [] + return joined_result + + +def triangle_cross(a,b,c): + return (a[0]-b[0])*(c[1]-b[1]) - (c[0]-b[0])*(a[1]-b[1]) + + +def csp_segment_convex_hull(sp1,sp2): + a,b,c,d = sp1[1][:], sp1[2][:], sp2[0][:], sp2[1][:] + + abc = triangle_cross(a,b,c) + abd = triangle_cross(a,b,d) + bcd = triangle_cross(b,c,d) + cad = triangle_cross(c,a,d) + if abc == 0 and abd == 0 : return [min(a,b,c,d), max(a,b,c,d)] + if abc == 0 : return [d, min(a,b,c), max(a,b,c)] + if abd == 0 : return [c, min(a,b,d), max(a,b,d)] + if bcd == 0 : return [a, min(b,c,d), max(b,c,d)] + if cad == 0 : return [b, min(c,a,d), max(c,a,d)] + + m1, m2, m3 = abc*abd>0, abc*bcd>0, abc*cad>0 + if m1 and m2 and m3 : return [a,b,c] + if m1 and m2 and not m3 : return [a,b,c,d] + if m1 and not m2 and m3 : return [a,b,d,c] + if not m1 and m2 and m3 : return [a,d,b,c] + if m1 and not (m2 and m3) : return [a,b,d] + if not (m1 and m2) and m3 : return [c,a,d] + if not (m1 and m3) and m2 : return [b,c,d] + + raise ValueError, "csp_segment_convex_hull happend something that shouldnot happen!" + + +################################################################################ +### Bezier additional functions +################################################################################ + +def bez_bounds_intersect(bez1, bez2) : + return bounds_intersect(bez_bound(bez2), bez_bound(bez1)) + + +def bez_bound(bez) : + return [ + min(bez[0][0], bez[1][0], bez[2][0], bez[3][0]), + min(bez[0][1], bez[1][1], bez[2][1], bez[3][1]), + max(bez[0][0], bez[1][0], bez[2][0], bez[3][0]), + max(bez[0][1], bez[1][1], bez[2][1], bez[3][1]), + ] + + +def bounds_intersect(a, b) : + return not ( (a[0]>b[2]) or (b[0]>a[2]) or (a[1]>b[3]) or (b[1]>a[3]) ) + + +def tpoint((x1,y1),(x2,y2),t): + return [x1+t*(x2-x1),y1+t*(y2-y1)] + + +def bez_to_csp_segment(bez) : + return [bez[0],bez[0],bez[1]], [bez[2],bez[3],bez[3]] + + +def bez_split(a,t=0.5) : + a1 = tpoint(a[0],a[1],t) + at = tpoint(a[1],a[2],t) + b2 = tpoint(a[2],a[3],t) + a2 = tpoint(a1,at,t) + b1 = tpoint(b2,at,t) + a3 = tpoint(a2,b1,t) + return [a[0],a1,a2,a3], [a3,b1,b2,a[3]] + + +def bez_at_t(bez,t) : + return csp_at_t([bez[0],bez[0],bez[1]],[bez[2],bez[3],bez[3]],t) + + +def bez_to_point_distance(bez,p,needed_dist=[0.,1e100]): + # returns [d^2,t] + return csp_seg_to_point_distance(bez_to_csp_segment(bez),p,needed_dist) + + +def bez_normalized_slope(bez,t): + return csp_normalized_slope([bez[0],bez[0],bez[1]], [bez[2],bez[3],bez[3]],t) + +################################################################################ +### Some vector functions +################################################################################ + +def normalize((x,y)) : + l = math.sqrt(x**2+y**2) + if l == 0 : return [0.,0.] + else : return [x/l, y/l] + + +def cross(a,b) : + return a[1] * b[0] - a[0] * b[1] + + +def dot(a,b) : + return a[0] * b[0] + a[1] * b[1] + + +def rotate_ccw(d) : + return [-d[1],d[0]] + + +def vectors_ccw(a,b): + return a[0]*b[1]-b[0]*a[1] < 0 + + +def vector_from_to_length(a,b): + return math.sqrt((a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1])) + +################################################################################ +### Common functions +################################################################################ + +def matrix_mul(a,b) : + return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ]) for j in range(len(b[0]))] for i in range(len(a))] + try : + return [ [ sum([a[i][k]*b[k][j] for k in range(len(a[0])) ]) for j in range(len(b[0]))] for i in range(len(a))] + except : + return None + + +def transpose(a) : + try : + return [ [ a[i][j] for i in range(len(a)) ] for j in range(len(a[0])) ] + except : + return None + + +def det_3x3(a): + return float( + a[0][0]*a[1][1]*a[2][2] + a[0][1]*a[1][2]*a[2][0] + a[1][0]*a[2][1]*a[0][2] + - a[0][2]*a[1][1]*a[2][0] - a[0][0]*a[2][1]*a[1][2] - a[0][1]*a[2][2]*a[1][0] + ) + + +def inv_3x3(a): # invert matrix 3x3 + det = det_3x3(a) + if det==0: return None + return [ + [ (a[1][1]*a[2][2] - a[2][1]*a[1][2])/det, -(a[0][1]*a[2][2] - a[2][1]*a[0][2])/det, (a[0][1]*a[1][2] - a[1][1]*a[0][2])/det ], + [ -(a[1][0]*a[2][2] - a[2][0]*a[1][2])/det, (a[0][0]*a[2][2] - a[2][0]*a[0][2])/det, -(a[0][0]*a[1][2] - a[1][0]*a[0][2])/det ], + [ (a[1][0]*a[2][1] - a[2][0]*a[1][1])/det, -(a[0][0]*a[2][1] - a[2][0]*a[0][1])/det, (a[0][0]*a[1][1] - a[1][0]*a[0][1])/det ] + ] + + +def inv_2x2(a): # invert matrix 2x2 + det = a[0][0]*a[1][1] - a[1][0]*a[0][1] + if det==0: return None + return [ + [a[1][1]/det, -a[0][1]/det], + [-a[1][0]/det, a[0][0]/det] + ] + + +def small(a) : + global small_tolerance + return abs(a)<small_tolerance + + +def atan2(*arg): + if len(arg)==1 and ( type(arg[0]) == type([0.,0.]) or type(arg[0])==type((0.,0.)) ) : + return (math.pi/2 - math.atan2(arg[0][0], arg[0][1]) ) % math.pi2 + elif len(arg)==2 : + + return (math.pi/2 - math.atan2(arg[0],arg[1]) ) % math.pi2 + else : + raise ValueError, "Bad argumets for atan! (%s)" % arg + + +def draw_text(text,x,y,style = None, font_size = 20) : + if style == None : + style = "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;" + style += "font-size:%fpx;"%font_size + t = inkex.etree.SubElement( options.doc_root, inkex.addNS('text','svg'), { + 'x': str(x), + inkex.addNS("space","xml"):"preserve", + 'y': str(y) + }) + text = str(text).split("\n") + for s in text : + span = inkex.etree.SubElement( t, inkex.addNS('tspan','svg'), + { + 'x': str(x), + 'y': str(+y), + inkex.addNS("role","sodipodi"):"line", + }) + y += font_size + span.text = s + + +def draw_pointer(x,color = "#f00", figure = "cross", comment = "", width = .1) : + if figure == "line" : + s = "" + for i in range(1,len(x)/2) : + s+= " %s, %s " %(x[i*2],x[i*2+1]) + inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} ) + else : + inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": "m %s,%s l 10,10 -20,-20 10,10 -10,10, 20,-20"%(x[0],x[1]), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)} ) + + +def straight_segments_intersection(a,b, true_intersection = True) : # (True intersection means check ta and tb are in [0,1]) + ax,bx,cx,dx, ay,by,cy,dy = a[0][0],a[1][0],b[0][0],b[1][0], a[0][1],a[1][1],b[0][1],b[1][1] + if (ax==bx and ay==by) or (cx==dx and cy==dy) : return False, 0, 0 + if (bx-ax)*(dy-cy)-(by-ay)*(dx-cx)==0 : # Lines are parallel + ta = (ax-cx)/(dx-cx) if cx!=dx else (ay-cy)/(dy-cy) + tb = (bx-cx)/(dx-cx) if cx!=dx else (by-cy)/(dy-cy) + tc = (cx-ax)/(bx-ax) if ax!=bx else (cy-ay)/(by-ay) + td = (dx-ax)/(bx-ax) if ax!=bx else (dy-ay)/(by-ay) + return ("Overlap" if 0<=ta<=1 or 0<=tb<=1 or 0<=tc<=1 or 0<=td<=1 or not true_intersection else False), (ta,tb), (tc,td) + else : + ta = ( (ay-cy)*(dx-cx)-(ax-cx)*(dy-cy) ) / ( (bx-ax)*(dy-cy)-(by-ay)*(dx-cx) ) + tb = ( ax-cx+ta*(bx-ax) ) / (dx-cx) if dx!=cx else ( ay-cy+ta*(by-ay) ) / (dy-cy) + return (0<=ta<=1 and 0<=tb<=1 or not true_intersection), ta, tb + + + +def isnan(x): return type(x) is float and x != x + +def isinf(x): inf = 1e5000; return x == inf or x == -inf + +def between(c,x,y): + return x-straight_tolerance<=c<=y+straight_tolerance or y-straight_tolerance<=c<=x+straight_tolerance + + +def cubic_solver(a,b,c,d): + if a!=0: + # Monics formula see http://en.wikipedia.org/wiki/Cubic_function#Monic_formula_of_roots + a,b,c = (b/a, c/a, d/a) + m = 2*a**3 - 9*a*b + 27*c + k = a**2 - 3*b + n = m**2 - 4*k**3 + w1 = -.5 + .5*cmath.sqrt(3)*1j + w2 = -.5 - .5*cmath.sqrt(3)*1j + if n>=0 : + t = m+math.sqrt(n) + m1 = pow(t/2,1./3) if t>=0 else -pow(-t/2,1./3) + t = m-math.sqrt(n) + n1 = pow(t/2,1./3) if t>=0 else -pow(-t/2,1./3) + else : + m1 = pow(complex((m+cmath.sqrt(n))/2),1./3) + n1 = pow(complex((m-cmath.sqrt(n))/2),1./3) + x1 = -1./3 * (a + m1 + n1) + x2 = -1./3 * (a + w1*m1 + w2*n1) + x3 = -1./3 * (a + w2*m1 + w1*n1) + return [x1,x2,x3] + elif b!=0: + det = c**2-4*b*d + if det>0 : + return [(-c+math.sqrt(det))/(2*b),(-c-math.sqrt(det))/(2*b)] + elif d == 0 : + return [-c/(b*b)] + else : + return [(-c+cmath.sqrt(det))/(2*b),(-c-cmath.sqrt(det))/(2*b)] + elif c!=0 : + return [-d/c] + else : return [] + + +################################################################################ +### print_ prints any arguments into specified log file +################################################################################ + +def print_(*arg): + f = open(options.log_filename,"a") + for s in arg : + s = str(unicode(s).encode('unicode_escape'))+" " + f.write( s ) + f.write("\n") + f.close() + + +################################################################################ +### Point (x,y) operations +################################################################################ +class P: + def __init__(self, x, y=None): + if not y==None: + self.x, self.y = float(x), float(y) + else: + self.x, self.y = float(x[0]), float(x[1]) + def __add__(self, other): return P(self.x + other.x, self.y + other.y) + def __sub__(self, other): return P(self.x - other.x, self.y - other.y) + def __neg__(self): return P(-self.x, -self.y) + def __mul__(self, other): + if isinstance(other, P): + return self.x * other.x + self.y * other.y + return P(self.x * other, self.y * other) + __rmul__ = __mul__ + def __div__(self, other): return P(self.x / other, self.y / other) + def mag(self): return math.hypot(self.x, self.y) + def unit(self): + h = self.mag() + if h: return self / h + else: return P(0,0) + def dot(self, other): return self.x * other.x + self.y * other.y + def rot(self, theta): + c = math.cos(theta) + s = math.sin(theta) + return P(self.x * c - self.y * s, self.x * s + self.y * c) + def angle(self): return math.atan2(self.y, self.x) + def __repr__(self): return '%f,%f' % (self.x, self.y) + def pr(self): return "%.2f,%.2f" % (self.x, self.y) + def to_list(self): return [self.x, self.y] + def ccw(self): return P(-self.y,self.x) + def l2(self): return self.x*self.x + self.y*self.y + +################################################################################ +### +### Offset function +### +### This function offsets given cubic super path. +### It's based on src/livarot/PathOutline.cpp from Inkscape's source code. +### +### +################################################################################ +def csp_offset(csp, r) : + offset_tolerance = 0.05 + offset_subdivision_depth = 10 + time_ = time.time() + time_start = time_ + print_("Offset start at %s"% time_) + print_("Offset radius %s"% r) + + + def csp_offset_segment(sp1,sp2,r) : + result = [] + t = csp_get_t_at_curvature(sp1,sp2,1/r) + if len(t) == 0 : t =[0.,1.] + t.sort() + if t[0]>.00000001 : t = [0.]+t + if t[-1]<.99999999 : t.append(1.) + for st,end in zip(t,t[1:]) : + c = csp_curvature_at_t(sp1,sp2,(st+end)/2) + sp = csp_split_by_two_points(sp1,sp2,st,end) + if sp[1]!=sp[2]: + if (c>1/r and r<0 or c<1/r and r>0) : + offset = offset_segment_recursion(sp[1],sp[2],r, offset_subdivision_depth, offset_tolerance) + else : # This part will be clipped for sure... TODO Optimize it... + offset = offset_segment_recursion(sp[1],sp[2],r, offset_subdivision_depth, offset_tolerance) + + if result==[] : + result = offset[:] + else: + if csp_subpaths_end_to_start_distance2(result,offset)<0.0001 : + result = csp_concat_subpaths(result,offset) + else: + + intersection = csp_get_subapths_last_first_intersection(result,offset) + if intersection != [] : + i,t1,j,t2 = intersection + sp1_,sp2_,sp3_ = csp_split(result[i-1],result[i],t1) + result = result[:i-1] + [ sp1_, sp2_ ] + sp1_,sp2_,sp3_ = csp_split(offset[j-1],offset[j],t2) + result = csp_concat_subpaths( result, [sp2_,sp3_] + offset[j+1:] ) + else : + pass # ??? + #raise ValueError, "Offset curvature clipping error" + #csp_draw([result]) + return result + + + def create_offset_segment(sp1,sp2,r) : + # See Gernot Hoffmann "Bezier Curves" p.34 -> 7.1 Bezier Offset Curves + p0,p1,p2,p3 = P(sp1[1]),P(sp1[2]),P(sp2[0]),P(sp2[1]) + s0,s1,s3 = p1-p0,p2-p1,p3-p2 + n0 = s0.ccw().unit() if s0.l2()!=0 else P(csp_normalized_normal(sp1,sp2,0)) + n3 = s3.ccw().unit() if s3.l2()!=0 else P(csp_normalized_normal(sp1,sp2,1)) + n1 = s1.ccw().unit() if s1.l2()!=0 else (n0.unit()+n3.unit()).unit() + + q0,q3 = p0+r*n0, p3+r*n3 + c = csp_curvature_at_t(sp1,sp2,0) + q1 = q0 + (p1-p0)*(1- (r*c if abs(c)<100 else 0) ) + c = csp_curvature_at_t(sp1,sp2,1) + q2 = q3 + (p2-p3)*(1- (r*c if abs(c)<100 else 0) ) + + + return [[q0.to_list(), q0.to_list(), q1.to_list()],[q2.to_list(), q3.to_list(), q3.to_list()]] + + + def csp_get_subapths_last_first_intersection(s1,s2): + _break = False + for i in range(1,len(s1)) : + sp11, sp12 = s1[-i-1], s1[-i] + for j in range(1,len(s2)) : + sp21,sp22 = s2[j-1], s2[j] + intersection = csp_segments_true_intersection(sp11,sp12,sp21,sp22) + if intersection != [] : + _break = True + break + if _break:break + if _break : + intersection = max(intersection) + return [len(s1)-i,intersection[0], j,intersection[1]] + else : + return [] + + + def csp_join_offsets(prev,next,sp1,sp2,sp1_l,sp2_l,r): + if len(next)>1 : + if (P(prev[-1][1])-P(next[0][1])).l2()<0.001 : + return prev,[],next + intersection = csp_get_subapths_last_first_intersection(prev,next) + if intersection != [] : + i,t1,j,t2 = intersection + sp1_,sp2_,sp3_ = csp_split(prev[i-1],prev[i],t1) + sp3_,sp4_,sp5_ = csp_split(next[j-1], next[j],t2) + return prev[:i-1] + [ sp1_, sp2_ ], [], [sp4_,sp5_] + next[j+1:] + + # Offsets do not intersect... will add an arc... + start = (P(csp_at_t(sp1_l,sp2_l,1.)) + r*P(csp_normalized_normal(sp1_l,sp2_l,1.))).to_list() + end = (P(csp_at_t(sp1,sp2,0.)) + r*P(csp_normalized_normal(sp1,sp2,0.))).to_list() + arc = csp_from_arc(start, end, sp1[1], r, csp_normalized_slope(sp1_l,sp2_l,1.) ) + if arc == [] : + return prev,[],next + else: + # Clip prev by arc + if csp_subpaths_end_to_start_distance2(prev,arc)>0.00001 : + intersection = csp_get_subapths_last_first_intersection(prev,arc) + if intersection != [] : + i,t1,j,t2 = intersection + sp1_,sp2_,sp3_ = csp_split(prev[i-1],prev[i],t1) + sp3_,sp4_,sp5_ = csp_split(arc[j-1],arc[j],t2) + prev = prev[:i-1] + [ sp1_, sp2_ ] + arc = [sp4_,sp5_] + arc[j+1:] + #else : raise ValueError, "Offset curvature clipping error" + # Clip next by arc + if next == [] : + return prev,[],arc + if csp_subpaths_end_to_start_distance2(arc,next)>0.00001 : + intersection = csp_get_subapths_last_first_intersection(arc,next) + if intersection != [] : + i,t1,j,t2 = intersection + sp1_,sp2_,sp3_ = csp_split(arc[i-1],arc[i],t1) + sp3_,sp4_,sp5_ = csp_split(next[j-1],next[j],t2) + arc = arc[:i-1] + [ sp1_, sp2_ ] + next = [sp4_,sp5_] + next[j+1:] + #else : raise ValueError, "Offset curvature clipping error" + + return prev,arc,next + + + def offset_segment_recursion(sp1,sp2,r, depth, tolerance) : + sp1_r,sp2_r = create_offset_segment(sp1,sp2,r) + err = max( + csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0], + csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.50)) + P(csp_normalized_normal(sp1,sp2,.50))*r).to_list())[0], + csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.75)) + P(csp_normalized_normal(sp1,sp2,.75))*r).to_list())[0], + ) + + if err>tolerance**2 and depth>0: + #print_(csp_seg_to_point_distance(sp1_r,sp2_r, (P(csp_at_t(sp1,sp2,.25)) + P(csp_normalized_normal(sp1,sp2,.25))*r).to_list())[0], tolerance) + if depth > offset_subdivision_depth-2 : + t = csp_max_curvature(sp1,sp2) + t = max(.1,min(.9 ,t)) + else : + t = .5 + sp3,sp4,sp5 = csp_split(sp1,sp2,t) + r1 = offset_segment_recursion(sp3,sp4,r, depth-1, tolerance) + r2 = offset_segment_recursion(sp4,sp5,r, depth-1, tolerance) + return r1[:-1]+ [[r1[-1][0],r1[-1][1],r2[0][2]]] + r2[1:] + else : + #csp_draw([[sp1_r,sp2_r]]) + #draw_pointer(sp1[1]+sp1_r[1], "#057", "line") + #draw_pointer(sp2[1]+sp2_r[1], "#705", "line") + return [sp1_r,sp2_r] + + + ############################################################################ + # Some small definitions + ############################################################################ + csp_len = len(csp) + + ############################################################################ + # Prepare the path + ############################################################################ + # Remove all small segments (segment length < 0.001) + + for i in xrange(len(csp)) : + for j in xrange(len(csp[i])) : + sp = csp[i][j] + if (P(sp[1])-P(sp[0])).mag() < 0.001 : + csp[i][j][0] = sp[1] + if (P(sp[2])-P(sp[0])).mag() < 0.001 : + csp[i][j][2] = sp[1] + for i in xrange(len(csp)) : + for j in xrange(1,len(csp[i])) : + if cspseglength(csp[i][j-1], csp[i][j])<0.001 : + csp[i] = csp[i][:j] + csp[i][j+1:] + if cspseglength(csp[i][-1],csp[i][0])>0.001 : + csp[i][-1][2] = csp[i][-1][1] + csp[i]+= [ [csp[i][0][1],csp[i][0][1],csp[i][0][1]] ] + + # TODO Get rid of self intersections. + + original_csp = csp[:] + # Clip segments which has curvature>1/r. Because their offset will be selfintersecting and very nasty. + + print_("Offset prepared the path in %s"%(time.time()-time_)) + print_("Path length = %s"% sum([len(i)for i in csp] ) ) + time_ = time.time() + + ############################################################################ + # Offset + ############################################################################ + # Create offsets for all segments in the path. And join them together inside each subpath. + unclipped_offset = [[] for i in xrange(csp_len)] + offsets_original = [[] for i in xrange(csp_len)] + join_points = [[] for i in xrange(csp_len)] + intersection = [[] for i in xrange(csp_len)] + for i in xrange(csp_len) : + subpath = csp[i] + subpath_offset = [] + last_offset_len = 0 + for sp1,sp2 in zip(subpath, subpath[1:]) : + segment_offset = csp_offset_segment(sp1,sp2,r) + if subpath_offset == [] : + subpath_offset = segment_offset + + prev_l = len(subpath_offset) + else : + prev, arc, next = csp_join_offsets(subpath_offset[-prev_l:],segment_offset,sp1,sp2,sp1_l,sp2_l,r) + #csp_draw([prev],"Blue") + #csp_draw([arc],"Magenta") + subpath_offset = csp_concat_subpaths(subpath_offset[:-prev_l+1],prev,arc,next) + prev_l = len(next) + sp1_l, sp2_l = sp1[:], sp2[:] + + # Join last and first offsets togother to close the curve + + prev, arc, next = csp_join_offsets(subpath_offset[-prev_l:], subpath_offset[:2], subpath[0], subpath[1], sp1_l,sp2_l, r) + subpath_offset[:2] = next[:] + subpath_offset = csp_concat_subpaths(subpath_offset[:-prev_l+1],prev,arc) + #csp_draw([prev],"Blue") + #csp_draw([arc],"Red") + #csp_draw([next],"Red") + + # Collect subpath's offset and save it to unclipped offset list. + unclipped_offset[i] = subpath_offset[:] + + #for k,t in intersection[i]: + # draw_pointer(csp_at_t(subpath_offset[k-1], subpath_offset[k], t)) + + #inkex.etree.SubElement( options.doc_root, inkex.addNS('path','svg'), {"d": cubicsuperpath.formatPath(unclipped_offset), "style":"fill:none;stroke:#0f0;"} ) + print_("Offsetted path in %s"%(time.time()-time_)) + time_ = time.time() + + #for i in range(len(unclipped_offset)): + # csp_draw([unclipped_offset[i]], color = ["Green","Red","Blue"][i%3], width = .1) + #return [] + ############################################################################ + # Now to the clipping. + ############################################################################ + # First of all find all intersection's between all segments of all offseted subpaths, including self intersections. + + #TODO define offset tolerance here + global small_tolerance + small_tolerance = 0.01 + summ = 0 + summ1 = 0 + for subpath_i in xrange(csp_len) : + for subpath_j in xrange(subpath_i,csp_len) : + subpath = unclipped_offset[subpath_i] + subpath1 = unclipped_offset[subpath_j] + for i in xrange(1,len(subpath)) : + # If subpath_i==subpath_j we are looking for self intersections, so + # we'll need search intersections only for xrange(i,len(subpath1)) + for j in ( xrange(i,len(subpath1)) if subpath_i==subpath_j else xrange(len(subpath1))) : + if subpath_i==subpath_j and j==i : + # Find self intersections of a segment + sp1,sp2,sp3 = csp_split(subpath[i-1],subpath[i],.5) + intersections = csp_segments_intersection(sp1,sp2,sp2,sp3) + summ +=1 + for t in intersections : + summ1 += 1 + if not ( small(t[0]-1) and small(t[1]) ) and 0<=t[0]<=1 and 0<=t[1]<=1 : + intersection[subpath_i] += [ [i,t[0]/2],[j,t[1]/2+.5] ] + else : + intersections = csp_segments_intersection(subpath[i-1],subpath[i],subpath1[j-1],subpath1[j]) + summ +=1 + for t in intersections : + summ1 += 1 + #TODO tolerance dependence to cpsp_length(t) + if len(t) == 2 and 0<=t[0]<=1 and 0<=t[1]<=1 and not ( + subpath_i==subpath_j and ( + (j-i-1) % (len(subpath)-1) == 0 and small(t[0]-1) and small(t[1]) or + (i-j-1) % (len(subpath)-1) == 0 and small(t[1]-1) and small(t[0]) ) ) : + intersection[subpath_i] += [ [i,t[0]] ] + intersection[subpath_j] += [ [j,t[1]] ] + #draw_pointer(csp_at_t(subpath[i-1],subpath[i],t[0]),"#f00") + #print_(t) + #print_(i,j) + elif len(t)==5 and t[4]=="Overlap": + intersection[subpath_i] += [ [i,t[0]], [i,t[1]] ] + intersection[subpath_j] += [ [j,t[1]], [j,t[3]] ] + + print_("Intersections found in %s"%(time.time()-time_)) + print_("Examined %s segments"%(summ)) + print_("found %s intersections"%(summ1)) + time_ = time.time() + + ######################################################################## + # Split unclipped offset by intersection points into splitted_offset + ######################################################################## + splitted_offset = [] + for i in xrange(csp_len) : + subpath = unclipped_offset[i] + if len(intersection[i]) > 0 : + parts = csp_subpath_split_by_points(subpath, intersection[i]) + # Close parts list to close path (The first and the last parts are joined together) + if [1,0.] not in intersection[i] : + parts[0][0][0] = parts[-1][-1][0] + parts[0] = csp_concat_subpaths(parts[-1], parts[0]) + splitted_offset += parts[:-1] + else: + splitted_offset += parts[:] + else : + splitted_offset += [subpath[:]] + + #for i in range(len(splitted_offset)): + # csp_draw([splitted_offset[i]], color = ["Green","Red","Blue"][i%3]) + print_("Splitted in %s"%(time.time()-time_)) + time_ = time.time() + + + ######################################################################## + # Clipping + ######################################################################## + result = [] + for subpath_i in range(len(splitted_offset)): + clip = False + s1 = splitted_offset[subpath_i] + for subpath_j in range(len(splitted_offset)): + s2 = splitted_offset[subpath_j] + if (P(s1[0][1])-P(s2[-1][1])).l2()<0.0001 and ( (subpath_i+1) % len(splitted_offset) != subpath_j ): + if dot(csp_normalized_normal(s2[-2],s2[-1],1.),csp_normalized_slope(s1[0],s1[1],0.))*r<-0.0001 : + clip = True + break + if (P(s2[0][1])-P(s1[-1][1])).l2()<0.0001 and ( (subpath_j+1) % len(splitted_offset) != subpath_i ): + if dot(csp_normalized_normal(s2[0],s2[1],0.),csp_normalized_slope(s1[-2],s1[-1],1.))*r>0.0001 : + clip = True + break + + if not clip : + result += [s1[:]] + elif options.offset_draw_clippend_path : + csp_draw([s1],color="Red",width=.1) + draw_pointer( csp_at_t(s2[-2],s2[-1],1.)+ + (P(csp_at_t(s2[-2],s2[-1],1.))+ P(csp_normalized_normal(s2[-2],s2[-1],1.))*10).to_list(),"Green", "line" ) + draw_pointer( csp_at_t(s1[0],s1[1],0.)+ + (P(csp_at_t(s1[0],s1[1],0.))+ P(csp_normalized_slope(s1[0],s1[1],0.))*10).to_list(),"Red", "line" ) + + # Now join all together and check closure and orientation of result + joined_result = csp_join_subpaths(result) + # Check if each subpath from joined_result is closed + #csp_draw(joined_result,color="Green",width=1) + + + for s in joined_result[:] : + if csp_subpaths_end_to_start_distance2(s,s) > 0.001 : + # Remove open parts + if options.offset_draw_clippend_path: + csp_draw([s],color="Orange",width=1) + draw_pointer(s[0][1], comment= csp_subpaths_end_to_start_distance2(s,s)) + draw_pointer(s[-1][1], comment = csp_subpaths_end_to_start_distance2(s,s)) + joined_result.remove(s) + else : + # Remove small parts + minx,miny,maxx,maxy = csp_true_bounds([s]) + if (minx[0]-maxx[0])**2 + (miny[1]-maxy[1])**2 < 0.1 : + joined_result.remove(s) + print_("Clipped and joined path in %s"%(time.time()-time_)) + time_ = time.time() + + ######################################################################## + # Now to the Dummy cliping: remove parts from splitted offset if their + # centers are closer to the original path than offset radius. + ######################################################################## + + r1,r2 = ( (0.99*r)**2, (1.01*r)**2 ) if abs(r*.01)<1 else ((abs(r)-1)**2, (abs(r)+1)**2) + for s in joined_result[:]: + dist = csp_to_point_distance(original_csp, s[int(len(s)/2)][1], dist_bounds = [r1,r2], tolerance = .000001) + if not r1 < dist[0] < r2 : + joined_result.remove(s) + if options.offset_draw_clippend_path: + csp_draw([s], comment = math.sqrt(dist[0])) + draw_pointer(csp_at_t(csp[dist[1]][dist[2]-1],csp[dist[1]][dist[2]],dist[3])+s[int(len(s)/2)][1],"blue", "line", comment = [math.sqrt(dist[0]),i,j,sp] ) + + print_("-----------------------------") + print_("Total offset time %s"%(time.time()-time_start)) + print_() + return joined_result + + + + + +################################################################################ +### +### Biarc function +### +### Calculates biarc approximation of cubic super path segment +### splits segment if needed or approximates it with straight line +### +################################################################################ +def biarc(sp1, sp2, z1, z2, depth=0): + def biarc_split(sp1,sp2, z1, z2, depth): + if depth<options.biarc_max_split_depth: + sp1,sp2,sp3 = csp_split(sp1,sp2) + l1, l2 = cspseglength(sp1,sp2), cspseglength(sp2,sp3) + if l1+l2 == 0 : zm = z1 + else : zm = z1+(z2-z1)*l1/(l1+l2) + return biarc(sp1,sp2,z1,zm,depth+1)+biarc(sp2,sp3,zm,z2,depth+1) + else: return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ] + + P0, P4 = P(sp1[1]), P(sp2[1]) + TS, TE, v = (P(sp1[2])-P0), -(P(sp2[0])-P4), P0 - P4 + tsa, tea, va = TS.angle(), TE.angle(), v.angle() + if TE.mag()<straight_distance_tolerance and TS.mag()<straight_distance_tolerance: + # Both tangents are zerro - line straight + return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ] + if TE.mag() < straight_distance_tolerance: + TE = -(TS+v).unit() + r = TS.mag()/v.mag()*2 + elif TS.mag() < straight_distance_tolerance: + TS = -(TE+v).unit() + r = 1/( TE.mag()/v.mag()*2 ) + else: + r=TS.mag()/TE.mag() + TS, TE = TS.unit(), TE.unit() + tang_are_parallel = ((tsa-tea)%math.pi<straight_tolerance or math.pi-(tsa-tea)%math.pi<straight_tolerance ) + if ( tang_are_parallel and + ((v.mag()<straight_distance_tolerance or TE.mag()<straight_distance_tolerance or TS.mag()<straight_distance_tolerance) or + 1-abs(TS*v/(TS.mag()*v.mag()))<straight_tolerance) ): + # Both tangents are parallel and start and end are the same - line straight + # or one of tangents still smaller then tollerance + + # Both tangents and v are parallel - line straight + return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ] + + c,b,a = v*v, 2*v*(r*TS+TE), 2*r*(TS*TE-1) + if v.mag()==0: + return biarc_split(sp1, sp2, z1, z2, depth) + asmall, bsmall, csmall = abs(a)<10**-10,abs(b)<10**-10,abs(c)<10**-10 + if asmall and b!=0: beta = -c/b + elif csmall and a!=0: beta = -b/a + elif not asmall: + discr = b*b-4*a*c + if discr < 0: raise ValueError, (a,b,c,discr) + disq = discr**.5 + beta1 = (-b - disq) / 2 / a + beta2 = (-b + disq) / 2 / a + if beta1*beta2 > 0 : raise ValueError, (a,b,c,disq,beta1,beta2) + beta = max(beta1, beta2) + elif asmall and bsmall: + return biarc_split(sp1, sp2, z1, z2, depth) + alpha = beta * r + ab = alpha + beta + P1 = P0 + alpha * TS + P3 = P4 - beta * TE + P2 = (beta / ab) * P1 + (alpha / ab) * P3 + + + def calculate_arc_params(P0,P1,P2): + D = (P0+P2)/2 + if (D-P1).mag()==0: return None, None + R = D - ( (D-P0).mag()**2/(D-P1).mag() )*(P1-D).unit() + p0a, p1a, p2a = (P0-R).angle()%(2*math.pi), (P1-R).angle()%(2*math.pi), (P2-R).angle()%(2*math.pi) + alpha = (p2a - p0a) % (2*math.pi) + if (p0a<p2a and (p1a<p0a or p2a<p1a)) or (p2a<p1a<p0a) : + alpha = -2*math.pi+alpha + if abs(R.x)>1000000 or abs(R.y)>1000000 or (R-P0).mag<options.min_arc_radius : + return None, None + else : + return R, alpha + R1,a1 = calculate_arc_params(P0,P1,P2) + R2,a2 = calculate_arc_params(P2,P3,P4) + if R1==None or R2==None or (R1-P0).mag()<straight_tolerance or (R2-P2).mag()<straight_tolerance : return [ [sp1[1],'line', 0, 0, sp2[1], [z1,z2]] ] + + d = csp_to_arc_distance(sp1,sp2, [P0,P2,R1,a1],[P2,P4,R2,a2]) + if d > options.biarc_tolerance and depth<options.biarc_max_split_depth : return biarc_split(sp1, sp2, z1, z2, depth) + else: + if R2.mag()*a2 == 0 : zm = z2 + else : zm = z1 + (z2-z1)*(abs(R1.mag()*a1))/(abs(R2.mag()*a2)+abs(R1.mag()*a1)) + return [ [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ], [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ] ] + + +def biarc_curve_segment_length(seg): + if seg[1] == "arc" : + return math.sqrt((seg[0][0]-seg[2][0])**2+(seg[0][1]-seg[2][1])**2)*seg[3] + elif seg[1] == "line" : + return math.sqrt((seg[0][0]-seg[4][0])**2+(seg[0][1]-seg[4][1])**2) + else: + return 0 + + +def biarc_curve_clip_at_l(curve, l, clip_type = "strict") : + # get first subcurve and ceck it's length + subcurve, subcurve_l, moved = [], 0, False + for seg in curve: + if seg[1] == "move" and moved or seg[1] == "end" : + break + if seg[1] == "move" : moved = True + subcurve_l += biarc_curve_segment_length(seg) + if seg[1] == "arc" or seg[1] == "line" : + subcurve += [seg] + + if subcurve_l < l and clip_type == "strict" : return [] + lc = 0 + if (subcurve[-1][4][0]-subcurve[0][0][0])**2 + (subcurve[-1][4][1]-subcurve[0][0][1])**2 < 10**-7 : subcurve_closed = True + i = 0 + reverse = False + while lc<l : + seg = subcurve[i] + if reverse : + if seg[1] == "line" : + seg = [seg[4], "line", 0 , 0, seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not? + elif seg[1] == "arc" : + seg = [seg[4], "arc", seg[2] , -seg[3], seg[0], seg[5]] # Hmmm... Do we have to swap seg[5][0] and seg[5][1] (zstart and zend) or not? + ls = biarc_curve_segment_length(seg) + if ls != 0 : + if l-lc>ls : + res += [seg] + else : + if seg[1] == "arc" : + r = math.sqrt((seg[0][0]-seg[2][0])**2+(seg[0][1]-seg[2][1])**2) + x,y = seg[0][0]-seg[2][0], seg[0][1]-seg[2][1] + a = seg[3]/ls*(l-lc) + x,y = x*math.cos(a) - y*math.sin(a), x*math.sin(a) + y*math.cos(a) + x,y = x+seg[2][0], y+seg[2][1] + res += [[ seg[0], "arc", seg[2], a, [x,y], [seg[5][0],seg[5][1]/ls*(l-lc)] ]] + if seg[1] == "line" : + res += [[ seg[0], "line", 0, 0, [(seg[4][0]-seg[0][0])/ls*(l-lc),(seg[4][1]-seg[0][1])/ls*(l-lc)], [seg[5][0],seg[5][1]/ls*(l-lc)] ]] + i += 1 + if i >= len(subcurve) and not subcurve_closed: + reverse = not reverse + i = i%len(subcurve) + return res + + + +class Postprocessor(): + def __init__(self, error_function_handler): + self.error = error_function_handler + self.functions = { + "remap" : self.remap, + "remapi" : self.remapi , + "scale" : self.scale, + "move" : self.move, + "flip" : self.flip_axis, + "flip_axis" : self.flip_axis, + "round" : self.round_coordinates, + "parameterize" : self.parameterize, + } + + + def process(self,command): + command = re.sub(r"\\\\",":#:#:slash:#:#:",command) + command = re.sub(r"\\;",":#:#:semicolon:#:#:",command) + command = command.split(";") + for s in command: + s = re.sub(":#:#:slash:#:#:","\\\\",s) + s = re.sub(":#:#:semicolon:#:#:","\\;",s) + s = s.strip() + if s!="" : + self.parse_command(s) + + + def parse_command(self,command): + r = re.match(r"([A-Za-z0-9_]+)\s*\(\s*(.*)\)",command) + if not r: + self.error("Parse error while postprocessing.\n(Command: '%s')"%(command), "error") + function, parameters = r.group(1).lower(),r.group(2) + if function in self.functions : + print_("Postprocessor: executing function %s(%s)"%(function,parameters)) + self.functions[function](parameters) + else : + self.error("Unrecognized function '%s' while postprocessing.\n(Command: '%s')"%(function,command), "error") + + + def re_sub_on_gcode_lines(self, pattern,replacemant): + gcode = self.gcode.split("\n") + self.gcode = "" + for i in range(len(gcode)) : + self.gcode += re.sub(pattern,replacement,gcode[i]) + + + def remapi(self,parameters): + self.remap(parameters, case_sensitive = True) + + + def remap(self,parameters, case_sensitive = False): + # remap parameters should be like "x->y,y->x" + parameters = parameters.replace("\,",":#:#:coma:#:#:") + parameters = parameters.split(",") + pattern, remap = [], [] + for s in parameters: + s = s.replace(":#:#:coma:#:#:","\,") + r = re.match("""\s*(\'|\")(.*)\\1\s*->\s*(\'|\")(.*)\\3\s*""",s) + if not r : + self.error("Bad parameters for remap.\n(Parameters: '%s')"%(parameters), "error") + pattern +=[r.group(2)] + remap +=[r.group(4)] + + + + for i in range(len(pattern)) : + if case_sensitive : + self.gcode = ireplace(self.gcode, pattern[i], ":#:#:remap_pattern%s:#:#:"%i ) + else : + self.gcode = self.gcode.replace(pattern[i], ":#:#:remap_pattern%s:#:#:"%i) + + for i in range(len(remap)) : + self.gcode = self.gcode.replace(":#:#:remap_pattern%s:#:#:"%i, remap[i]) + + + def transform(self, move, scale): + axis = ["xi","yj","zk","a"] + flip = scale[0]*scale[1]*scale[2] < 0 + gcode = "" + warned = [] + r_scale = scale[0] + plane = "g17" + for s in self.gcode.split("\n"): + # get plane selection: + s_wo_comments = re.sub(r"\([^\)]*\)","",s) + r = re.search(r"(?i)(G17|G18|G19)", s_wo_comments) + if r : + plane = r.group(1).lower() + if plane == "g17" : r_scale = scale[0] # plane XY -> scale x + if plane == "g18" : r_scale = scale[0] # plane XZ -> scale x + if plane == "g19" : r_scale = scale[1] # plane YZ -> scale y + # Raise warning if scale factors are not the game for G02 and G03 + if plane not in warned: + r = re.search(r"(?i)(G02|G03)", s_wo_comments) + if r : + if plane == "g17" and scale[0]!=scale[1]: self.error("Post-processor: Scale factors for X and Y axis are not the same. G02 and G03 codes will be corrupted.","warning") + if plane == "g18" and scale[0]!=scale[2]: self.error("Post-processor: Scale factors for X and Z axis are not the same. G02 and G03 codes will be corrupted.","warning") + if plane == "g19" and scale[1]!=scale[2]: self.error("Post-processor: Scale factors for Y and Z axis are not the same. G02 and G03 codes will be corrupted.","warning") + warned += [plane] + # Transform + for i in range(len(axis)) : + if move[i] != 0 or scale[i] != 1: + for a in axis[i] : + r = re.search(r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", s) + if r and r.group(3)!="": + s = re.sub(r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", r"\1 %f"%(float(r.group(2)+r.group(3))*scale[i]+(move[i] if a not in ["i","j","k"] else 0) ), s) + #scale radius R + if r_scale != 1 : + r = re.search(r"(?i)(r)\s*(-?\s*(\d*\.?\d*))", s) + if r and r.group(3)!="": + try: + s = re.sub(r"(?i)(r)\s*(-?)\s*(\d*\.?\d*)", r"\1 %f"%( float(r.group(2)+r.group(3))*r_scale ), s) + except: + pass + + gcode += s + "\n" + + self.gcode = gcode + if flip : + self.remapi("'G02'->'G03', 'G03'->'G02'") + + + def parameterize(self,parameters) : + planes = [] + feeds = {} + coords = [] + gcode = "" + coords_def = {"x":"x","y":"y","z":"z","i":"x","j":"y","k":"z","a":"a"} + for s in self.gcode.split("\n"): + s_wo_comments = re.sub(r"\([^\)]*\)","",s) + # get Planes + r = re.search(r"(?i)(G17|G18|G19)", s_wo_comments) + if r : + plane = r.group(1).lower() + if plane not in planes : + planes += [plane] + # get Feeds + r = re.search(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", s_wo_comments) + if r : + feed = float (r.group(2)+r.group(3)) + if feed not in feeds : + feeds[feed] = "#"+str(len(feeds)+20) + + #Coordinates + for c in "xyzijka" : + r = re.search(r"(?i)("+c+r")\s*(-?)\s*(\d*\.?\d*)", s_wo_comments) + if r : + c = coords_def[r.group(1).lower()] + if c not in coords : + coords += [c] + # Add offset parametrization + offset = {"x":"#6","y":"#7","z":"#8","a":"#9"} + for c in coords: + gcode += "%s = 0 (%s axis offset)\n" % (offset[c],c.upper()) + + # Add scale parametrization + if planes == [] : planes = ["g17"] + if len(planes)>1 : # have G02 and G03 in several planes scale_x = scale_y = scale_z required + gcode += "#10 = 1 (Scale factor)\n" + scale = {"x":"#10","i":"#10","y":"#10","j":"#10","z":"#10","k":"#10","r":"#10"} + else : + gcode += "#10 = 1 (%s Scale factor)\n" % ({"g17":"XY","g18":"XZ","g19":"YZ"}[planes[0]]) + gcode += "#11 = 1 (%s Scale factor)\n" % ({"g17":"Z","g18":"Y","g19":"X"}[planes[0]]) + scale = {"x":"#10","i":"#10","y":"#10","j":"#10","z":"#10","k":"#10","r":"#10"} + if "g17" in planes : + scale["z"] = "#11" + scale["k"] = "#11" + if "g18" in planes : + scale["y"] = "#11" + scale["j"] = "#11" + if "g19" in planes : + scale["x"] = "#11" + scale["i"] = "#11" + # Add a scale + if "a" in coords: + gcode += "#12 = 1 (A axis scale)\n" + scale["a"] = "#12" + + # Add feed parametrization + for f in feeds : + gcode += "%s = %f (Feed definition)\n" % (feeds[f],f) + + # Parameterize Gcode + for s in self.gcode.split("\n"): + #feed replace : + r = re.search(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", s) + if r and len(r.group(3))>0: + s = re.sub(r"(?i)(F)\s*(-?)\s*(\d*\.?\d*)", "F [%s]"%feeds[float(r.group(2)+r.group(3))], s) + #Coords XYZA replace + for c in "xyza" : + r = re.search(r"(?i)(("+c+r")\s*(-?)\s*(\d*\.?\d*))", s) + if r and len(r.group(4))>0: + s = re.sub(r"(?i)("+c+r")\s*((-?)\s*(\d*\.?\d*))", r"\1[\2*%s+%s]"%(scale[c],offset[c]), s) + + #Coords IJKR replace + for c in "ijkr" : + r = re.search(r"(?i)(("+c+r")\s*(-?)\s*(\d*\.?\d*))", s) + if r and len(r.group(4))>0: + s = re.sub(r"(?i)("+c+r")\s*((-?)\s*(\d*\.?\d*))", r"\1[\2*%s]"%scale[c], s) + + gcode += s + "\n" + + self.gcode = gcode + + + def round_coordinates(self,parameters) : + try: + round_ = int(parameters) + except : + self.error("Bad parameters for round. Round should be an integer! \n(Parameters: '%s')"%(parameters), "error") + gcode = "" + for s in self.gcode.split("\n"): + for a in "xyzijkaf" : + r = re.search(r"(?i)("+a+r")\s*(-?\s*(\d*\.?\d*))", s) + if r : + + if r.group(2)!="": + s = re.sub( + r"(?i)("+a+r")\s*(-?)\s*(\d*\.?\d*)", + (r"\1 %0."+str(round_)+"f" if round_>0 else r"\1 %d")%round(float(r.group(2)),round_), + s) + gcode += s + "\n" + self.gcode = gcode + + + def scale(self, parameters): + parameters = parameters.split(",") + scale = [1.,1.,1.,1.] + try : + for i in range(len(parameters)) : + if float(parameters[i])==0 : + self.error("Bad parameters for scale. Scale should not be 0 at any axis! \n(Parameters: '%s')"%(parameters), "error") + scale[i] = float(parameters[i]) + except : + self.error("Bad parameters for scale.\n(Parameters: '%s')"%(parameters), "error") + self.transform([0,0,0,0],scale) + + + def move(self, parameters): + parameters = parameters.split(",") + move = [0.,0.,0.,0.] + try : + for i in range(len(parameters)) : + move[i] = float(parameters[i]) + except : + self.error("Bad parameters for move.\n(Parameters: '%s')"%(parameters), "error") + self.transform(move,[1.,1.,1.,1.]) + + + def flip_axis(self, parameters): + parameters = parameters.lower() + axis = {"x":1.,"y":1.,"z":1.,"a":1.} + for p in parameters: + if p in [","," "," ","\r","'",'"'] : continue + if p not in ["x","y","z","a"] : + self.error("Bad parameters for flip_axis. Parameter should be string consists of 'xyza' \n(Parameters: '%s')"%(parameters), "error") + axis[p] = -axis[p] + self.scale("%f,%f,%f,%f"%(axis["x"],axis["y"],axis["z"],axis["a"])) + + + +################################################################################ +### Polygon class +################################################################################ +class Polygon: + def __init__(self, polygon=None): + self.polygon = [] if polygon==None else polygon[:] + + + def move(self, x, y) : + for i in range(len(self.polygon)) : + for j in range(len(self.polygon[i])) : + self.polygon[i][j][0] += x + self.polygon[i][j][1] += y + + + def bounds(self) : + minx,miny,maxx,maxy = 1e400, 1e400, -1e400, -1e400 + for poly in self.polygon : + for p in poly : + if minx > p[0] : minx = p[0] + if miny > p[1] : miny = p[1] + if maxx < p[0] : maxx = p[0] + if maxy < p[1] : maxy = p[1] + return minx*1,miny*1,maxx*1,maxy*1 + + + def width(self): + b = self.bounds() + return b[2]-b[0] + + + def rotate_(self,sin,cos) : + for i in range(len(self.polygon)) : + for j in range(len(self.polygon[i])) : + x,y = self.polygon[i][j][0], self.polygon[i][j][1] + self.polygon[i][j][0] = x*cos - y*sin + self.polygon[i][j][1] = x*sin + y*cos + + + def rotate(self, a): + cos, sin = math.cos(a), math.sin(a) + self.rotate_(sin,cos) + + + def drop_into_direction(self, direction, surface) : + # Polygon is a list of simple polygons + # Surface is a polygon + line y = 0 + # Direction is [dx,dy] + if len(self.polygon) == 0 or len(self.polygon[0])==0 : return + if direction[0]**2 + direction[1]**2 <1e-10 : return + direction = normalize(direction) + sin,cos = direction[0], -direction[1] + self.rotate_(-sin,cos) + surface.rotate_(-sin,cos) + self.drop_down(surface, zerro_plane = False) + self.rotate_(sin,cos) + surface.rotate_(sin,cos) + + + def centroid(self): + centroids = [] + sa = 0 + for poly in self.polygon: + cx,cy,a = 0,0,0 + for i in range(len(poly)): + [x1,y1],[x2,y2] = poly[i-1],poly[i] + cx += (x1+x2)*(x1*y2-x2*y1) + cy += (y1+y2)*(x1*y2-x2*y1) + a += (x1*y2-x2*y1) + a *= 3. + if abs(a)>0 : + cx /= a + cy /= a + sa += abs(a) + centroids += [ [cx,cy,a] ] + if sa == 0 : return [0.,0.] + cx,cy = 0.,0. + for c in centroids : + cx += c[0]*c[2] + cy += c[1]*c[2] + cx /= sa + cy /= sa + return [cx,cy] + + + def drop_down(self, surface, zerro_plane = True) : + # Polygon is a list of simple polygons + # Surface is a polygon + line y = 0 + # Down means min y (0,-1) + if len(self.polygon) == 0 or len(self.polygon[0])==0 : return + # Get surface top point + top = surface.bounds()[3] + if zerro_plane : top = max(0, top) + # Get polygon bottom point + bottom = self.bounds()[1] + self.move(0, top - bottom + 10) + # Now get shortest distance from surface to polygon in positive x=0 direction + # Such distance = min(distance(vertex, edge)...) where edge from surface and + # vertex from polygon and vice versa... + dist = 1e300 + for poly in surface.polygon : + for i in range(len(poly)) : + for poly1 in self.polygon : + for i1 in range(len(poly1)) : + st,end = poly[i-1], poly[i] + vertex = poly1[i1] + if st[0]<=vertex[0]<= end[0] or end[0]<=vertex[0]<=st[0] : + if st[0]==end[0] : d = min(vertex[1]-st[1],vertex[1]-end[1]) + else : d = vertex[1] - st[1] - (end[1]-st[1])*(vertex[0]-st[0])/(end[0]-st[0]) + if dist > d : dist = d + # and vice versa just change the sign because vertex now under the edge + st,end = poly1[i1-1], poly1[i1] + vertex = poly[i] + if st[0]<=vertex[0]<=end[0] or end[0]<=vertex[0]<=st[0] : + if st[0]==end[0] : d = min(- vertex[1]+st[1],-vertex[1]+end[1]) + else : d = - vertex[1] + st[1] + (end[1]-st[1])*(vertex[0]-st[0])/(end[0]-st[0]) + if dist > d : dist = d + + if zerro_plane and dist > 10 + top : dist = 10 + top + #print_(dist, top, bottom) + #self.draw() + self.move(0, -dist) + + + def draw(self,color="#075",width=.1) : + for poly in self.polygon : + csp_draw( [csp_subpath_line_to([],poly+[poly[0]])], color=color,width=width ) + + + def add(self, add) : + if type(add) == type([]) : + self.polygon += add[:] + else : + self.polygon += add.polygon[:] + + + def point_inside(self,p) : + inside = False + for poly in self.polygon : + for i in range(len(poly)): + st,end = poly[i-1], poly[i] + if p==st or p==end : return True # point is a vertex = point is on the edge + if st[0]>end[0] : st, end = end, st # This will be needed to check that edge if open only at rigth end + c = (p[1]-st[1])*(end[0]-st[0])-(end[1]-st[1])*(p[0]-st[0]) + #print_(c) + if st[0]<=p[0]<end[0] : + if c<0 : + inside = not inside + elif c == 0 : return True # point is on the edge + elif st[0]==end[0]==p[0] and (st[1]<=p[1]<=end[1] or end[1]<=p[1]<=st[1]) : # point is on the edge + return True + return inside + + + def hull(self) : + # Add vertices at all self intersection points. + hull = [] + for i1 in range(len(self.polygon)): + poly1 = self.polygon[i1] + poly_ = [] + for j1 in range(len(poly1)): + s, e = poly1[j1-1],poly1[j1] + poly_ += [s] + + # Check self intersections + for j2 in range(j1+1,len(poly1)): + s1, e1 = poly1[j2-1],poly1[j2] + int_ = line_line_intersection_points(s,e,s1,e1) + for p in int_ : + if point_to_point_d2(p,s)>0.000001 and point_to_point_d2(p,e)>0.000001 : + poly_ += [p] + # Check self intersections with other polys + for i2 in range(len(self.polygon)): + if i1==i2 : continue + poly2 = self.polygon[i2] + for j2 in range(len(poly2)): + s1, e1 = poly2[j2-1],poly2[j2] + int_ = line_line_intersection_points(s,e,s1,e1) + for p in int_ : + if point_to_point_d2(p,s)>0.000001 and point_to_point_d2(p,e)>0.000001 : + poly_ += [p] + hull += [poly_] + # Create the dictionary containing all edges in both directions + edges = {} + for poly in self.polygon : + for i in range(len(poly)): + s,e = tuple(poly[i-1]), tuple(poly[i]) + if (point_to_point_d2(e,s)<0.000001) : continue + break_s, break_e = False, False + for p in edges : + if point_to_point_d2(p,s)<0.000001 : + break_s = True + s = p + if point_to_point_d2(p,e)<0.000001 : + break_e = True + e = p + if break_s and break_e : break + l = point_to_point_d(s,e) + if not break_s and not break_e : + edges[s] = [ [s,e,l] ] + edges[e] = [ [e,s,l] ] + #draw_pointer(s+e,"red","line") + #draw_pointer(s+e,"red","line") + else : + if e in edges : + for edge in edges[e] : + if point_to_point_d2(edge[1],s)<0.000001 : + break + if point_to_point_d2(edge[1],s)>0.000001 : + edges[e] += [ [e,s,l] ] + #draw_pointer(s+e,"red","line") + + else : + edges[e] = [ [e,s,l] ] + #draw_pointer(s+e,"green","line") + if s in edges : + for edge in edges[s] : + if point_to_point_d2(edge[1],e)<0.000001 : + break + if point_to_point_d2(edge[1],e)>0.000001 : + edges[s] += [ [s,e, l] ] + #draw_pointer(s+e,"red","line") + else : + edges[s] = [ [s,e,l] ] + #draw_pointer(s+e,"green","line") + + + def angle_quadrant(sin,cos): + # quadrants are (0,pi/2], (pi/2,pi], (pi,3*pi/2], (3*pi/2, 2*pi], i.e. 0 is in the 4-th quadrant + if sin>0 and cos>=0 : return 1 + if sin>=0 and cos<0 : return 2 + if sin<0 and cos<=0 : return 3 + if sin<=0 and cos>0 : return 4 + + + def angle_is_less(sin,cos,sin1,cos1): + # 0 = 2*pi is the largest angle + if [sin1, cos1] == [0,1] : return True + if [sin, cos] == [0,1] : return False + if angle_quadrant(sin,cos)>angle_quadrant(sin1,cos1) : + return False + if angle_quadrant(sin,cos)<angle_quadrant(sin1,cos1) : + return True + if sin>=0 and cos>0 : return sin<sin1 + if sin>0 and cos<=0 : return sin>sin1 + if sin<=0 and cos<0 : return sin>sin1 + if sin<0 and cos>=0 : return sin<sin1 + + + def get_closes_edge_by_angle(edges, last): + # Last edge is normalized vector of the last edge. + min_angle = [0,1] + next = last + last_edge = [(last[0][0]-last[1][0])/last[2], (last[0][1]-last[1][1])/last[2]] + for p in edges: + #draw_pointer(list(p[0])+[p[0][0]+last_edge[0]*40,p[0][1]+last_edge[1]*40], "Red", "line", width=1) + #print_("len(edges)=",len(edges)) + cur = [(p[1][0]-p[0][0])/p[2],(p[1][1]-p[0][1])/p[2]] + cos, sin = dot(cur,last_edge), cross(cur,last_edge) + #draw_pointer(list(p[0])+[p[0][0]+cur[0]*40,p[0][1]+cur[1]*40], "Orange", "line", width=1, comment = [sin,cos]) + #print_("cos, sin=",cos,sin) + #print_("min_angle_before=",min_angle) + + if angle_is_less(sin,cos,min_angle[0],min_angle[1]) : + min_angle = [sin,cos] + next = p + #print_("min_angle=",min_angle) + + return next + + # Join edges together into new polygon cutting the vertexes inside new polygon + self.polygon = [] + len_edges = sum([len(edges[p]) for p in edges]) + loops = 0 + + while len(edges)>0 : + poly = [] + if loops > len_edges : raise ValueError, "Hull error" + loops+=1 + # Find left most vertex. + start = (1e100,1) + for edge in edges : + start = min(start, min(edges[edge])) + last = [(start[0][0]-1,start[0][1]),start[0],1] + first_run = True + loops1 = 0 + while (last[1]!=start[0] or first_run) : + first_run = False + if loops1 > len_edges : raise ValueError, "Hull error" + loops1 += 1 + next = get_closes_edge_by_angle(edges[last[1]],last) + #draw_pointer(next[0]+next[1],"Green","line", comment=i, width= 1) + #print_(next[0],"-",next[1]) + + last = next + poly += [ list(last[0]) ] + self.polygon += [ poly ] + # Remove all edges that are intersects new poly (any vertex inside new poly) + poly_ = Polygon([poly]) + for p in edges.keys()[:] : + if poly_.point_inside(list(p)) : del edges[p] + self.draw(color="Green", width=1) + + +class Arangement_Genetic: + # gene = [fittness, order, rotation, xposition] + # spieces = [gene]*shapes count + # population = [spieces] + def __init__(self, polygons, material_width): + self.population = [] + self.genes_count = len(polygons) + self.polygons = polygons + self.width = material_width + self.mutation_factor = 0.1 + self.order_mutate_factor = 1. + self.move_mutate_factor = 1. + + + def add_random_species(self,count): + for i in range(count): + specimen = [] + order = range(self.genes_count) + random.shuffle(order) + for j in order: + specimen += [ [j, random.random(), random.random()] ] + self.population += [ [None,specimen] ] + + + def species_distance2(self,sp1,sp2) : + # retun distance, each component is normalized + s = 0 + for j in range(self.genes_count) : + s += ((sp1[j][0]-sp2[j][0])/self.genes_count)**2 + (( sp1[j][1]-sp2[j][1]))**2 + ((sp1[j][2]-sp2[j][2]))**2 + return s + + + def similarity(self,sp1,top) : + # Define similarity as a simple distance between two points in len(gene)*len(spiece) -th dimentions + # for sp2 in top_spieces sum(|sp1-sp2|)/top_count + sim = 0 + for sp2 in top : + sim += math.sqrt(species_distance2(sp1,sp2[1])) + return sim/len(top) + + + def leave_top_species(self,count): + self.population.sort() + res = [ copy.deepcopy(self.population[0]) ] + del self.population[0] + for i in range(count-1) : + t = [] + for j in range(20) : + i1 = random.randint(0,len(self.population)-1) + t += [ [self.population[i1][0],i1] ] + t.sort() + res += [ copy.deepcopy(self.population[t[0][1]]) ] + del self.population[t[0][1]] + self.population = res + #del self.population[0] + #for c in range(count-1) : + # rank = [] + # for i in range(len(self.population)) : + # sim = self.similarity(self.population[i][1],res) + # rank += [ [self.population[i][0] / sim if sim>0 else 1e100,i] ] + # rank.sort() + # res += [ copy.deepcopy(self.population[rank[0][1]]) ] + # print_(rank[0],self.population[rank[0][1]][0]) + # print_(res[-1]) + # del self.population[rank[0][1]] + + self.population = res + + + def populate_species(self,count, parent_count): + self.population.sort() + self.inc = 0 + for c in range(count): + parent1 = random.randint(0,parent_count-1) + parent2 = random.randint(0,parent_count-1) + if parent1==parent2 : parent2 = (parent2+1) % parent_count + parent1, parent2 = self.population[parent1][1], self.population[parent2][1] + i1,i2 = 0, 0 + genes_order = [] + specimen = [ [0,0.,0.] for i in range(self.genes_count) ] + + self.incest_mutation_multiplyer = 1. + self.incest_mutation_count_multiplyer = 1. + + if self.species_distance2(parent1, parent2) <= .01/self.genes_count : + # OMG it's a incest :O!!! + # Damn you bastards! + self.inc +=1 + self.incest_mutation_multiplyer = 2. + self.incest_mutation_count_multiplyer = 2. + else : + if random.random()<.01 : print_(self.species_distance2(parent1, parent2)) + start_gene = random.randint(0,self.genes_count) + end_gene = (max(1,random.randint(0,self.genes_count),int(self.genes_count/4))+start_gene) % self.genes_count + if end_gene<start_gene : + end_gene, start_gene = start_gene, end_gene + parent1, parent2 = parent2, parent1 + for i in range(start_gene,end_gene) : + #rotation_mutate_param = random.random()/100 + #xposition_mutate_param = random.random()/100 + tr = 1. #- rotation_mutate_param + tp = 1. #- xposition_mutate_param + specimen[i] = [parent1[i][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)] + genes_order += [ parent1[i][0] ] + + for i in range(0,start_gene)+range(end_gene,self.genes_count) : + tr = 0. #rotation_mutate_param + tp = 0. #xposition_mutate_param + j = i + while parent2[j][0] in genes_order : + j = (j+1)%self.genes_count + specimen[i] = [parent2[j][0], parent1[i][1]*tr+parent2[i][1]*(1-tr),parent1[i][2]*tp+parent2[i][2]*(1-tp)] + genes_order += [ parent2[j][0] ] + + + for i in range(random.randint(self.mutation_genes_count[0],self.mutation_genes_count[0]*self.incest_mutation_count_multiplyer )) : + if random.random() < self.order_mutate_factor * self.incest_mutation_multiplyer : + i1,i2 = random.randint(0,self.genes_count-1),random.randint(0,self.genes_count-1) + specimen[i1][0], specimen[i2][0] = specimen[i2][0], specimen[i1][0] + if random.random() < self.move_mutation_factor * self.incest_mutation_multiplyer: + i1 = random.randint(0,self.genes_count-1) + specimen[i1][1] = (specimen[i1][1]+random.random()*math.pi2*self.move_mutation_multiplier)%1. + specimen[i1][2] = (specimen[i1][2]+random.random()*self.move_mutation_multiplier)%1. + self.population += [ [None,specimen] ] + + + def test_spiece_drop_down(self,spiece) : + surface = Polygon() + for p in spiece : + time_ = time.time() + poly = Polygon(copy.deepcopy(self.polygons[p[0]].polygon)) + poly.rotate(p[1]*math.pi2) + w = poly.width() + left = poly.bounds()[0] + poly.move( -left + (self.width-w)*p[2],0) + poly.drop_down(surface) + surface.add(poly) + return surface + + + def test(self,test_function): + for i in range(len(self.population)) : + if self.population[i][0] == None : + surface = test_function(self.population[i][1]) + b = surface.bounds() + self.population[i][0] = (b[3]-b[1])*(b[2]-b[0]) + self.population.sort() + + + def test_spiece_centroid(self,spiece) : + poly = Polygon(copy.deepcopy(self.polygons[spiece[0][0]].polygon)) + poly.rotate(spiece[0][2]*math.pi2) + surface = Polygon(poly.polygon) + i = 0 + for p in spiece[1:] : + i += 1 + poly = Polygon(copy.deepcopy(self.polygons[p[0]].polygon)) + poly.rotate(p[2]*math.pi2) + c = surface.centroid() + c1 = poly.centroid() + direction = [math.cos(p[1]*math.pi2), -math.sin(p[1]*math.pi2)] + poly.move(c[0]-c1[0]-direction[0]*100,c[1]-c1[1]-direction[1]*100) + poly.drop_into_direction(direction,surface) + surface.add(poly) + return surface + + + + #surface.draw() + + +################################################################################ +### +### Gcodetools class +### +################################################################################ + +class Gcodetools(inkex.Effect): + + def export_gcode(self,gcode) : + if self.options.postprocessor != "" or self.options.postprocessor_custom != "" : + postprocessor = Postprocessor(self.error) + postprocessor.gcode = gcode + if self.options.postprocessor != "" : + postprocessor.process(self.options.postprocessor) + if self.options.postprocessor_custom != "" : + postprocessor.process(self.options.postprocessor_custom) + postprocessor.gcode = self.header + postprocessor.gcode + self.footer + f = open(self.options.directory+self.options.file, "w") + f.write(postprocessor.gcode) + f.close() + + +################################################################################ +### Arrangement: arranges paths by givven params +### TODO move it to the bottom +################################################################################ + def arrangement(self) : + paths = self.selected_paths + surface = Polygon() + polygons = [] + time_ = time.time() + print_("Arrangement start at %s"%(time_)) + original_paths = [] + for layer in self.layers : + if layer in paths : + for path in paths[layer] : + csp = cubicsuperpath.parsePath(path.get("d")) + polygon = Polygon() + for subpath in csp : + for sp1, sp2 in zip(subpath,subpath[1:]) : + polygon.add([csp_segment_convex_hull(sp1,sp2)]) + #print_("Redused edges count from", sum([len(poly) for poly in polygon.polygon ]) ) + polygon.hull() + original_paths += [path] + polygons += [polygon] + + print_("Paths hull computed in %s sec."%(time.time()-time_)) + print_("Got %s polygons having average %s edges each."% ( len(polygons), float(sum([ sum([len(poly) for poly in polygon.polygon]) for polygon in polygons ])) / len(polygons) ) ) + time_ = time.time() + +# material_width = self.options.arrangement_material_width +# population = Arangement_Genetic(polygons, material_width) +# population.add_random_species(1) +# population.test_population_centroid() +## return + material_width = self.options.arrangement_material_width + population = Arangement_Genetic(polygons, material_width) + + + print_("Genetic alhorithm start at %s"%(time_)) + time_ = time.time() + + + + population.add_random_species(50) + population.test(population.test_spiece_centroid) + print_("Initial population done in %s"%(time.time()-time_)) + time_ = time.time() + pop = copy.deepcopy(population) + population_count = self.options.arrangement_population_count + last_champ = [] + champions_count = 0 + + + + + for i in range(population_count): + population.leave_top_species(20) + population.move_mutation_multiplier = random.random()/2 + + population.order_mutation_factor = .2 + population.move_mutation_factor = 1. + population.mutation_genes_count = [1,2] + population.populate_species(250, 20) + """ + randomize = i%100 < 40 + if i%100 < 40 : + population.add_random_species(250) + if 40<= i%100 < 100 : + population.mutation_genes_count = [1,max(2,int(population.genes_count/4))] #[1,max(2,int(population.genes_count/2))] if 40<=i%100<60 else [1,max(2,int(population.genes_count/10))] + population.move_mutation_multiplier = 1. if 40<=i%100<80 else .1 + population.move_mutation_factor = (-(i%100)/30+10/3) if 50<=i%100<100 else .5 + population.order_mutation_factor = 1./(i%100-79) if 80<=i%100<100 else 1. + population.populate_species(250, 10) + """ + population.test(population.test_spiece_centroid) + draw_new_champ = False + print_() + for x in population.population[:10]: + print_(x[0]) + + if population.population[0][0]!= last_champ : + draw_new_champ = True + last_champ = population.population[0][0]*1 + + + k = "" + #for j in range(10) : + # k += "%s " % population.population[j][0] + print_("Cicle %s done in %s"%(i,time.time()-time_)) + time_ = time.time() + print_("%s incests been found"%population.inc) + print_() + #print_(k) + #print_() + if i == 0 or i == population_count-1 or draw_new_champ : + colors = ["blue"] + + surface = population.test_spiece_centroid(population.population[0][1]) + b = surface.bounds() + x,y = 400* (champions_count%10), 700*int(champions_count/10) + surface.move(x-b[0],y-b[1]) + surface.draw(width=2, color=colors[0]) + draw_text("Step = %s\nSquare = %f"%(i,(b[2]-b[0])*(b[3]-b[1])),x,y-40) + champions_count += 1 + + spiece = population.population[0][1] + poly = Polygon(copy.deepcopy(population.polygons[spiece[0][0]].polygon)) + poly.rotate(spiece[0][2]*math.pi2) + surface = Polygon(poly.polygon) + poly.draw(width = 2, color= "Violet") + for p in spiece[1:] : + poly = Polygon(copy.deepcopy(population.polygons[p[0]].polygon)) + poly.rotate(p[2]*math.pi2) + direction = [math.cos(p[1]*math.pi2), -math.sin(p[1]*math.pi2)] + normalize(direction) + c = surface.centroid() + c1 = poly.centroid() + poly.move(c[0]-c1[0]-direction[0]*400,c[1]-c1[1]-direction[1]*400) + c = surface.centroid() + c1 = poly.centroid() + poly.draw(width = 5, color= "Violet") + draw_pointer(c+c1,"Green","line") + direction = normalize(direction) + + + sin,cos = direction[0], direction[1] + poly.rotate_(-sin,cos) + surface.rotate_(-sin,cos) +# poly.draw(color = "Violet",width=4) + surface.draw(color = "Orange",width=4) + poly.rotate_(sin,cos) + surface.rotate_(sin,cos) + + + poly.drop_into_direction(direction,surface) + surface.add(poly) + + + # Now we'll need apply transforms to original paths + + + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("-d", "--directory", action="store", type="string", dest="directory", default="/home/", help="Directory for gcode file") + self.OptionParser.add_option("-f", "--filename", action="store", type="string", dest="file", default="-1.0", help="File name") + self.OptionParser.add_option("", "--add-numeric-suffix-to-filename", action="store", type="inkbool", dest="add_numeric_suffix_to_filename", default=True,help="Add numeric suffix to filename") + self.OptionParser.add_option("", "--Zscale", action="store", type="float", dest="Zscale", default="1.0", help="Scale factor Z") + self.OptionParser.add_option("", "--Zoffset", action="store", type="float", dest="Zoffset", default="0.0", help="Offset along Z") + self.OptionParser.add_option("-s", "--Zsafe", action="store", type="float", dest="Zsafe", default="0.5", help="Z above all obstacles") + self.OptionParser.add_option("-z", "--Zsurface", action="store", type="float", dest="Zsurface", default="0.0", help="Z of the surface") + self.OptionParser.add_option("-c", "--Zdepth", action="store", type="float", dest="Zdepth", default="-0.125", help="Z depth of cut") + self.OptionParser.add_option("", "--Zstep", action="store", type="float", dest="Zstep", default="-0.125", help="Z step of cutting") + self.OptionParser.add_option("-p", "--feed", action="store", type="float", dest="feed", default="4.0", help="Feed rate in unit/min") + + self.OptionParser.add_option("", "--biarc-tolerance", action="store", type="float", dest="biarc_tolerance", default="1", help="Tolerance used when calculating biarc interpolation.") + self.OptionParser.add_option("", "--biarc-max-split-depth", action="store", type="int", dest="biarc_max_split_depth", default="4", help="Defines maximum depth of splitting while approximating using biarcs.") + + self.OptionParser.add_option("", "--tool-diameter", action="store", type="float", dest="tool_diameter", default="3", help="Tool diameter used for area cutting") + self.OptionParser.add_option("", "--max-area-curves", action="store", type="int", dest="max_area_curves", default="100", help="Maximum area curves for each area") + self.OptionParser.add_option("", "--area-inkscape-radius", action="store", type="float", dest="area_inkscape_radius", default="-10", help="Radius for preparing curves using inkscape") + self.OptionParser.add_option("", "--unit", action="store", type="string", dest="unit", default="G21 (All units in mm)", help="Units") + self.OptionParser.add_option("", "--active-tab", action="store", type="string", dest="active_tab", default="", help="Defines which tab is active") + + self.OptionParser.add_option("", "--area-find-artefacts-diameter",action="store", type="float", dest="area_find_artefacts_diameter", default="1", help="artefacts seeking radius") + self.OptionParser.add_option("", "--area-find-artefacts-action", action="store", type="string", dest="area_find_artefacts_action", default="mark with an arrow", help="artefacts action type") + + self.OptionParser.add_option("", "--auto_select_paths", action="store", type="inkbool", dest="auto_select_paths", default=True, help="Select all paths if nothing is selected.") + + self.OptionParser.add_option("", "--loft-distances", action="store", type="string", dest="loft_distances", default="10", help="Distances between paths.") + self.OptionParser.add_option("", "--loft-direction", action="store", type="string", dest="loft_direction", default="crosswise", help="Direction of loft's interpolation.") + self.OptionParser.add_option("", "--loft-interpolation-degree", action="store", type="float", dest="loft_interpolation_degree", default="2", help="Which interpolation use to loft the paths smooth interpolation or staright.") + + self.OptionParser.add_option("", "--min-arc-radius", action="store", type="float", dest="min_arc_radius", default=".1", help="All arc having radius less than minimum will be considered as straight line") + + self.OptionParser.add_option("", "--engraving-sharp-angle-tollerance",action="store", type="float", dest="engraving_sharp_angle_tollerance", default="150", help="All angles thar are less than engraving-sharp-angle-tollerance will be thought sharp") + self.OptionParser.add_option("", "--engraving-max-dist", action="store", type="float", dest="engraving_max_dist", default="10", help="Distanse from original path where engraving is not needed (usualy it's cutting tool diameter)") + self.OptionParser.add_option("", "--engraving-newton-iterations", action="store", type="int", dest="engraving_newton_iterations", default="4", help="Number of sample points used to calculate distance") + self.OptionParser.add_option("", "--engraving-draw-calculation-paths",action="store", type="inkbool", dest="engraving_draw_calculation_paths", default=False, help="Draw additional graphics to debug engraving path") + self.OptionParser.add_option("", "--engraving-cutter-shape-function",action="store", type="string", dest="engraving_cutter_shape_function", default="w", help="Cutter shape function z(w). Ex. cone: w. ") + + self.OptionParser.add_option("", "--lathe-width", action="store", type="float", dest="lathe_width", default=10., help="Lathe width") + self.OptionParser.add_option("", "--lathe-fine-cut-width", action="store", type="float", dest="lathe_fine_cut_width", default=1., help="Fine cut width") + self.OptionParser.add_option("", "--lathe-fine-cut-count", action="store", type="int", dest="lathe_fine_cut_count", default=1., help="Fine cut count") + self.OptionParser.add_option("", "--lathe-create-fine-cut-using", action="store", type="string", dest="lathe_create_fine_cut_using", default="Move path", help="Create fine cut using") + self.OptionParser.add_option("", "--lathe-x-axis-remap", action="store", type="string", dest="lathe_x_axis_remap", default="X", help="Lathe X axis remap") + self.OptionParser.add_option("", "--lathe-z-axis-remap", action="store", type="string", dest="lathe_z_axis_remap", default="Z", help="Lathe Z axis remap") + + self.OptionParser.add_option("", "--create-log", action="store", type="inkbool", dest="log_create_log", default=False, help="Create log files") + self.OptionParser.add_option("", "--log-filename", action="store", type="string", dest="log_filename", default='', help="Create log files") + + self.OptionParser.add_option("", "--orientation-points-count", action="store", type="int", dest="orientation_points_count", default='2', help="Orientation points count") + self.OptionParser.add_option("", "--tools-library-type", action="store", type="string", dest="tools_library_type", default='cylinder cutter', help="Create tools defention") + + self.OptionParser.add_option("", "--dxfpoints-action", action="store", type="string", dest="dxfpoints_action", default='replace', help="dxfpoint sign toggle") + + self.OptionParser.add_option("", "--help-language", action="store", type="string", dest="help_language", default='http://www.cnc-club.ru/forum/viewtopic.php?f=33&t=35', help="Open help page in webbrowser.") + + self.OptionParser.add_option("", "--offset-radius", action="store", type="float", dest="offset_radius", default=10., help="Offset radius") + self.OptionParser.add_option("", "--offset-step", action="store", type="float", dest="offset_step", default=10., help="Offset step") + self.OptionParser.add_option("", "--offset-draw-clippend-path", action="store", type="inkbool", dest="offset_draw_clippend_path", default=False, help="Draw clipped path") + self.OptionParser.add_option("", "--offset-just-get-distance", action="store", type="inkbool", dest="offset_just_get_distance", default=False, help="Don't do offset just get distance") + + self.OptionParser.add_option("", "--arrangement-material-width", action="store", type="float", dest="arrangement_material_width", default=500, help="Materials width for arrangement") + self.OptionParser.add_option("", "--arrangement-population-count",action="store", type="int", dest="arrangement_population_count", default=100, help="Genetic algorithm populations count") + + self.OptionParser.add_option("", "--postprocessor", action="store", type="string", dest="postprocessor", default='', help="Postprocessor command.") + self.OptionParser.add_option("", "--postprocessor-custom", action="store", type="string", dest="postprocessor_custom", default='', help="Postprocessor custom command.") + + + + self.default_tool = { + "name": "Default tool", + "id": "default tool", + "diameter":10., + "shape": "10", + "penetration angle":90., + "penetration feed":100., + "depth step":1., + "feed":400., + "in trajectotry":"", + "out trajectotry":"", + "gcode before path":"", + "gcode after path":"", + "sog":"", + "spinlde rpm":"", + "CW or CCW":"", + "tool change gcode":" ", + "4th axis meaning": " ", + "4th axis scale": 1., + "4th axis offset": 0., + "passing feed":"800", + "fine feed":"800", + } + self.tools_field_order = [ + 'name', + 'id', + 'diameter', + 'feed', + 'shape', + 'penetration angle', + 'penetration feed', + "passing feed", + 'depth step', + "in trajectotry", + "out trajectotry", + "gcode before path", + "gcode after path", + "sog", + "spinlde rpm", + "CW or CCW", + "tool change gcode", + ] + + + def parse_curve(self, p, layer, w = None, f = None): + c = [] + if len(p)==0 : + return [] + p = self.transform_csp(p, layer) + + + ### Sort to reduce Rapid distance + k = range(1,len(p)) + keys = [0] + while len(k)>0: + end = p[keys[-1]][-1][1] + dist = None + for i in range(len(k)): + start = p[k[i]][0][1] + dist = max( ( -( ( end[0]-start[0])**2+(end[1]-start[1])**2 ) ,i) , dist ) + keys += [k[dist[1]]] + del k[dist[1]] + for k in keys: + subpath = p[k] + c += [ [ [subpath[0][1][0],subpath[0][1][1]] , 'move', 0, 0] ] + for i in range(1,len(subpath)): + sp1 = [ [subpath[i-1][j][0], subpath[i-1][j][1]] for j in range(3)] + sp2 = [ [subpath[i ][j][0], subpath[i ][j][1]] for j in range(3)] + c += biarc(sp1,sp2,0,0) if w==None else biarc(sp1,sp2,-f(w[k][i-1]),-f(w[k][i])) +# l1 = biarc(sp1,sp2,0,0) if w==None else biarc(sp1,sp2,-f(w[k][i-1]),-f(w[k][i])) +# print_((-f(w[k][i-1]),-f(w[k][i]), [i1[5] for i1 in l1]) ) + c += [ [ [subpath[-1][1][0],subpath[-1][1][1]] ,'end',0,0] ] + return c + + + def draw_curve(self, curve, layer, group=None, style=styles["biarc_style"]): + + self.get_defs() + # Add marker to defs if it doesnot exists + if "DrawCurveMarker" not in self.defs : + defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg")) + marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"}) + inkex.etree.SubElement( marker, inkex.addNS("path","svg"), + { "d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126", + "style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" } + ) + if "DrawCurveMarker_r" not in self.defs : + defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg")) + marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"DrawCurveMarker_r","orient":"auto","refX":"8","refY":"-2.41063","style":"overflow:visible"}) + inkex.etree.SubElement( marker, inkex.addNS("path","svg"), + { "d":"m 6.55552,-2.41063 0,0 L 13.11104,0 c -1.0473,-1.42323 -1.04126,-3.37047 0,-4.82126", + "style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" } + ) + for i in [0,1]: + style['biarc%s_r'%i] = simplestyle.parseStyle(style['biarc%s'%i]) + style['biarc%s_r'%i]["marker-start"] = "url(#DrawCurveMarker_r)" + del(style['biarc%s_r'%i]["marker-end"]) + style['biarc%s_r'%i] = simplestyle.formatStyle(style['biarc%s_r'%i]) + + if group==None: + group = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) + s, arcn = '', 0 + + + a,b,c = [0.,0.], [1.,0.], [0.,1.] + k = (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1]) + a,b,c = self.transform(a, layer, True), self.transform(b, layer, True), self.transform(c, layer, True) + if ((b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1]))*k > 0 : reverse_angle = 1 + else : reverse_angle = -1 + for sk in curve: + si = sk[:] + si[0], si[2] = self.transform(si[0], layer, True), (self.transform(si[2], layer, True) if type(si[2])==type([]) and len(si[2])==2 else si[2]) + + if s!='': + if s[1] == 'line': + inkex.etree.SubElement( group, inkex.addNS('path','svg'), + { + 'style': style['line'], + 'd':'M %s,%s L %s,%s' % (s[0][0], s[0][1], si[0][0], si[0][1]), + "gcodetools": "Preview", + } + ) + elif s[1] == 'arc': + arcn += 1 + sp = s[0] + c = s[2] + s[3] = s[3]*reverse_angle + + a = ( (P(si[0])-P(c)).angle() - (P(s[0])-P(c)).angle() )%math.pi2 #s[3] + if s[3]*a<0: + if a>0: a = a-math.pi2 + else: a = math.pi2+a + r = math.sqrt( (sp[0]-c[0])**2 + (sp[1]-c[1])**2 ) + a_st = ( math.atan2(sp[0]-c[0],- (sp[1]-c[1])) - math.pi/2 ) % (math.pi*2) + st = style['biarc%s' % (arcn%2)][:] + if a>0: + a_end = a_st+a + st = style['biarc%s'%(arcn%2)] + else: + a_end = a_st*1 + a_st = a_st+a + st = style['biarc%s_r'%(arcn%2)] + inkex.etree.SubElement( group, inkex.addNS('path','svg'), + { + 'style': st, + inkex.addNS('cx','sodipodi'): str(c[0]), + inkex.addNS('cy','sodipodi'): str(c[1]), + inkex.addNS('rx','sodipodi'): str(r), + inkex.addNS('ry','sodipodi'): str(r), + inkex.addNS('start','sodipodi'): str(a_st), + inkex.addNS('end','sodipodi'): str(a_end), + inkex.addNS('open','sodipodi'): 'true', + inkex.addNS('type','sodipodi'): 'arc', + "gcodetools": "Preview", + }) + s = si + + + def check_dir(self): + if self.options.directory[-1] not in ["/","\\"]: + if "\\" in self.options.directory : + self.options.directory += "\\" + else : + self.options.directory += "/" + print_("Checking direcrory: '%s'"%self.options.directory) + if (os.path.isdir(self.options.directory)): + if (os.path.isfile(self.options.directory+'header')): + f = open(self.options.directory+slash+'header', 'r') + self.header = f.read() + f.close() + else: + self.header = defaults['header'] + if (os.path.isfile(self.options.directory+'footer')): + f = open(self.options.directory+'footer','r') + self.footer = f.read() + f.close() + else: + self.footer = defaults['footer'] + self.header += self.options.unit + "\n" + else: + self.error(_("Directory does not exist! Please specify existing directory at Preferences tab!"),"error") + return False + + if self.options.add_numeric_suffix_to_filename : + dir_list = os.listdir(self.options.directory) + if "." in self.options.file : + r = re.match(r"^(.*)(\..*)$",self.options.file) + ext = r.group(2) + name = r.group(1) + else: + ext = "" + name = self.options.file + max_n = 0 + for s in dir_list : + r = re.match(r"^%s_0*(\d+)%s$"%(re.escape(name),re.escape(ext) ), s) + if r : + max_n = max(max_n,int(r.group(1))) + filename = name + "_" + ( "0"*(4-len(str(max_n+1))) + str(max_n+1) ) + ext + self.options.file = filename + + print_("Testing writing rights on '%s'"%(self.options.directory+self.options.file)) + try: + f = open(self.options.directory+self.options.file, "w") + f.close() + except: + self.error(_("Can not write to specified file!\n%s"%(self.options.directory+self.options.file)),"error") + return False + return True + + + +################################################################################ +### +### Generate Gcode +### Generates Gcode on given curve. +### +### Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]] +### +################################################################################ + def generate_gcode(self, curve, layer, depth): + Zauto_scale = self.Zauto_scale[layer] + tool = self.tools[layer][0] + + def c(c): + c = [c[i] if i<len(c) else None for i in range(6)] + if c[5] == 0 : c[5]=None + s,s1 = [" X", " Y", " Z", " I", " J", " K"], ["","","","","",""] + m,a = [1,1,self.options.Zscale*Zauto_scale,1,1,self.options.Zscale*Zauto_scale], [0,0,self.options.Zoffset,0,0,0] + r = '' + for i in range(6): + if c[i]!=None: + r += s[i] + ("%f" % (c[i]*m[i]+a[i])) + s1[i] + return r + + def calculate_angle(a, current_a): + return min( + [abs(a-current_a%math.pi2+math.pi2), a+current_a-current_a%math.pi2+math.pi2], + [abs(a-current_a%math.pi2-math.pi2), a+current_a-current_a%math.pi2-math.pi2], + [abs(a-current_a%math.pi2), a+current_a-current_a%math.pi2])[1] + if len(curve)==0 : return "" + + try : + self.last_used_tool == None + except : + self.last_used_tool = None + print_("working on curve") + print_(curve) + g = tool['tool change gcode'] +"\n" if tool != self.last_used_tool else "\n" + + lg, zs, f = 'G00', self.options.Zsafe, " F%f"%tool['feed'] + current_a = 0 + go_to_safe_distance = "G00" + c([None,None,zs]) + "\n" + penetration_feed = " F%s"%tool['penetration feed'] + for i in range(1,len(curve)): + # Creating Gcode for curve between s=curve[i-1] and si=curve[i] start at s[0] end at s[4]=si[0] + s, si = curve[i-1], curve[i] + feed = f if lg not in ['G01','G02','G03'] else '' + if s[1] == 'move': + g += go_to_safe_distance + "G00" + c(si[0]) + "\n" + tool['gcode before path'] + "\n" + lg = 'G00' + elif s[1] == 'end': + g += go_to_safe_distance + tool['gcode after path'] + "\n" + lg = 'G00' + elif s[1] == 'line': + if tool['4th axis meaning'] == "tangent knife" : + a = atan2(si[0][0]-s[0][0],si[0][1]-s[0][1]) + a = calculate_angle(a, current_a) + g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset']) + current_a = a + if lg=="G00": g += "G01" + c([None,None,s[5][0]+depth]) + penetration_feed +"\n" + g += "G01" +c(si[0]+[s[5][1]+depth]) + feed + "\n" + lg = 'G01' + elif s[1] == 'arc': + r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])] + if tool['4th axis meaning'] == "tangent knife" : + if s[3]<0 : # CW + a1 = atan2(s[2][1]-s[0][1],-s[2][0]+s[0][0]) + math.pi + else: #CCW + a1 = atan2(-s[2][1]+s[0][1],s[2][0]-s[0][0]) + math.pi + a = calculate_angle(a1, current_a) + g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset']) + current_a = a + axis4 = " A%s"%((current_a+s[3])*tool['4th axis scale']+tool['4th axis offset']) + current_a = current_a+s[3] + else : axis4 = "" + if lg=="G00": g += "G01" + c([None,None,s[5][0]+depth]) + penetration_feed + "\n" + if (r[0]**2 + r[1]**2)>self.options.min_arc_radius: + r1, r2 = (P(s[0])-P(s[2])), (P(si[0])-P(s[2])) + if abs(r1.mag()-r2.mag()) < 0.001 : + g += ("G02" if s[3]<0 else "G03") + c(si[0]+[ s[5][1]+depth, (s[2][0]-s[0][0]),(s[2][1]-s[0][1]) ]) + feed + axis4 + "\n" + else: + r = (r1.mag()+r2.mag())/2 + g += ("G02" if s[3]<0 else "G03") + c(si[0]+[s[5][1]+depth]) + " R%f" % (r) + feed + axis4 + "\n" + lg = 'G02' + else: + if tool['4th axis meaning'] == "tangent knife" : + a = atan2(si[0][0]-s[0][0],si[0][1]-s[0][1]) + math.pi + a = calculate_angle(a, current_a) + g+="G01 A%s\n" % (a*tool['4th axis scale']+tool['4th axis offset']) + current_a = a + g += "G01" +c(si[0]+[s[5][1]+depth]) + feed + "\n" + lg = 'G01' + if si[1] == 'end': + g += go_to_safe_distance + tool['gcode after path'] + "\n" + return g + + + def get_transforms(self,g): + root = self.document.getroot() + trans = [] + while (g!=root): + if 'transform' in g.keys(): + t = g.get('transform') + t = simpletransform.parseTransform(t) + trans = simpletransform.composeTransform(t,trans) if trans != [] else t + print_(trans) + g=g.getparent() + return trans + + + def apply_transforms(self,g,csp): + trans = self.get_transforms(g) + if trans != []: + simpletransform.applyTransformToPath(trans, csp) + return csp + + + def transform(self,source_point, layer, reverse=False): + if layer not in self.transform_matrix: + for i in range(self.layers.index(layer),-1,-1): + if self.layers[i] in self.orientation_points : + break + if self.layers[i] not in self.orientation_points : + self.error(_("Orientation points for '%s' layer have not been found! Please add orientation points using Orientation tab!") % layer.get(inkex.addNS('label','inkscape')),"no_orientation_points") + elif self.layers[i] in self.transform_matrix : + self.transform_matrix[layer] = self.transform_matrix[self.layers[i]] + else : + orientation_layer = self.layers[i] + if len(self.orientation_points[orientation_layer])>1 : + self.error(_("There are more than one orientation point groups in '%s' layer") % orientation_layer.get(inkex.addNS('label','inkscape')),"more_than_one_orientation_point_groups") + points = self.orientation_points[orientation_layer][0] + if len(points)==2: + points += [ [ [(points[1][0][1]-points[0][0][1])+points[0][0][0], -(points[1][0][0]-points[0][0][0])+points[0][0][1]], [-(points[1][1][1]-points[0][1][1])+points[0][1][0], points[1][1][0]-points[0][1][0]+points[0][1][1]] ] ] + if len(points)==3: + print_("Layer '%s' Orientation points: " % orientation_layer.get(inkex.addNS('label','inkscape'))) + for point in points: + print_(point) + # Zcoordinates definition taken from Orientatnion point 1 and 2 + self.Zcoordinates[layer] = [max(points[0][1][2],points[1][1][2]), min(points[0][1][2],points[1][1][2])] + matrix = numpy.array([ + [points[0][0][0], points[0][0][1], 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, points[0][0][0], points[0][0][1], 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, points[0][0][0], points[0][0][1], 1], + [points[1][0][0], points[1][0][1], 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, points[1][0][0], points[1][0][1], 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, points[1][0][0], points[1][0][1], 1], + [points[2][0][0], points[2][0][1], 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, points[2][0][0], points[2][0][1], 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, points[2][0][0], points[2][0][1], 1] + ]) + + if numpy.linalg.det(matrix)!=0 : + m = numpy.linalg.solve(matrix, + numpy.array( + [[points[0][1][0]], [points[0][1][1]], [1], [points[1][1][0]], [points[1][1][1]], [1], [points[2][1][0]], [points[2][1][1]], [1]] + ) + ).tolist() + self.transform_matrix[layer] = [[m[j*3+i][0] for i in range(3)] for j in range(3)] + + else : + self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points") + else : + self.error(_("Orientation points are wrong! (if there are two orientation points they sould not be the same. If there are three orientation points they should not be in a straight line.)"),"wrong_orientation_points") + + self.transform_matrix_reverse[layer] = numpy.linalg.inv(self.transform_matrix[layer]).tolist() + print_("\n Layer '%s' transformation matrixes:" % layer.get(inkex.addNS('label','inkscape')) ) + print_(self.transform_matrix) + print_(self.transform_matrix_reverse) + + ###self.Zauto_scale[layer] = math.sqrt( (self.transform_matrix[layer][0][0]**2 + self.transform_matrix[layer][1][1]**2)/2 ) + ### Zautoscale is absolete + self.Zauto_scale[layer] = 1 + print_("Z automatic scale = %s (computed according orientation points)" % self.Zauto_scale[layer]) + + x,y = source_point[0], source_point[1] + if not reverse : + t = self.transform_matrix[layer] + else : + t = self.transform_matrix_reverse[layer] + return [t[0][0]*x+t[0][1]*y+t[0][2], t[1][0]*x+t[1][1]*y+t[1][2]] + + + def transform_csp(self, csp_, layer, reverse = False): + csp = [ [ [csp_[i][j][0][:],csp_[i][j][1][:],csp_[i][j][2][:]] for j in range(len(csp_[i])) ] for i in range(len(csp_)) ] + for i in xrange(len(csp)): + for j in xrange(len(csp[i])): + for k in xrange(len(csp[i][j])): + csp[i][j][k] = self.transform(csp[i][j][k],layer, reverse) + return csp + + +################################################################################ +### Errors handling function, notes are just printed into Logfile, +### warnings are printed into log file and warning message is displayed but +### extension continues working, errors causes log and execution is halted +### Notes, warnings adn errors could be assigned to space or comma or dot +### sepparated strings (case is ignoreg). +################################################################################ + def error(self, s, type_= "Warning"): + notes = "Note " + warnings = """ + Warning tools_warning + bad_orientation_points_in_some_layers + more_than_one_orientation_point_groups + more_than_one_tool + orientation_have_not_been_defined + tool_have_not_been_defined + selection_does_not_contain_paths + selection_does_not_contain_paths_will_take_all + selection_is_empty_will_comupe_drawing + selection_contains_objects_that_are_not_paths + """ + errors = """ + Error + wrong_orientation_points + area_tools_diameter_error + no_tool_error + active_layer_already_has_tool + active_layer_already_has_orientation_points + """ + if type_.lower() in re.split("[\s\n,\.]+", errors.lower()) : + print_(s) + inkex.errormsg(s+"\n") + sys.exit() + elif type_.lower() in re.split("[\s\n,\.]+", warnings.lower()) : + print_(s) + inkex.errormsg(s+"\n") + elif type_.lower() in re.split("[\s\n,\.]+", notes.lower()) : + print_(s) + else : + print_(s) + inkex.errormsg(s) + sys.exit() + + +################################################################################ +### Get defs from svg +################################################################################ + def get_defs(self) : + self.defs = {} + def recursive(g) : + for i in g: + if i.tag == inkex.addNS("defs","svg") : + for j in i: + self.defs[j.get("id")] = i + if i.tag ==inkex.addNS("g",'svg') : + recursive(i) + recursive(self.document.getroot()) + + +################################################################################ +### +### Get Gcodetools info from the svg +### +################################################################################ + def get_info(self): + self.selected_paths = {} + self.paths = {} + self.tools = {} + self.orientation_points = {} + self.layers = [self.document.getroot()] + self.Zcoordinates = {} + self.transform_matrix = {} + self.transform_matrix_reverse = {} + self.Zauto_scale = {} + + def recursive_search(g, layer, selected=False): + items = g.getchildren() + items.reverse() + for i in items: + if selected: + self.selected[i.get("id")] = i + if i.tag == inkex.addNS("g",'svg') and i.get(inkex.addNS('groupmode','inkscape')) == 'layer': + self.layers += [i] + recursive_search(i,i) + elif i.get('gcodetools') == "Gcodetools orientation group" : + points = self.get_orientation_points(i) + if points != None : + self.orientation_points[layer] = self.orientation_points[layer]+[points[:]] if layer in self.orientation_points else [points[:]] + print_("Found orientation points in '%s' layer: %s" % (layer.get(inkex.addNS('label','inkscape')), points)) + else : + self.error(_("Warning! Found bad orientation points in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers") + elif i.get("gcodetools") == "Gcodetools tool defenition" : + tool = self.get_tool(i) + self.tools[layer] = self.tools[layer] + [tool.copy()] if layer in self.tools else [tool.copy()] + print_("Found tool in '%s' layer: %s" % (layer.get(inkex.addNS('label','inkscape')), tool)) + elif i.tag == inkex.addNS('path','svg'): + if "gcodetools" not in i.keys() : + self.paths[layer] = self.paths[layer] + [i] if layer in self.paths else [i] + if i.get("id") in self.selected : + self.selected_paths[layer] = self.selected_paths[layer] + [i] if layer in self.selected_paths else [i] + elif i.tag == inkex.addNS("g",'svg'): + recursive_search(i,layer, (i.get("id") in self.selected) ) + elif i.get("id") in self.selected : +# xgettext:no-pango-format + self.error(_("This extension works with Paths and Dynamic Offsets and groups of them only! All other objects will be ignored!\nSolution 1: press Path->Object to path or Shift+Ctrl+C.\nSolution 2: Path->Dynamic offset or Ctrl+J.\nSolution 3: export all contours to PostScript level 2 (File->Save As->.ps) and File->Import this file."),"selection_contains_objects_that_are_not_paths") + + + recursive_search(self.document.getroot(),self.document.getroot()) + + + def get_orientation_points(self,g): + items = g.getchildren() + items.reverse() + p2, p3 = [], [] + p = None + for i in items: + if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (2 points)": + p2 += [i] + if i.tag == inkex.addNS("g",'svg') and i.get("gcodetools") == "Gcodetools orientation point (3 points)": + p3 += [i] + if len(p2)==2 : p=p2 + elif len(p3)==3 : p=p3 + if p==None : return None + points = [] + for i in p : + point = [[],[]] + for node in i : + if node.get('gcodetools') == "Gcodetools orientation point arrow": + point[0] = self.apply_transforms(node,cubicsuperpath.parsePath(node.get("d")))[0][0][1] + if node.get('gcodetools') == "Gcodetools orientation point text": + r = re.match(r'(?i)\s*\(\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*;\s*(-?\s*\d*(?:,|\.)*\d*)\s*\)\s*',node.text) + point[1] = [float(r.group(1)),float(r.group(2)),float(r.group(3))] + if point[0]!=[] and point[1]!=[]: points += [point] + if len(points)==len(p2)==2 or len(points)==len(p3)==3 : return points + else : return None + + + def get_tool(self, g): + tool = self.default_tool.copy() + tool["self_group"] = g + for i in g: + # Get parameters + if i.get("gcodetools") == "Gcodetools tool background" : + tool["style"] = simplestyle.parseStyle(i.get("style")) + elif i.get("gcodetools") == "Gcodetools tool parameter" : + key = None + value = None + for j in i: + if j.get("gcodetools") == "Gcodetools tool defention field name": + key = j.text + if j.get("gcodetools") == "Gcodetools tool defention field value": + for k in j : + if k.tag == inkex.addNS('tspan','svg') and k.get("gcodetools") == "Gcodetools tool defention field value": + if k.text!=None : value = value +"\n" + k.text if value != None else k.text + if value == None or key == None: continue + #print_("Found tool parameter '%s':'%s'" % (key,value)) + if key in self.default_tool.keys() : + try : + tool[key] = type(self.default_tool[key])(value) + except : + tool[key] = self.default_tool[key] + self.error(_("Warning! Tool's and default tool's parameter's (%s) types are not the same ( type('%s') != type('%s') ).") % (key, value, self.default_tool[key]), "tools_warning") + else : + tool[key] = value + self.error(_("Warning! Tool has parameter that default tool has not ( '%s': '%s' ).") % (key, value), "tools_warning" ) + return tool + + + def set_tool(self,layer): +# print_(("index(layer)=",self.layers.index(layer),"set_tool():layer=",layer,"self.tools=",self.tools)) +# for l in self.layers: +# print_(("l=",l)) + for i in range(self.layers.index(layer),-1,-1): +# print_(("processing layer",i)) + if self.layers[i] in self.tools : + break + if self.layers[i] in self.tools : + if self.layers[i] != layer : self.tools[layer] = self.tools[self.layers[i]] + if len(self.tools[layer])>1 : self.error(_("Layer '%s' contains more than one tool!") % self.layers[i].get(inkex.addNS('label','inkscape')), "more_than_one_tool") + return self.tools[layer] + else : + self.error(_("Can not find tool for '%s' layer! Please add one with Tools library tab!") % layer.get(inkex.addNS('label','inkscape')), "no_tool_error") + + +################################################################################ +### +### Path to Gcode +### +################################################################################ + def path_to_gcode(self) : + + def get_boundaries(points): + minx,miny,maxx,maxy=None,None,None,None + out=[[],[],[],[]] + for p in points: + if minx==p[0]: + out[0]+=[p] + if minx==None or p[0]<minx: + minx=p[0] + out[0]=[p] + + if miny==p[1]: + out[1]+=[p] + if miny==None or p[1]<miny: + miny=p[1] + out[1]=[p] + + if maxx==p[0]: + out[2]+=[p] + if maxx==None or p[0]>maxx: + maxx=p[0] + out[2]=[p] + + if maxy==p[1]: + out[3]+=[p] + if maxy==None or p[1]>maxy: + maxy=p[1] + out[3]=[p] + return out + + + def remove_duplicates(points): + i=0 + out=[] + for p in points: + for j in xrange(i,len(points)): + if p==points[j]: points[j]=[None,None] + if p!=[None,None]: out+=[p] + i+=1 + return(out) + + + def get_way_len(points): + l=0 + for i in xrange(1,len(points)): + l+=math.sqrt((points[i][0]-points[i-1][0])**2 + (points[i][1]-points[i-1][1])**2) + return l + + + def sort_dxfpoints(points): + points=remove_duplicates(points) +# print_(get_boundaries(get_boundaries(points)[2])[1]) + ways=[ + # l=0, d=1, r=2, u=3 + [3,0], # ul + [3,2], # ur + [1,0], # dl + [1,2], # dr + [0,3], # lu + [0,1], # ld + [2,3], # ru + [2,1], # rd + ] +# print_(("points=",points)) + minimal_way=[] + minimal_len=None + minimal_way_type=None + for w in ways: + tpoints=points[:] + cw=[] +# print_(("tpoints=",tpoints)) + for j in xrange(0,len(points)): + p=get_boundaries(get_boundaries(tpoints)[w[0]])[w[1]] +# print_(p) + tpoints.remove(p[0]) + cw+=p + curlen = get_way_len(cw) + if minimal_len==None or curlen < minimal_len: + minimal_len=curlen + minimal_way=cw + minimal_way_type=w + + return minimal_way + + + def print_dxfpoints(points): + gcode="" + for point in points: + gcode +="(drilling dxfpoint)\nG00 Z%f\nG00 X%f Y%f\nG01 Z%f F%f\nG04 P%f\nG00 Z%f\n" % (self.options.Zsafe,point[0],point[1],self.Zcoordinates[layer][1],self.tools[layer][0]["penetration feed"],0.2,self.options.Zsafe) +# print_(("got dxfpoints array=",points)) + return gcode + + if self.selected_paths == {} and self.options.auto_select_paths: + paths=self.paths + self.error(_("No paths are selected! Trying to work on all available paths."),"warning") + else : + paths = self.selected_paths + self.check_dir() + gcode = "" + + biarc_group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') ) + print_(("self.layers=",self.layers)) + print_(("paths=",paths)) + for layer in self.layers : +# print_(("processing layer",layer," of layers:",self.layers)) + if layer in paths : +# print_(("layer ",layer, " is in paths:",paths)) + print_(("layer",layer)) + self.set_tool(layer) + p = [] + dxfpoints = [] + for path in paths[layer] : + if "d" not in path.keys() : + self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths") + continue + csp = cubicsuperpath.parsePath(path.get("d")) + csp = self.apply_transforms(path, csp) + if path.get("dxfpoint") == "1": + tmp_curve=self.transform_csp(csp, layer) + x=tmp_curve[0][0][0][0] + y=tmp_curve[0][0][0][1] + print_("got dxfpoint (scaled) at (%f,%f)" % (x,y)) + dxfpoints += [[x,y]] + else: + p += csp + dxfpoints=sort_dxfpoints(dxfpoints) + gcode+=print_dxfpoints(dxfpoints) + curve = self.parse_curve(p, layer) + self.draw_curve(curve, layer, biarc_group) + if self.tools[layer][0]["depth step"] == 0 : self.tools[layer][0]["depth step"] = 1 + for step in range( 0, int(math.ceil( abs( (self.Zcoordinates[layer][1]-self.Zcoordinates[layer][0])/self.tools[layer][0]["depth step"] )) ) ): + Zpos = max( self.Zcoordinates[layer][1], self.Zcoordinates[layer][0] - abs(self.tools[layer][0]["depth step"]*(step+1)) ) + gcode += self.generate_gcode(curve, layer, Zpos) + + self.export_gcode(gcode) + +################################################################################ +### +### dxfpoints +### +################################################################################ + def dxfpoints(self): + if self.selected_paths == {}: + self.error(_("Noting is selected. Please select something to convert to drill point (dxfpoint) or clear point sign."),"warning") + for layer in self.layers : + if layer in self.selected_paths : + for path in self.selected_paths[layer]: +# print_(("processing path",path.get('d'))) + if self.options.dxfpoints_action == 'replace': +# print_("trying to set as dxfpoint") + + path.set("dxfpoint","1") + r = re.match("^\s*.\s*(\S+)",path.get("d")) + if r!=None: + print_(("got path=",r.group(1))) + path.set("d","m %s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z" % r.group(1)) + path.set("style",styles["dxf_points"]) + + if self.options.dxfpoints_action == 'save': + path.set("dxfpoint","1") + + if self.options.dxfpoints_action == 'clear' and path.get("dxfpoint") == "1": + path.set("dxfpoint","0") +# for id, node in self.selected.iteritems(): +# print_((id,node,node.attrib)) + + +################################################################################ +### +### Artefacts +### +################################################################################ + def area_artefacts(self) : + if self.selected_paths == {} and self.options.auto_select_paths: + paths=self.paths + self.error(_("No paths are selected! Trying to work on all available paths."),"warning") + else : + paths = self.selected_paths + for layer in paths : +# paths[layer].reverse() # Reverse list of paths to leave their order + for path in paths[layer] : + parent = path.getparent() + style = path.get("style") if "style" in path.keys() else "" + if "d" not in path.keys() : + self.error(_("Warning: One or more paths dont have 'd' parameter, try to Ungroup (Ctrl+Shift+G) and Object to Path (Ctrl+Shift+C)!"),"selection_contains_objects_that_are_not_paths") + continue + csp = cubicsuperpath.parsePath(path.get("d")) + csp = self.apply_transforms(path, csp) + for subpath in csp : + bounds = csp_simple_bound([subpath]) + if (bounds[2]-bounds[0])**2+(bounds[3]-bounds[1])**2 < self.options.area_find_artefacts_diameter**2: + if self.options.area_find_artefacts_action == "mark with an arrow" : + inkex.etree.SubElement(parent, inkex.addNS('path','svg'), + { + 'd': 'm %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z' % (subpath[0][1][0],subpath[0][1][1]), + 'style': styles["area artefact arrow"], + 'gcodetools': 'area artefact arrow', + }) + inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style, "gcodetools_parameter":"area artefact"}) + elif self.options.area_find_artefacts_action == "mark with style" : + inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': styles["area artefact"]}) + elif self.options.area_find_artefacts_action == "delete" : + print_("Deleted artifact %s" % subpath ) + else : + inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath([subpath]), 'style': style}) + parent.remove(path) + return + + +################################################################################ +### +### Calculate area curves +### +################################################################################ + def area(self) : + if len(self.selected_paths)<=0: + self.error(_("This extension requires at least one selected path."),"warning") + return + for layer in self.layers : + if layer in self.selected_paths : + self.set_tool(layer) + if self.tools[layer][0]['diameter']<=0 : + self.error(_("Tool diameter must be > 0 but tool's diameter on '%s' layer is not!") % layer.get(inkex.addNS('label','inkscape')),"area_tools_diameter_error") + + for path in self.selected_paths[layer]: + print_(("doing path", path.get("style"), path.get("d"))) + + area_group = inkex.etree.SubElement( path.getparent(), inkex.addNS('g','svg') ) + + d = path.get('d') + print_(d) + if d==None: + print_("omitting non-path") + self.error(_("Warning: omitting non-path"),"selection_contains_objects_that_are_not_paths") + continue + csp = cubicsuperpath.parsePath(d) + + if path.get(inkex.addNS('type','sodipodi'))!="inkscape:offset": + print_("Path %s is not an offset. Preparation started." % path.get("id")) + # Path is not offset. Preparation will be needed. + # Finding top most point in path (min y value) + + min_x,min_y,min_i,min_j,min_t = csp_true_bounds(csp)[1] + + # Reverse path if needed. + if min_y!=float("-inf") : + # Move outline subpath to the begining of csp + subp = csp[min_i] + del csp[min_i] + j = min_j + # Split by the topmost point and join again + if min_t in [0,1]: + if min_t == 0: j=j-1 + subp[-1][2], subp[0][0] = subp[-1][1], subp[0][1] + subp = [ [subp[j][1], subp[j][1], subp[j][2]] ] + subp[j+1:] + subp[:j] + [ [subp[j][0], subp[j][1], subp[j][1]] ] + else: + sp1,sp2,sp3 = csp_split(subp[j-1],subp[j],min_t) + subp[-1][2], subp[0][0] = subp[-1][1], subp[0][1] + subp = [ [ sp2[1], sp2[1],sp2[2] ] ] + [sp3] + subp[j+1:] + subp[:j-1] + [sp1] + [[ sp2[0], sp2[1],sp2[1] ]] + csp = [subp] + csp + # reverse path if needed + if csp_subpath_ccw(csp[0]) : + for i in range(len(csp)): + n = [] + for j in csp[i]: + n = [ [j[2][:],j[1][:],j[0][:]] ] + n + csp[i] = n[:] + + + d = cubicsuperpath.formatPath(csp) + print_(("original d=",d)) + d = re.sub(r'(?i)(m[^mz]+)',r'\1 Z ',d) + d = re.sub(r'(?i)\s*z\s*z\s*',r' Z ',d) + d = re.sub(r'(?i)\s*([A-Za-z])\s*',r' \1 ',d) + print_(("formatted d=",d)) + # scale = sqrt(Xscale**2 + Yscale**2) / sqrt(1**2 + 1**2) + p0 = self.transform([0,0],layer) + p1 = self.transform([0,1],layer) + scale = (P(p0)-P(p1)).mag() + if scale == 0 : scale = 1. + else : scale = 1./scale + print_(scale) + tool_d = self.tools[layer][0]['diameter']*scale + r = self.options.area_inkscape_radius * scale + sign=1 if r>0 else -1 + print_("Tool diameter = %s, r = %s" % (tool_d, r)) + + for i in range(self.options.max_area_curves): + radius = - tool_d * (i+0.5) * sign + if abs(radius)>abs(r): + radius = -r + + inkex.etree.SubElement( area_group, inkex.addNS('path','svg'), + { + inkex.addNS('type','sodipodi'): 'inkscape:offset', + inkex.addNS('radius','inkscape'): str(radius), + inkex.addNS('original','inkscape'): d, + 'style': styles["biarc_style_i"]['area'] + }) + print_(("adding curve",area_group,d,styles["biarc_style_i"]['area'])) + if radius == -r : break + + +################################################################################ +### +### Engraving +### +################################################################################ + def engraving(self) : + if len(self.selected_paths)<=0: + self.error(_("This extension requires at least one selected path."),"warning") + return + if not self.check_dir() : return + gcode = '' + + def find_cutter_center((x1,y1),(nx1,ny1), sp1,sp2, tool, t3 = .5): + #################################################################### + ### To find center of cutter a system of non linear equations + ### will be solved using Newton's method + #################################################################### + bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) + ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize(bez) + fx=ax*(t3*t3*t3)+bx*(t3*t3)+cx*t3+dx + fy=ay*(t3*t3*t3)+by*(t3*t3)+cy*t3+dy + + nx2,ny2 = csp_normalized_normal(sp1,sp2,t3) + intersection, t1, t2 = straight_segments_intersection([[x1,y1],[x1+nx1,y1+ny1]],[[fx,fy],[fx+nx2,fy+ny2]], False) + if not intersection or intersection == "Overlap" : + if nx1!=0 : + t1 = t2 = (x1-fx)/nx1 + else : + t1 = t2 = (y1-fy)/ny1 + + t = [ t1, t2, t3 ] + i = 0 + F = [0.,0.,0.] + F1 = [[0.,0.,0.],[0.,0.,0.],[0.,0.,0.]] + while i==0 or abs(F[0])+abs(F[1])+math.sqrt(abs(F[2])) >engraving_tolerance and i<10: + t1,t2,t3 = t[0],t[1],t[2] + fx=ax*(t3*t3*t3)+bx*(t3*t3)+cx*t3+dx + fy=ay*(t3*t3*t3)+by*(t3*t3)+cy*t3+dy + f1x=3*ax*(t3*t3)+2*bx*t3+cx + f1y=3*ay*(t3*t3)+2*by*t3+cy + i+=1 + + tx = fx-x1-nx1*t1 + ty = fy-y1-ny1*t1 + + F[0] = x1+nx1*t1-fx+t2*f1y + F[1] = y1+ny1*t1-fy-t2*f1x + F[2] = t1*t1 - tx*tx -ty*ty + + F1[0][0] = nx1 + F1[0][1] = f1y + F1[0][2] = -f1x+t2*(6*ay*t3+2*by) + + F1[1][0] = ny1 + F1[1][1] = -f1x + F1[1][2] = -f1y-t2*(6*ax*t3+2*bx) + + F1[2][0] = 2*t1+2*nx1*tx +2*ny1*ty + F1[2][1] = 0 + F1[2][2] = -2*f1x*tx -2*f1y*ty + + F1 = inv_3x3(F1) + + if ( isnan(F[0]) or isnan(F[1]) or isnan(F[2]) or + isinf(F[0]) or isinf(F[1]) or isinf(F[2]) ): + return t+[1e100,i] + + if F1!= None : + t[0] -= F1[0][0]*F[0] + F1[0][1]*F[1] + F1[0][2]*F[2] + t[1] -= F1[1][0]*F[0] + F1[1][1]*F[1] + F1[1][2]*F[2] + t[2] -= F1[2][0]*F[0] + F1[2][1]*F[1] + F1[2][2]*F[2] + else: break + + return t+[abs(F[0])+abs(F[1])+math.sqrt(abs(F[2])),i] + cspe =[] + we = [] + for layer in self.layers : + if layer in self.selected_paths : + self.set_tool(layer) + engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg') ) + for node in self.selected_paths[layer] : + if node.tag == inkex.addNS('path','svg'): + cspi = cubicsuperpath.parsePath(node.get('d')) + + for j in xrange(len(cspi)): + # Remove zerro length segments + i = 1 + while i<len(cspi[j]): + if abs(cspi[j][i-1][1][0]-cspi[j][i][1][0])<engraving_tolerance and abs(cspi[j][i-1][1][1]-cspi[j][i][1][1])<engraving_tolerance: + cspi[j][i-1][2] = cspi[j][i][2] + del cspi[j][i] + else: + i += 1 + for csp in cspi: + # Create list containing normlas and points + nl = [] + for i in range(1,len(csp)): + n, n1 = [], [] + sp1, sp2 = csp[i-1], csp[i] + for ti in [.0,.25,.75,1.]: + # Is following string is nedded or not??? (It makes t depend on form of the curve) + #ti = bezmisc.beziertatlength(bez,ti) + x1,y1 = csp_at_t(sp1,sp2,ti) + nx,ny = csp_normalized_normal(sp1,sp2,ti) + n+=[ [ [x1,y1], [nx,ny], False, False, i] ] # [point coordinates, normal, is an inner corner, is an outer corner, csp's index] + if ti==1 and i<len(csp)-1: + nx2, ny2 = csp_normalized_slope(csp[i],csp[i+1],0) + nx2,ny2 = -ny2,nx2 + ang = ny2*nx-ny*nx2 + ang1 = 180-math.acos(max(-1,min(1,nx*nx2+ny*ny2)))*180/math.pi + if ang > 0 and ang1 < self.options.engraving_sharp_angle_tollerance : # inner angle + n[-1][2] = True + elif ang < 0 and ang1 < self.options.engraving_sharp_angle_tollerance : # outer angle + a = -math.acos(nx*nx2+ny*ny2) + for t in [.0,.25,.75,1.]: + n1 += [ [ [x1,y1], [nx*math.cos(a*t)-ny*math.sin(a*t),nx*math.sin(a*t)+ny*math.cos(a*t)], False, True, i ] ] + nl += [ n ] + ([ n1 ] if n1!=[] else []) + # Modify first/last points if curve is closed + if abs(csp[-1][1][0]-csp[0][1][0])<engraving_tolerance and abs(csp[-1][1][1]-csp[0][1][1])<engraving_tolerance : + x1,y1 = csp_at_t(csp[-2],csp[-1],1) + nx,ny = csp_normalized_slope(csp[-2],csp[-1],1) + nx,ny = -ny,nx + nx2,ny2 = csp_normalized_slope(csp[0],csp[1],0) + nx2,ny2 = -ny2,nx2 + ang = ny2*nx-ny*nx2 + if ang > 0 and 180-math.acos(nx*nx2+ny*ny2)*180/math.pi < self.options.engraving_sharp_angle_tollerance : # inner angle + nl[-1][-1][2] = True + elif ang < 0 and 180-math.acos(nx*nx2+ny*ny2)*180/math.pi < self.options.engraving_sharp_angle_tollerance : # outer angle + a = -math.acos(nx*nx2+ny*ny2) + n1 = [] + for t in [.0,.25,.75,1.]: + n1 += [ [ [x1,y1], [nx*math.cos(a*t)-ny*math.sin(a*t),nx*math.sin(a*t)+ny*math.cos(a*t)], False, True, i ] ] + nl += [ n1 ] + + + print_(("engraving_draw_calculation_paths=",self.options.engraving_draw_calculation_paths)) + if self.options.engraving_draw_calculation_paths==True: + for i in nl: + for p in i: + inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), + { + "d": "M %f,%f L %f,%f" %(p[0][0],p[0][1],p[0][0]+p[1][0]*10,p[0][1]+p[1][1]*10), + 'style': "stroke:#0000ff; stroke-opacity:0.46; stroke-width:0.1; fill:none", + "gcodetools": "Engraving calculation paths" + }) + + + # Calculate offset points + csp_points = [] + for ki in xrange(len(nl)): + p = [] + for ti in xrange(3) if ki!=len(nl)-1 else xrange(4): + n = nl[ki][ti] + x1,y1 = n[0] + nx,ny = n[1] + d, r = 0, float("inf") + if ti==0 and nl[ki-1][-1][2] == True or ti==3 and nl[ki][ti][2] == True: + # Point is a sharp angle r=0p + r = 0 + else : + for j in xrange(0,len(cspi)): + for i in xrange(1,len(cspi[j])): + d = csp_bound_to_point_distance(cspi[j][i-1], cspi[j][i], [x1,y1]) + if d >= self.options.engraving_max_dist*2 : + r = min(math.sqrt(d/2),r) + continue + for n1 in xrange(self.options.engraving_newton_iterations): + t = find_cutter_center((x1,y1),(nx,ny), cspi[j][i-1], cspi[j][i], self.tools[layer][0], float(n1)/(self.options.engraving_newton_iterations-1)) + print_(t) + if t[0] > engraving_tolerance and 0<=t[2]<=1 and abs(t[3])<engraving_tolerance: + print_("!@#!@#!@#!@#!@",t) + t3 = t[2] + ax,ay,bx,by,cx,cy,dx,dy=bezmisc.bezierparameterize((cspi[j][i-1][1],cspi[j][i-1][2],cspi[j][i][0],cspi[j][i][1])) + x2=ax*(t3*t3*t3)+bx*(t3*t3)+cx*t3+dx + y2=ay*(t3*t3*t3)+by*(t3*t3)+cy*t3+dy + if abs(x2-x1)<engraving_tolerance and abs(y2-y1)<engraving_tolerance: + f1x = 3*ax*(t3*t3)+2*bx*t3+cx + f1y = 3*ay*(t3*t3)+2*by*t3+cy + f2x = 6*ax*t3+2*bx + f2y = 6*ay*t3+2*by + d = f1x*f2y-f1y*f2x + # d = curvature + if d!=0 : + d = math.sqrt((f1x*f1x+f1y*f1y)**3)/d + if d>0: + r = min( d,r) if r!=None else d + else : + r = min(r,self.options.engraving_max_dist) if r!=None else self.options.engraving_max_dist + else: + r = min(t[0],r) if r!=None else t[0] + for j in xrange(0,len(cspi)): + for i in xrange(0,len(cspi[j])): + x2,y2 = cspi[j][i][1] + if (abs(x1-x2)>engraving_tolerance or abs(y1-y2)>engraving_tolerance ) and (x2*nx - x1*nx + y2*ny - y1*ny) != 0: + t1 = .5 * ( (x1-x2)**2+(y1-y2)**2 ) / (x2*nx - x1*nx + y2*ny - y1*ny) + if t1>0 : r = min(t1,r) if r!=None else t1 + if self.options.engraving_draw_calculation_paths==True: + inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), + {"gcodetools": "Engraving calculation paths", 'style': "fill:#ff00ff; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x1+nx*r), inkex.addNS('cy','sodipodi'): str(y1+ny*r), inkex.addNS('rx','sodipodi'): str(1), inkex.addNS('ry','sodipodi'): str(1), inkex.addNS('type','sodipodi'): 'arc'}) + inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), + {"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x1+nx*r), inkex.addNS('cy','sodipodi'): str(y1+ny*r),inkex.addNS('rx','sodipodi'): str(r), inkex.addNS('ry','sodipodi'): str(r), inkex.addNS('type','sodipodi'): 'arc'}) + r = min(r, self.options.engraving_max_dist) + w = min(r, self.tools[layer][0]['diameter']) + p += [ [x1+nx*w,y1+ny*w,r,w] ] + + + + if len(csp_points)>0 : csp_points[-1] += [p[0]] + csp_points += [ p ] + # Splitting path to pieces each of them not further from path more than engraving_max_dist + engraving_path = [ [] ] + for p_ in csp_points : + for p in p_: + if p[2]<self.options.engraving_max_dist : break + if p[2]<self.options.engraving_max_dist: engraving_path[-1] += [p_] + else : + if engraving_path[-1] != [] : engraving_path += [ [] ] + if engraving_path[-1] == [] : del engraving_path[-1] + + + for csp_points in engraving_path : + # Create Path that goes through this points + cspm = [] + w = [] + m = [[0.0, 0.0, 0.0, 1.0], [0.015625, 0.140625, 0.421875, 0.421875], [0.421875, 0.421875, 0.140625, 0.015625], [1.0, 0.0, 0.0, 0.0]] + for p in csp_points: + m = numpy.array(m) + xi = numpy.array( [p[i][:2] for i in range(4)]) + sp1,sp2 = [[0.,0.],[0.,0.],[0.,0.]], [[0.,0.],[0.,0.],[0.,0.]] + a,b,c,d = numpy.linalg.solve(m, xi).tolist() + sp1[1], sp1[0] = d, d + sp1[2] = c + sp2[0] = b + sp2[1], sp2[2] = a, a + sp3,sp4,sp5 = csp_split(sp1, sp2, .25) + l = cspseglength(sp3,sp4) + sp1,sp2,sp4 = csp_split(sp1, sp2, .75) + l1 = cspseglength(sp1,sp2) + if l1!=0: + sp1,sp2,sp3 = csp_splitatlength(sp1, sp2, l/l1) + if len(cspm)>0 : + cspm[-1][2] = sp1[2] + cspm += [sp2[:], sp3[:], sp4[:]] + w += [p[i][3] for i in range(1,4)] + else : + cspm += [sp1[:], sp2[:], sp3[:], sp4[:]] + w += [p[i][3] for i in range(4)] + if self.options.engraving_draw_calculation_paths==True: + node = inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), { + "d": cubicsuperpath.formatPath([cspm]), + 'style': styles["biarc_style_i"]['biarc1'], + "gcodetools": "Engraving calculation paths", + }) + for i in xrange(len(cspm)): + inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), + {"gcodetools": "Engraving calculation paths", 'style': "fill:none; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(cspm[i][1][0]), inkex.addNS('cy','sodipodi'): str(cspm[i][1][1]),inkex.addNS('rx','sodipodi'): str(w[i]), inkex.addNS('ry','sodipodi'): str(w[i]), inkex.addNS('type','sodipodi'): 'arc'}) + cspe += [cspm] + we += [w] + + if self.tools[layer][0]['shape'] != "": + f = eval('lambda w: ' + self.tools[layer][0]['shape'].strip('"')) + else: + self.error(_("Tool '%s' has no shape!") % self.tools[layer][0]['name'],"engraving_tools_shape_error") + f = lambda w: w + + if cspe!=[]: + curve = self.parse_curve(cspe, layer, we, f) + self.draw_curve(curve, layer, engraving_group) + gcode += self.generate_gcode(curve, layer, self.options.Zsurface) + + if gcode!='' : + self.export_gcode(gcode) + else : self.error(_("No need to engrave sharp angles."),"warning") + + +################################################################################ +### +### Orientation +### +################################################################################ + def orientation(self, layer=None) : + print_("entering orientations") + if layer == None : + layer = self.current_layer if self.current_layer is not None else self.document.getroot() + if layer in self.orientation_points: + self.error(_("Active layer already has orientation points! Remove them or select another layer!"),"active_layer_already_has_orientation_points") + + orientation_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {"gcodetools":"Gcodetools orientation group"}) + doc_height = inkex.unittouu(self.document.getroot().get('height')) + if self.document.getroot().get('height') == "100%" : + doc_height = 1052.3622047 + print_("Overruding height from 100 percents to %s" % doc_height) + if self.options.unit == "G21 (All units in mm)" : + points = [[0.,0.,self.options.Zsurface],[100.,0.,self.options.Zdepth],[0.,100.,0.]] + orientation_scale = 3.5433070660 + print_("orientation_scale < 0 ===> switching to mm units=%0.10f"%orientation_scale ) + elif self.options.unit == "G20 (All units in inches)" : + points = [[0.,0.,self.options.Zsurface],[5.,0.,self.options.Zdepth],[0.,5.,0.]] + orientation_scale = 90 + print_("orientation_scale < 0 ===> switching to inches units=%0.10f"%orientation_scale ) + if self.options.orientation_points_count == 2 : + points = points[:2] + print_(("using orientation scale",orientation_scale,"i=",points)) + for i in points : + si = [i[0]*orientation_scale, i[1]*orientation_scale] + g = inkex.etree.SubElement(orientation_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools orientation point (%s points)" % self.options.orientation_points_count}) + inkex.etree.SubElement( g, inkex.addNS('path','svg'), + { + 'style': "stroke:none;fill:#000000;", + 'd':'m %s,%s 2.9375,-6.343750000001 0.8125,1.90625 6.843748640396,-6.84374864039 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.812500000001 z z' % (si[0], -si[1]+doc_height), + 'gcodetools': "Gcodetools orientation point arrow" + }) + t = inkex.etree.SubElement( g, inkex.addNS('text','svg'), + { + 'style': "font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;", + inkex.addNS("space","xml"):"preserve", + 'x': str(si[0]+10), + 'y': str(-si[1]-10+doc_height), + 'gcodetools': "Gcodetools orientation point text" + }) + t.text = "(%s; %s; %s)" % (i[0],i[1],i[2]) + + +################################################################################ +### +### Tools library +### +################################################################################ + def tools_library(self, layer=None) : + # Add a tool to the drawing + if layer == None : + layer = self.current_layer if self.current_layer is not None else self.document.getroot() + if layer in self.tools: + self.error(_("Active layer already has a tool! Remove it or select another layer!"),"active_layer_already_has_tool") + + if self.options.tools_library_type == "cylinder cutter" : + tool = { + "name": "Cylindrical cutter", + "id": "Cylindrical cutter 0001", + "diameter":10, + "penetration angle":90, + "feed":"400", + "penetration feed":"100", + "depth step":"1", + "tool change gcode":" " + } + elif self.options.tools_library_type == "lathe cutter" : + tool = { + "name": "Lathe cutter", + "id": "Lathe cutter 0001", + "diameter":10, + "penetration angle":90, + "feed":"400", + "passing feed":"800", + "fine feed":"100", + "penetration feed":"100", + "depth step":"1", + "tool change gcode":" " + } + elif self.options.tools_library_type == "cone cutter": + tool = { + "name": "Cone cutter", + "id": "Cone cutter 0001", + "diameter":10, + "shape":"w", + "feed":"400", + "penetration feed":"100", + "depth step":"1", + "tool change gcode":" " + } + elif self.options.tools_library_type == "tangent knife": + tool = { + "name": "Tangent knife", + "id": "Tangent knife 0001", + "feed":"400", + "penetration feed":"100", + "depth step":"100", + "4th axis meaning": "tangent knife", + "4th axis scale": 1., + "4th axis offset": 0, + "tool change gcode":" " + } + + elif self.options.tools_library_type == "plasma cutter": + tool = { + "name": "Plasma cutter", + "id": "Plasma cutter 0001", + "diameter":10, + "penetration feed":100, + "feed":400, + "gcode before path":"""G31 Z-100 F500 (find metal) +G92 Z0 (zerro z) +G00 Z10 F500 (going up) +M03 (turn on plasma) +G04 P0.2 (pause) +G01 Z1 (going to cutting z)\n""", + "gcode after path":"M05 (turn off plasma)\n", + } + else : + tool = self.default_tool + + tool_num = sum([len(self.tools[i]) for i in self.tools]) + colors = ["00ff00","0000ff","ff0000","fefe00","00fefe", "fe00fe", "fe7e00", "7efe00", "00fe7e", "007efe", "7e00fe", "fe007e"] + + tools_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool defenition"}) + bg = inkex.etree.SubElement( tools_group, inkex.addNS('path','svg'), + {'style': "fill:#%s;fill-opacity:0.5;stroke:#444444; stroke-width:1px;"%colors[tool_num%len(colors)], "gcodetools":"Gcodetools tool background"}) + + y = 0 + keys = [] + for key in self.tools_field_order: + if key in tool: keys += [key] + for key in tool: + if key not in keys: keys += [key] + for key in keys : + g = inkex.etree.SubElement(tools_group, inkex.addNS('g','svg'), {'gcodetools': "Gcodetools tool parameter"}) + + t = inkex.etree.SubElement( g, inkex.addNS('text','svg'), + { + 'style': ("font-size:10px;" if key!="name" else "font-size:20px;") + "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;", + inkex.addNS("space","xml"):"preserve", + 'x': str(0), + 'y': str(y), + 'gcodetools': "Gcodetools tool defention field name" + }) + t.text = str(key) + v = str(tool[key]).split("\n") + t = inkex.etree.SubElement( g, inkex.addNS('text','svg'), + { + 'style': ("font-size:10px;" if key!="name" else "font-size:20px;") + "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;", + 'x': str(150), + inkex.addNS("space","xml"):"preserve", + 'y': str(y), + 'gcodetools': "Gcodetools tool defention field value" + }) + for s in v : + span = inkex.etree.SubElement( t, inkex.addNS('tspan','svg'), + { + 'x': str(150), + 'y': str(+y), + inkex.addNS("role","sodipodi"):"line", + 'gcodetools': "Gcodetools tool defention field value" + }) + y += 15 if key!='name' else 20 + span.text = s + bg.set('d',"m -20,-20 l 400,0 0,%f -400,0 z " % (y+50)) + tool = [] + tools_group.set("transform", simpletransform.formatTransform([ [1,0,self.view_center[0]-150 ], [0,1,self.view_center[1]] ] )) + + +################################################################################ +### +### Check tools and OP asignment +### +################################################################################ + def check_tools_and_op(self): + if len(self.selected)<=0 : + self.error(_("Selection is empty! Will compute whole drawing."),"selection_is_empty_will_comupe_drawing") + paths = self.paths + else : + paths = self.selected_paths + # Set group + group = inkex.etree.SubElement( self.selected_paths.keys()[0] if len(self.selected_paths.keys())>0 else self.layers[0], inkex.addNS('g','svg') ) + trans_ = [[1,0.3,0],[0,0.5,0]] + self.get_defs() + # Add marker to defs if it doesnot exists + if "CheckToolsAndOPMarker" not in self.defs : + defs = inkex.etree.SubElement( self.document.getroot(), inkex.addNS("defs","svg")) + marker = inkex.etree.SubElement( defs, inkex.addNS("marker","svg"), {"id":"CheckToolsAndOPMarker","orient":"auto","refX":"-8","refY":"-2.41063","style":"overflow:visible"}) + inkex.etree.SubElement( marker, inkex.addNS("path","svg"), + { "d":"m -6.55552,-2.41063 0,0 L -13.11104,0 c 1.0473,-1.42323 1.04126,-3.37047 0,-4.82126", + "style": "fill:#000044; fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" } + ) + bounds = [float('inf'),float('inf'),float('-inf'),float('-inf')] + tools_bounds = {} + for layer in self.layers : + if layer in paths : + self.set_tool(layer) + tool = self.tools[layer][0] + tools_bounds[layer] = tools_bounds[layer] if layer in tools_bounds else [float("inf"),float("-inf")] + style = simplestyle.formatStyle(tool["style"]) + for path in paths[layer] : + style = "fill:%s; fill-opacity:%s; stroke:#000044; stroke-width:1; marker-mid:url(#CheckToolsAndOPMarker);" % ( + tool["style"]["fill"] if "fill" in tool["style"] else "#00ff00", + tool["style"]["fill-opacity"] if "fill-opacity" in tool["style"] else "0.5") + group.insert( 0, inkex.etree.Element(path.tag, path.attrib)) + new = group.getchildren()[0] + new.set("style", style) + + trans = self.get_transforms(path) + trans = simpletransform.composeTransform( trans_, trans if trans != [] else [[1.,0.,0.],[0.,1.,0.]]) + csp = cubicsuperpath.parsePath(path.get("d")) + simpletransform.applyTransformToPath(trans,csp) + path_bounds = csp_simple_bound(csp) + trans = simpletransform.formatTransform(trans) + bounds = [min(bounds[0],path_bounds[0]), min(bounds[1],path_bounds[1]), max(bounds[2],path_bounds[2]), max(bounds[3],path_bounds[3])] + tools_bounds[layer] = [min(tools_bounds[layer][0], path_bounds[1]), max(tools_bounds[layer][1], path_bounds[3])] + + new.set("transform", trans) + trans_[1][2] += 20 + trans_[1][2] += 100 + + for layer in self.layers : + if layer in self.tools : + if layer in tools_bounds : + tool = self.tools[layer][0] + g = copy.deepcopy(tool["self_group"]) + g.attrib["gcodetools"] = "Check tools and OP asignment" + trans = [[1,0.3,bounds[2]],[0,0.5,tools_bounds[layer][0]]] + g.set("transform",simpletransform.formatTransform(trans)) + group.insert( 0, g ) + + +################################################################################ +### TODO Launch browser on help tab +################################################################################ + def help(self): + self.error(_("""Tutorials, manuals and support can be found at\nEnglish support forum:\n http://www.cnc-club.ru/gcodetools\nand Russian support forum:\n http://www.cnc-club.ru/gcodetoolsru"""),"warning") + return + + +################################################################################ +### Lathe +################################################################################ + def generate_lathe_gcode(self, subpath, layer, feed_type) : + if len(subpath) <2 : return "" + feed = " F %f" % self.tool[feed_type] + x,z = self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap + flip_angle = -1 if x.lower()+z.lower() in ["xz", "yx", "zy"] else 1 + alias = {"X":"I", "Y":"J", "Z":"K", "x":"i", "y":"j", "z":"k"} + i_, k_ = alias[x], alias[z] + c = [ [subpath[0][1], "move", 0, 0, 0] ] + #csp_draw(self.transform_csp([subpath],layer,True), color = "Orange", width = .1) + for sp1,sp2 in zip(subpath,subpath[1:]) : + c += biarc(sp1,sp2,0,0) + for i in range(1,len(c)) : # Just in case check end point of each segment + c[i-1][4] = c[i][0][:] + c += [ [subpath[-1][1], "end", 0, 0, 0] ] + self.draw_curve(c, layer, style = styles["biarc_style_lathe_%s" % feed_type]) + + gcode = ("G01 %s %f %s %f" % (x, c[0][4][0], z, c[0][4][1]) ) + feed + "\n" # Just in case move to the start... + for s in c : + if s[1] == 'line': + gcode += ("G01 %s %f %s %f" % (x, s[4][0], z, s[4][1]) ) + feed + "\n" + elif s[1] == 'arc': + r = [(s[2][0]-s[0][0]), (s[2][1]-s[0][1])] + if (r[0]**2 + r[1]**2)>self.options.min_arc_radius: + r1, r2 = (P(s[0])-P(s[2])), (P(s[4])-P(s[2])) + if abs(r1.mag()-r2.mag()) < 0.001 : + gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f %s %f %s %f" % (x,s[4][0],z,s[4][1],i_,(s[2][0]-s[0][0]), k_, (s[2][1]-s[0][1]) ) ) + feed + "\n" + else: + r = (r1.mag()+r2.mag())/2 + gcode += ("G02" if s[3]*flip_angle<0 else "G03") + (" %s %f %s %f" % (x,s[4][0],z,y[4][1]) ) + " R%f"%r + feed + "\n" + return gcode + + + def lathe(self): + if not self.check_dir() : return + x,z = self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap + x = re.sub("^\s*([XYZxyz])\s*$",r"\1",x) + z = re.sub("^\s*([XYZxyz])\s*$",r"\1",z) + if x not in ["X", "Y", "Z", "x", "y", "z"] or z not in ["X", "Y", "Z", "x", "y", "z"] : + self.error(_("Lathe X and Z axis remap should be 'X', 'Y' or 'Z'. Exiting..."),"warning") + return + if x.lower() == z.lower() : + self.error(_("Lathe X and Z axis remap should be the same. Exiting..."),"warning") + return + if x.lower()+z.lower() in ["xy","yx"] : gcode_plane_selection = "G17 (Using XY plane)\n" + if x.lower()+z.lower() in ["xz","zx"] : gcode_plane_selection = "G18 (Using XZ plane)\n" + if x.lower()+z.lower() in ["zy","yz"] : gcode_plane_selection = "G19 (Using YZ plane)\n" + self.options.lathe_x_axis_remap, self.options.lathe_z_axis_remap = x, z + + paths = self.selected_paths + self.tool = [] + gcode = "" + for layer in self.layers : + if layer in paths : + self.set_tool(layer) + if self.tool != self.tools[layer][0] : + self.tool = self.tools[layer][0] + self.tool["passing feed"] = float(self.tool["passing feed"] if "passing feed" in self.tool else self.tool["feed"]) + self.tool["feed"] = float(self.tool["feed"]) + self.tool["fine feed"] = float(self.tool["fine feed"] if "fine feed" in self.tool else self.tool["feed"]) + + gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n" + + for path in paths[layer]: + csp = self.transform_csp(cubicsuperpath.parsePath(path.get("d")),layer) + + for subpath in csp : + # Offset the path if fine cut is defined. + fine_cut = subpath[:] + if self.options.lathe_fine_cut_width>0 : + r = self.options.lathe_fine_cut_width + # Close the path to make offset correct + bound = csp_simple_bound([subpath]) + minx,miny,maxx,maxy = csp_true_bounds([subpath]) + offsetted_subpath = csp_subpath_line_to(subpath[:], [ [subpath[-1][1][0], miny[1]-r*10 ], [subpath[0][1][0], miny[1]-r*10 ], [subpath[0][1][0], subpath[0][1][1] ] ]) + left,right = subpath[-1][1][0], subpath[0][1][0] + if left>right : left, right = right,left + offsetted_subpath = csp_offset([offsetted_subpath], r if not csp_subpath_ccw(offsetted_subpath) else -r ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [left,10], [left,0] ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [right,0], [right,10] ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [0, miny[1]-r], [10, miny[1]-r] ) + #csp_draw(self.transform_csp(offsetted_subpath,layer,True), color = "Green", width = 1) + # Join offsetted_subpath together + # Hope there wont be any cicles + subpath = csp_join_subpaths(offsetted_subpath)[0] + + # Create solid object from path and lathe_width + bound = csp_simple_bound([subpath]) + top_start, top_end = [subpath[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [subpath[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width] + + gcode += ("G01 %s %f F %f \n" % (z, top_start[1], self.tool["passing feed"]) ) + gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) ) + + subpath = csp_concat_subpaths(csp_subpath_line_to([],[top_start,subpath[0][1]]), subpath) + subpath = csp_subpath_line_to(subpath,[top_end,top_start]) + + + width = max(0, self.options.lathe_width - max(0, bound[1]) ) + step = self.tool['depth step'] + steps = int(math.ceil(width/step)) + for i in range(steps+1): + current_width = self.options.lathe_width - step*i + intersections = [] + for j in range(1,len(subpath)) : + sp1,sp2 = subpath[j-1], subpath[j] + intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width], [bound[2]+10,current_width], sp1, sp2)] + intersections += [[j,k] for k in csp_line_intersection([bound[0]-10,current_width+step], [bound[2]+10,current_width+step], sp1, sp2)] + parts = csp_subpath_split_by_points(subpath,intersections) + for part in parts : + minx,miny,maxx,maxy = csp_true_bounds([part]) + y = (maxy[1]+miny[1])/2 + if y > current_width+step : + gcode += self.generate_lathe_gcode(part,layer,"passing feed") + elif current_width <= y <= current_width+step : + gcode += self.generate_lathe_gcode(part,layer,"feed") + else : + # full step cut + part = csp_subpath_line_to([], [part[0][1], part[-1][1]] ) + gcode += self.generate_lathe_gcode(part,layer,"feed") + + top_start, top_end = [fine_cut[0][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width], [fine_cut[-1][1][0], self.options.lathe_width+self.options.Zsafe+self.options.lathe_fine_cut_width] + gcode += "\n(Fine cutting start)\n(Calculating fine cut using %s)\n"%self.options.lathe_create_fine_cut_using + for i in range(self.options.lathe_fine_cut_count) : + width = self.options.lathe_fine_cut_width*(1-float(i+1)/self.options.lathe_fine_cut_count ) + if width == 0 : + current_pass = fine_cut + else : + if self.options.lathe_create_fine_cut_using == "Move path" : + current_pass = [ [ [i2[0],i2[1]+width] for i2 in i1] for i1 in fine_cut] + else : + minx,miny,maxx,maxy = csp_true_bounds([fine_cut]) + offsetted_subpath = csp_subpath_line_to(fine_cut[:], [ [fine_cut[-1][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], miny[1]-r*10 ], [fine_cut[0][1][0], fine_cut[0][1][1] ] ]) + left,right = fine_cut[-1][1][0], fine_cut[0][1][0] + if left>right : left, right = right,left + offsetted_subpath = csp_offset([offsetted_subpath], width if not csp_subpath_ccw(offsetted_subpath) else -width ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [left,10], [left,0] ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [right,0], [right,10] ) + offsetted_subpath = csp_clip_by_line(offsetted_subpath, [0, miny[1]-r], [10, miny[1]-r] ) + current_pass = csp_join_subpaths(offsetted_subpath)[0] + + + gcode += "\n(Fine cut %i-th cicle start)\n"%(i+1) + gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) ) + gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1]+self.options.lathe_fine_cut_width, self.tool["passing feed"]) ) + gcode += ("G01 %s %f %s %f F %f \n" % (x, current_pass[0][1][0], z, current_pass[0][1][1], self.tool["fine feed"]) ) + + gcode += self.generate_lathe_gcode(current_pass,layer,"fine feed") + gcode += ("G01 %s %f F %f \n" % (z, top_start[1], self.tool["passing feed"]) ) + gcode += ("G01 %s %f %s %f F %f \n" % (x, top_start[0], z, top_start[1], self.tool["passing feed"]) ) + + + + self.export_gcode(gcode) + + + def update(self) : + try : + import urllib + f = urllib.urlopen("http://www.cnc-club.ru/gcodetools_latest_version", proxies = urllib.getproxies()) + a = f.read() + for s in a.split("\n") : + r = re.search(r"Gcodetools\s+latest\s+version\s*=\s*(.*)",s) + if r : + ver = r.group(1).strip() + if ver != gcodetools_current_version : + self.error("There is a newer version of Gcodetools you can get it at: \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). ","Warning") + else : + self.error("You are currently using latest stable version of Gcodetools.","Warning") + return + self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning") + except : + self.error("Can not check the latest version. You can check it manualy at \nhttp://www.cnc-club.ru/gcodetools (English version). \nhttp://www.cnc-club.ru/gcodetools_ru (Russian version). \nCurrent version is Gcodetools %s"%gcodetools_current_version,"Warning") + + +################################################################################ +### +### Effect +### +### Main function of Gcodetools class +### +################################################################################ + def effect(self) : + global options + options = self.options + options.self = self + options.doc_root = self.document.getroot() + + # define print_ function + global print_ + if self.options.log_create_log : + try : + if os.path.isfile(self.options.log_filename) : os.remove(self.options.log_filename) + f = open(self.options.log_filename,"a") + f.write("Gcodetools log file.\nStarted at %s.\n%s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"),options.log_filename)) + f.write("%s tab is active.\n" % self.options.active_tab) + f.close() + except : + print_ = lambda *x : None + else : print_ = lambda *x : None + if self.options.active_tab == '"help"' : + self.help() + return + elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"']: + self.error(_("Select one of the active tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library."),"error") + else: + # Get all Gcodetools data from the scene. + self.get_info() + if self.options.active_tab in ['"dxfpoints"','"path-to-gcode"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"']: + if self.orientation_points == {} : + self.error(_("Orientation points have not been defined! A default set of orientation points has been automatically added."),"warning") + self.orientation( self.layers[min(1,len(self.layers)-1)] ) + self.get_info() + if self.tools == {} : + self.error(_("Cutting tool has not been defined! A default tool has been automatically added."),"warning") + self.options.tools_library_type = "default" + self.tools_library( self.layers[min(1,len(self.layers)-1)] ) + self.get_info() + if self.options.active_tab == '"path-to-gcode"': + self.path_to_gcode() + elif self.options.active_tab == '"area"': + self.area() + elif self.options.active_tab == '"area_artefacts"': + self.area_artefacts() + elif self.options.active_tab == '"dxfpoints"': + self.dxfpoints() + elif self.options.active_tab == '"engraving"': + self.engraving() + elif self.options.active_tab == '"orientation"': + self.orientation() + elif self.options.active_tab == '"tools_library"': + if self.options.tools_library_type != "check": + self.tools_library() + else : + self.check_tools_and_op() + elif self.options.active_tab == '"lathe"': + self.lathe() + elif self.options.active_tab == '"update"': + self.update() + elif self.options.active_tab == '"offset"': + if self.options.offset_just_get_distance : + for layer in self.selected_paths : + if len(self.selected_paths[layer]) == 2 : + csp1, csp2 = cubicsuperpath.parsePath(self.selected_paths[layer][0].get("d")), cubicsuperpath.parsePath(self.selected_paths[layer][1].get("d")) + dist = csp_to_csp_distance(csp1,csp2) + print_(dist) + draw_pointer( list(csp_at_t(csp1[dist[1]][dist[2]-1],csp1[dist[1]][dist[2]],dist[3])) + +list(csp_at_t(csp2[dist[4]][dist[5]-1],csp2[dist[4]][dist[5]],dist[6])),"red","line", comment = math.sqrt(dist[0])) + return + if self.options.offset_step == 0 : self.options.offset_step = self.options.offset_radius + if self.options.offset_step*self.options.offset_radius <0 : self.options.offset_step *= -1 + time_ = time.time() + offsets_count = 0 + for layer in self.selected_paths : + for path in self.selected_paths[layer] : + + offset = self.options.offset_step/2 + while abs(offset) <= abs(self.options.offset_radius) : + offset_ = csp_offset(cubicsuperpath.parsePath(path.get("d")), offset) + offsets_count += 1 + if offset_ != [] : + for iii in offset_ : + csp_draw([iii], color="Green", width=1) + #print_(offset_) + else : + print_("------------Reached empty offset at radius %s"% offset ) + break + offset += self.options.offset_step + print_() + print_("-----------------------------------------------------------------------------------") + print_("-----------------------------------------------------------------------------------") + print_("-----------------------------------------------------------------------------------") + print_() + print_("Done in %s"%(time.time()-time_)) + print_("Total offsets count %s"%offsets_count) + elif self.options.active_tab == '"arrangement"': + self.arrangement() +# +e = Gcodetools() +e.affect() + diff --git a/share/extensions/gcodetools_all_in_one.inx b/share/extensions/gcodetools_all_in_one.inx new file mode 100644 index 000000000..0f566fc7b --- /dev/null +++ b/share/extensions/gcodetools_all_in_one.inx @@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>All in one</_name> + <id>ru.cnc-club.filter.gcodetools_ptg_area_area_artefacts_engraving_dxfpoints_tools_library_orientation</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='path-to-gcode' _gui-text='Path to Gcode'> + <param name="biarc-tolerance" type='float' precision="5" _gui-text='Biarc interpolation tolerance:'>1</param> + <param name="biarc-max-split-depth" type="int" _gui-text="Maximum splitting depth:">4</param> + <_param name="help" type="description"> +Biarc interpolation tolerance is the maximum distance between path and its approximation. +The segment will be split into two segments if the distance between path's segment and it's approximation exceeds biarc interpolation tolerance. +</_param> + </page> + + <page name='area' _gui-text='Area'> + <param name="max-area-curves" type="int" min="0" max="1000" _gui-text="Maximum area cutting curves:">100</param> + <param name="area-inkscape-radius" type="float" min="-1000" max="1000" _gui-text="Area width:">-10</param> + + <_param name="help" type="description"> +"Create area offset": creates several Inkscape path offsets to fill original path's area up to "Area radius" value. + +Outlines start from "1/2 D" up to "Area width" total width with "D" steps where D is taken from the nearest tool definition ("Tool diameter" value). +Only one offset will be created if the "Area width" is equal to "1/2 D". + </_param> + </page> + + <page name='area_artefacts' _gui-text='Area artefacts'> + <param name="area-find-artefacts-diameter" type="float" min="0.01" max="1000" _gui-text="Artefact diameter:">5.0</param> + <param name="area-find-artefacts-action" type="optiongroup" _gui-text="Action:"> + <_option value="mark with an arrow">mark with an arrow</_option> + <_option value="mark with style">mark with style</_option> + <_option value="delete">delete</_option> + </param> + <_param name="help" type="description"> +Usage: +1. Select all Area Offsets (gray outlines) +2. Object/Ungroup (Shift+Ctrl+G) +3. Press Apply + +Suspected small objects will be marked out by colored arrows. + </_param> + </page> + + <page name='engraving' _gui-text='Engraving'> + <param name="engraving-sharp-angle-tollerance" type="float" precision="5" min="0" max="180" _gui-text="Sharp angle tolerance:">150</param> + <param name="engraving-max-dist" type="float" precision="5" min="0" max="1000" _gui-text="Maximum distance for engraving:">10</param> + <param name="engraving-newton-iterations" type="int" min="2" max="10" _gui-text="Number of sample points used to calculate distance:">4</param> + <param name="engraving-draw-calculation-paths" type="boolean" _gui-text="Draw additional graphics to debug engraving path:">false</param> + + <_param name="help" type="description"> +This function creates path to engrave sharp angles. +Cutter's shape function is defined by the tool. Some simple shapes: + +cone....(45 degrees)...........: w +cone....(height/diameter=10/3).: 10/3 w +sphere..("r" diameter).........: math.sqrt(max(0,r**2-w**2)) +ellipse.(R1=r and R2=r*4r).....: math.sqrt(max(0,r**2-w**2))*4</_param> + </page> + + <page name='dxfpoints' _gui-text='DXF points'> + <_param name="help" type="description"> + +Convert selected objects to drill points (as dxf_import plugin does). Also you can save original shape. Only the start point of each curve will be used. + +Also you can manually select object, open XML editor (Shift+Ctrl+X) and add or remove XML tag 'dxfpoint' with any value. + </_param> + <param type='optiongroup' name='dxfpoints-action' _gui-text="Convert selection:"> +<_option value='save'>set as dxfpoint and save shape</_option> +<_option value='replace'>set as dxfpoint and draw arrow</_option> +<_option value='clear'>clear dxfpoint sign</_option> + </param> + + </page> + + <page name='tools_library' _gui-text='Tools library'> + + <param type='optiongroup' name='tools-library-type' _gui-text="Tools type:"> +<_option value='default tool'>default</_option> +<_option value='cylinder cutter'>cylinder</_option> +<_option value='cone cutter'>cone</_option> +<_option value='plasma cutter'>plasma</_option> +<_option value='tangent knife'>tangent knife</_option> +<_option value='lathe cutter'>lathe cutter</_option> + +<_option value='check'>Just check tools</_option> + + </param> + + <_param name="help" type="description"> +Selected tool type fills appropriate default values. You can change these values using the Text tool later on. + +The topmost (z order) tool in the active layer is used. If there is no tool inside the current layer it is taken from the upper layer. + +Press Apply to create new tool. + </_param> + </page> + + <page name='orientation' _gui-text='Orientation'> + + <param name="orientation-points-count" type="optiongroup" _gui-text="Orientation type:"> +<_option value="2">2-points mode +(move and rotate, +maintained aspect ratio X/Y)</_option> +<_option value="3">3-points mode +(move, rotate and mirror, +different X/Y scale)</_option> + </param> + <param name="Zsurface" type="float" precision="5" min="-1000" max="1000" _gui-text="Z surface:">0</param> + <param name="Zdepth" type="float" precision="5" min="-1000" max="1000" _gui-text="Z depth:">-1</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + + <_param name="help" type="description"> +Orientation points are used to calculate transformation (offset,scale,mirror,rotation in XY plane) of the path. +3-points mode only: do not put all three into one line (use 2-points mode instead). + +You can modify Z surface, Z depth values later using text tool (3rd coordinates). + +If there are no orientation points inside current layer they are taken from the upper layer. + +Do not ungroup orientation points! You can select them using double click to enter the group or by Ctrl+Click. + +Now press apply to create control points (independent set for each layer). + </_param> + </page> + + <page name='options' _gui-text='Options'> + <param name="Zscale" type="float" precision="5" min="-100000" max="100000" _gui-text="Scale along Z axis:">1</param> + <param name="Zoffset" type="float" precision="5" min="-100000" max="100000" _gui-text="Offset along Z axis:">0.0</param> + <param name="auto_select_paths" type="boolean" _gui-text="Select all paths if nothing is selected">true</param> + <param name="min-arc-radius" type="float" precision="5" min="-1000" max="1000" _gui-text="Minimum arc radius:">0.05</param> + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File:">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_area.inx b/share/extensions/gcodetools_area.inx new file mode 100644 index 000000000..718ae0d9f --- /dev/null +++ b/share/extensions/gcodetools_area.inx @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Area</_name> + <id>ru.cnc-club.filter.gcodetools_area_area_artefacts_ptg</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='area' _gui-text='Area'> + <param name="max-area-curves" type="int" min="0" max="1000" _gui-text="Maximum area cutting curves:">100</param> + <param name="area-inkscape-radius" type="float" min="-1000" max="1000" _gui-text="Area width:">-10</param> + + <_param name="help" type="description"> +"Create area offset": creates several Inkscape path offsets to fill original path's area up to "Area radius" value. + +Outlines start from "1/2 D" up to "Area width" total width with "D" steps where D is taken from the nearest tool definition ("Tool diameter" value). +Only one offset will be created if the "Area width" is equal to "1/2 D". + </_param> + </page> + + <page name='area_artefacts' _gui-text='Area artefacts'> + <param name="area-find-artefacts-diameter" type="float" min="0.01" max="1000" _gui-text="Artefact diameter:">5.0</param> + <param name="area-find-artefacts-action" type="optiongroup" _gui-text="Action:"> + <_option value="mark with an arrow">mark with an arrow</_option> + <_option value="mark with style">mark with style</_option> + <_option value="delete">delete</_option> + </param> + <_param name="help" type="description"> +Usage: +1. Select all Area Offsets (gray outlines) +2. Object/Ungroup (Shift+Ctrl+G) +3. Press Apply + +Suspected small objects will be marked out by colored arrows. + </_param> + </page> + + <page name='path-to-gcode' _gui-text='Path to Gcode'> + <param name="biarc-tolerance" type='float' precision="5" _gui-text='Biarc interpolation tolerance:'>1</param> + <param name="biarc-max-split-depth" type="int" _gui-text="Maximum splitting depth:">4</param> + <_param name="help" type="description"> +Biarc interpolation tolerance is the maximum distance between path and its approximation. +The segment will be split into two segments if the distance between path's segment and it's approximation exceeds biarc interpolation tolerance. +</_param> + </page> + + <page name='options' _gui-text='Options'> + <param name="Zscale" type="float" precision="5" min="-100000" max="100000" _gui-text="Scale along Z axis:">1</param> + <param name="Zoffset" type="float" precision="5" min="-100000" max="100000" _gui-text="Offset along Z axis:">0.0</param> + <param name="auto_select_paths" type="boolean" _gui-text="Select all paths if nothing is selected">true</param> + <param name="min-arc-radius" type="float" precision="5" min="-1000" max="1000" _gui-text="Minimum arc radius:">0.05</param> + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File:">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_check_for_updates.inx b/share/extensions/gcodetools_check_for_updates.inx new file mode 100644 index 000000000..728f5d1e6 --- /dev/null +++ b/share/extensions/gcodetools_check_for_updates.inx @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Check for updates</_name> + <id>ru.cnc-club.filter.gcodetools_update_no_options_no_preferences</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='update' _gui-text='Check for updates'> + <_param name="help" type="description">Check for Gcodetools latest stable version and try to get the updates.</_param> + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_dxf_points.inx b/share/extensions/gcodetools_dxf_points.inx new file mode 100644 index 000000000..7283853f9 --- /dev/null +++ b/share/extensions/gcodetools_dxf_points.inx @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>DXF Points</_name> + <id>ru.cnc-club.filter.gcodetools_dxfpoints_no_options</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='dxfpoints' _gui-text='DXF points'> + <_param name="help" type="description"> + +Convert selected objects to drill points (as dxf_import plugin does). Also you can save original shape. Only the start point of each curve will be used. + +Also you can manually select object, open XML editor (Shift+Ctrl+X) and add or remove XML tag 'dxfpoint' with any value. + </_param> + <param type='optiongroup' name='dxfpoints-action' _gui-text="Convert selection:"> +<_option value='save'>set as dxfpoint and save shape</_option> +<_option value='replace'>set as dxfpoint and draw arrow</_option> +<_option value='clear'>clear dxfpoint sign</_option> + </param> + + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File:">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_engraving.inx b/share/extensions/gcodetools_engraving.inx new file mode 100644 index 000000000..8645faa27 --- /dev/null +++ b/share/extensions/gcodetools_engraving.inx @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Engraving</_name> + <id>ru.cnc-club.filter.gcodetools_engraving</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='engraving' _gui-text='Engraving'> + <param name="engraving-sharp-angle-tollerance" type="float" precision="5" min="0" max="180" _gui-text="Sharp angle tolerance:">150</param> + <param name="engraving-max-dist" type="float" precision="5" min="0" max="1000" _gui-text="Maximum distance for engraving:">10</param> + <param name="engraving-newton-iterations" type="int" min="2" max="10" _gui-text="Number of sample points used to calculate distance:">4</param> + <param name="engraving-draw-calculation-paths" type="boolean" _gui-text="Draw additional graphics to debug engraving path">false</param> + + <_param name="help" type="description"> +This function creates path to engrave sharp angles. +Cutter's shape function is defined by the tool. Some simple shapes: + +cone....(45 degrees)...........: w +cone....(height/diameter=10/3).: 10/3 w +sphere..("r" diameter).........: math.sqrt(max(0,r**2-w**2)) +ellipse.(R1=r and R2=r*4r).....: math.sqrt(max(0,r**2-w**2))*4</_param> + </page> + + <page name='options' _gui-text='Options'> + <param name="Zscale" type="float" precision="5" min="-100000" max="100000" _gui-text="Scale along Z axis:">1</param> + <param name="Zoffset" type="float" precision="5" min="-100000" max="100000" _gui-text="Offset along Z axis:">0.0</param> + <param name="auto_select_paths" type="boolean" _gui-text="Select all paths if nothing is selected">true</param> + <param name="min-arc-radius" type="float" precision="5" min="-1000" max="1000" _gui-text="Minimum arc radius:">0.05</param> + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File:">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_lathe.inx b/share/extensions/gcodetools_lathe.inx new file mode 100644 index 000000000..933073649 --- /dev/null +++ b/share/extensions/gcodetools_lathe.inx @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Lathe</_name> + <id>ru.cnc-club.filter.gcodetools_lathe_ptg</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='lathe' _gui-text='Lathe'> + <param name="lathe-width" type="float" precision="5" min="0" max="1000" _gui-text="Lathe width:">10</param> + <param name="lathe-fine-cut-width" type="float" precision="5" min="0" max="1000" _gui-text="Fine cut width:">1</param> + <param name="lathe-fine-cut-count" type="int" min="0" max="1000" _gui-text="Fine cut count:">1</param> + <param name="lathe-create-fine-cut-using" _gui-text="Create fine cut using:" type="optiongroup" appearance="minimal"> + <option value="Move path">Move path</option> + <option value="Offset path">Offset path</option> + </param> + <param name="lathe-x-axis-remap" type="string" _gui-text="Lathe X axis remap:">X</param> + <param name="lathe-z-axis-remap" type="string" _gui-text="Lathe Z axis remap:">Z</param> + + + </page> + + <page name='path-to-gcode' _gui-text='Path to Gcode'> + <param name="biarc-tolerance" type='float' precision="5" _gui-text='Biarc interpolation tolerance:'>1</param> + <param name="biarc-max-split-depth" type="int" _gui-text="Maximum splitting depth:">4</param> + <_param name="help" type="description"> +Biarc interpolation tolerance is the maximum distance between path and its approximation. +The segment will be split into two segments if the distance between path's segment and it's approximation exceeds biarc interpolation tolerance. +</_param> + </page> + + <page name='options' _gui-text='Options'> + <param name="Zscale" type="float" precision="5" min="-100000" max="100000" _gui-text="Scale along Z axis:">1</param> + <param name="Zoffset" type="float" precision="5" min="-100000" max="100000" _gui-text="Offset along Z axis:">0.0</param> + <param name="auto_select_paths" type="boolean" _gui-text="Select all paths if nothing is selected">true</param> + <param name="min-arc-radius" type="float" precision="5" min="-1000" max="1000" _gui-text="Minimum arc radius:">0.05</param> + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_orientation_points.inx b/share/extensions/gcodetools_orientation_points.inx new file mode 100644 index 000000000..997b24d9b --- /dev/null +++ b/share/extensions/gcodetools_orientation_points.inx @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Orientation points</_name> + <id>ru.cnc-club.filter.gcodetools_orientation_no_options_no_preferences</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='orientation' _gui-text='Orientation'> + + <param name="orientation-points-count" type="optiongroup" _gui-text="Orientation type:"> +<_option value="2">2-points mode +(move and rotate, +maintained aspect ratio X/Y)</_option> +<_option value="3">3-points mode +(move, rotate and mirror, +different X/Y scale)</_option> + </param> + <param name="Zsurface" type="float" precision="5" min="-1000" max="1000" _gui-text="Z surface:">0</param> + <param name="Zdepth" type="float" precision="5" min="-1000" max="1000" _gui-text="Z depth:">-1</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + + <_param name="help" type="description"> +Orientation points are used to calculate transformation (offset,scale,mirror,rotation in XY plane) of the path. +3-points mode only: do not put all three into one line (use 2-points mode instead). + +You can modify Z surface, Z depth values later using text tool (3rd coordinates). + +If there are no orientation points inside current layer they are taken from the upper layer. + +Do not ungroup orientation points! You can select them using double click to enter the group or by Ctrl+Click. + +Now press apply to create control points (independent set for each layer). + </_param> + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_path_to_gcode.inx b/share/extensions/gcodetools_path_to_gcode.inx new file mode 100644 index 000000000..1be758370 --- /dev/null +++ b/share/extensions/gcodetools_path_to_gcode.inx @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Path to Gcode</_name> + <id>ru.cnc-club.filter.gcodetools_ptg</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='path-to-gcode' _gui-text='Path to Gcode'> + <param name="biarc-tolerance" type='float' precision="5" _gui-text='Biarc interpolation tolerance:'>1</param> + <param name="biarc-max-split-depth" type="int" _gui-text="Maximum splitting depth:">4</param> + <_param name="help" type="description"> +Biarc interpolation tolerance is the maximum distance between path and its approximation. +The segment will be split into two segments if the distance between path's segment and it's approximation exceeds biarc interpolation tolerance. +</_param> + </page> + + <page name='options' _gui-text='Options'> + <param name="Zscale" type="float" precision="5" min="-100000" max="100000" _gui-text="Scale along Z axis:">1</param> + <param name="Zoffset" type="float" precision="5" min="-100000" max="100000" _gui-text="Offset along Z axis:">0.0</param> + <param name="auto_select_paths" type="boolean" _gui-text="Select all paths if nothing is selected">true</param> + <param name="min-arc-radius" type="float" precision="5" min="-1000" max="1000" _gui-text="Minimum arc radius:">0.05</param> + </page> + + <page name='preferences' _gui-text='Preferences'> + <param name="filename" type="string" _gui-text="File:">output.ngc</param> + <param name="add-numeric-suffix-to-filename" type="boolean" _gui-text="Add numeric suffix to filename">true</param> + + <param name="directory" type="string" _gui-text="Directory:">/home</param> + + <param name="Zsafe" type="float" precision="5" min="-1000" max="1000" _gui-text="Z safe height for G00 move over blank:">5</param> + <param name="unit" type="enum" _gui-text="Units (mm or in):"> + <item value="G21 (All units in mm)">mm</item> + <item value="G20 (All units in inches)">in</item> + </param> + <param name="postprocessor" type="enum" _gui-text="Post-processor:"> + <item value=" ">None</item> + <item value="parameterize();">Parameterize Gcode</item> + <item value="flip(y);parameterize();">Flip y axis and parameterize Gcode</item> + <item value="round(4);">Round all values to 4 digits</item> + </param> + <param name="postprocessor-custom" type="string" _gui-text="Additional post-processor:"></param> + + + <param name="create-log" type="boolean" _gui-text="Generate log file">false</param> + <param name="log-filename" type="string" _gui-text="Full path to log file:"></param> + + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gcodetools_tools_library.inx b/share/extensions/gcodetools_tools_library.inx new file mode 100644 index 000000000..4d15dc52c --- /dev/null +++ b/share/extensions/gcodetools_tools_library.inx @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Tools library</_name> + <id>ru.cnc-club.filter.gcodetools_tools_library_no_options_no_preferences</id> + <dependency type="executable" location="extensions">gcodetools.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name='active-tab' type="notebook"> + + <page name='tools_library' _gui-text='Tools library'> + + <param type='optiongroup' name='tools-library-type' _gui-text="Tools type:"> +<_option value='default tool'>default</_option> +<_option value='cylinder cutter'>cylinder</_option> +<_option value='cone cutter'>cone</_option> +<_option value='plasma cutter'>plasma</_option> +<_option value='tangent knife'>tangent knife</_option> +<_option value='lathe cutter'>lathe cutter</_option> + +<_option value='check'>Just check tools</_option> + + </param> + + <_param name="help" type="description"> +Selected tool type fills appropriate default values. You can change these values using the Text tool later on. + +The topmost (z order) tool in the active layer is used. If there is no tool inside the current layer it is taken from the upper layer. + +Press Apply to create new tool. + </_param> + </page> + + <page name='help' _gui-text='Help'> + <_param name="fullhelp" type="description"> +Gcodetools plug-in: converts paths to Gcode (using circular interpolation), makes offset paths and engraves sharp corners using cone cutters. +This plug-in calculates Gcode for paths using circular interpolation or linear motion when needed. + +Tutorials, manuals and support can be found at +English support forum: + http://www.cnc-club.ru/gcodetools + +and Russian support forum: + http://www.cnc-club.ru/gcodetoolsru + +Credits: Nick Drobchenko, Vladimir Kalyaev, John Brooker, Henry Nicolas. + +Gcodetools ver. 1.6.01 +</_param> + + </page> + + </param> + <effect> + <effects-menu> + <submenu _name="Gcodetools"/> + </effects-menu> + <object-type>path</object-type> + </effect> + <script> + <command reldir="extensions" interpreter="python">gcodetools.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/gears.inx b/share/extensions/gears.inx index 5cf4e4c2f..8360a3745 100644 --- a/share/extensions/gears.inx +++ b/share/extensions/gears.inx @@ -4,9 +4,9 @@ <id>org.ekips.filter.gears</id> <dependency type="executable" location="extensions">gears.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="teeth" type="int" min="6" max="360" _gui-text="Number of teeth">24</param> - <param name="pitch" type="float" min="0.0" max="1000.0" _gui-text="Circular pitch, px">20.0</param> - <param name="angle" type="float" min="10.0" max="30.0" _gui-text="Pressure angle">20.0</param> + <param name="teeth" type="int" min="6" max="360" _gui-text="Number of teeth:">24</param> + <param name="pitch" type="float" min="0.0" max="1000.0" _gui-text="Circular pitch (px):">20.0</param> + <param name="angle" type="float" min="10.0" max="30.0" _gui-text="Pressure angle:">20.0</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/gears.py b/share/extensions/gears.py index e4dbefc2e..8f4745423 100644 --- a/share/extensions/gears.py +++ b/share/extensions/gears.py @@ -163,4 +163,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/generate_voronoi.inx b/share/extensions/generate_voronoi.inx index dc0dde07d..0c1e827aa 100644 --- a/share/extensions/generate_voronoi.inx +++ b/share/extensions/generate_voronoi.inx @@ -5,10 +5,17 @@ <dependency type="executable" location="extensions">generate_voronoi.py</dependency> <dependency type="executable" location="extensions">voronoi.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title1" type="description">Generate a random pattern of Voronoi cells. The pattern will be accessible in the Fill and Stroke dialog. You must select an object or a group.</_param> - <_param name="title2" type="description">If border is zero, the pattern will be discontinuous at the edges. Use a positive border, preferably greater than the cell size, to produce a smooth join of the pattern at the edges. Use a negative border to reduce the size of the pattern and get an empty border.</_param> - <param name="size" type="int" min="2" max="200" _gui-text="Average size of cell (px)">10</param> - <param name="border" type="int" min="-200" max="200" _gui-text="Size of Border (px)">0</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="size" type="int" min="2" max="200" _gui-text="Average size of cell (px):">10</param> + <param name="border" type="int" min="-200" max="200" _gui-text="Size of Border (px):">0</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="title" type="description" xml:space="preserve">Generate a random pattern of Voronoi cells. The pattern will be accessible in the Fill and Stroke dialog. You must select an object or a group. + +If border is zero, the pattern will be discontinuous at the edges. Use a positive border, preferably greater than the cell size, to produce a smooth join of the pattern at the edges. Use a negative border to reduce the size of the pattern and get an empty border.</_param> + </page> + </param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/generate_voronoi.py b/share/extensions/generate_voronoi.py index 3d5d5e9a8..54400a90a 100644 --- a/share/extensions/generate_voronoi.py +++ b/share/extensions/generate_voronoi.py @@ -78,6 +78,10 @@ class Pattern(inkex.Effect): action="store", type="int", dest="border", default=0, help="Size of Border (px)") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def effect(self): if not self.options.ids: @@ -186,4 +190,4 @@ if __name__ == '__main__': e = Pattern() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/gimp_xcf.inx b/share/extensions/gimp_xcf.inx index 6f24485f0..1f5f65949 100644 --- a/share/extensions/gimp_xcf.inx +++ b/share/extensions/gimp_xcf.inx @@ -6,9 +6,21 @@ <dependency type="executable" location="extensions">gimp_xcf.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> <dependency type="executable" location="path">gimp</dependency> - - <param name="guides" type="boolean" _gui-text="Save Guides:">false</param> - <param name="grid" type="boolean" _gui-text="Save Grid:">false</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="guides" type="boolean" _gui-text="Save Guides">false</param> + <param name="grid" type="boolean" _gui-text="Save Grid">false</param> + <param name="background" type="boolean" _gui-text="Save Background">false</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="instructions" type="description" xml:space="preserve">This extension exports the document to Gimp XCF format according to the following options: + * Save Guides: convert all guides to Gimp guides. + * Save Grid: convert the first rectangular grid to a Gimp grid (note that the default Inkscape grid is very narrow when shown in Gimp). + * Save Background: add the document background to each converted layer. + +Each first level layer is converted to a Gimp layer. Sublayers are concatenated and converted with their first level parent layer into a single Gimp layer.</_param> + </page> + </param> <output> <extension>.xcf</extension> <mimetype>application/x-xcf</mimetype> diff --git a/share/extensions/gimp_xcf.py b/share/extensions/gimp_xcf.py index 92da6cf40..ae62c4a3d 100755 --- a/share/extensions/gimp_xcf.py +++ b/share/extensions/gimp_xcf.py @@ -1,6 +1,7 @@ #!/usr/bin/env python ''' Copyright (C) 2006 Aaron Spike, aaron@ekips.org +Copyright (C) 2010 Nicolas Dufour, nicoduf@yahoo.fr (Windows support and various fixes) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +18,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' import inkex -import sys, os, tempfile +import sys, os, tempfile, shutil +import gettext try: from subprocess import Popen, PIPE @@ -28,95 +30,134 @@ except: class MyEffect(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("-d", "--guides", - action="store", type="inkbool", - dest="saveGuides", default=False, - help="Save the Guides with the .XCF") - self.OptionParser.add_option("-r", "--grid", - action="store", type="inkbool", - dest="saveGrid", default=False, - help="Save the Grid with the .XCF") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab") + self.OptionParser.add_option("-d", "--guides", + action="store", type="inkbool", + dest="saveGuides", default=False, + help="Save the Guides with the .XCF") + self.OptionParser.add_option("-r", "--grid", + action="store", type="inkbool", + dest="saveGrid", default=False, + help="Save the Grid with the .XCF") + self.OptionParser.add_option("-b", "--background", + action="store", type="inkbool", + dest="layerBackground", default=False, + help="Add background color to each layer") + def output(self): pass + + def clear_tmp(self): + shutil.rmtree(self.tmp_dir) + def effect(self): svg_file = self.args[-1] - docname = self.xpathSingle('/svg:svg/@sodipodi:docname')[:-4] - pageHeight = int(self.xpathSingle('/svg:svg/@height').split('.')[0]) - pageWidth = int(self.xpathSingle('/svg:svg/@width').split('.')[0]) + ttmp_orig = self.document.getroot() + docname = ttmp_orig.get(inkex.addNS('docname',u'sodipodi')) + if docname is None: docname = self.args[-1] - #create os temp dir - tmp_dir = tempfile.mkdtemp() - - hGuides = [] - vGuides = [] - if self.options.saveGuides: - guideXpath = "sodipodi:namedview/sodipodi:guide" #grab all guide tags in the namedview tag - for guideNode in self.document.xpath(guideXpath, namespaces=inkex.NSS): - ori = guideNode.get('orientation') - if ori == '0,1': - #this is a horizontal guide - pos = int(guideNode.get('position').split(',')[1].split('.')[0]) - #GIMP doesn't like guides that are outside of the image - if pos > 0 and pos < pageHeight: - #the origin is at the top in GIMP land - hGuides.append(str(pageHeight - pos)) - elif ori == '1,0': - #this is a vertical guide - pos = int(guideNode.get('position').split(',')[0].split('.')[0]) - #GIMP doesn't like guides that are outside of the image - if pos > 0 and pos < pageWidth: - vGuides.append(str(pos)) - - hGList = ' '.join(hGuides) - vGList = ' '.join(vGuides) - - gridSpacingFunc = '' - gridOriginFunc = '' - #GIMP only allows one rectangular grid - if self.options.saveGrid: - gridNode = self.xpathSingle("sodipodi:namedview/inkscape:grid[@type='xygrid' and (not(@units) or @units='px')]") - if gridNode != None: - #these attributes could be nonexistant - spacingX = gridNode.get('spacingx') - if spacingX == None: spacingX = '1 ' - - spacingY = gridNode.get('spacingy') - if spacingY == None: spacingY = '1 ' - - originX = gridNode.get('originx') - if originX == None: originX = '0 ' - - originY = gridNode.get('originy') - if originY == None: originY = '0 ' - - gridSpacingFunc = '(gimp-image-grid-set-spacing img %s %s)' % (spacingX[:-2], spacingY[:-2]) - gridOriginFunc = '(gimp-image-grid-set-offset img %s %s)'% (originX[:-2], originY[:-2]) + pageHeight = int(inkex.unittouu(self.xpathSingle('/svg:svg/@height').split('.')[0])) + pageWidth = int(inkex.unittouu(self.xpathSingle('/svg:svg/@width').split('.')[0])) + #create os temp dir + self.tmp_dir = tempfile.mkdtemp() + + # Guides + hGuides = [] + vGuides = [] + if self.options.saveGuides: + guideXpath = "sodipodi:namedview/sodipodi:guide" #grab all guide tags in the namedview tag + for guideNode in self.document.xpath(guideXpath, namespaces=inkex.NSS): + ori = guideNode.get('orientation') + if ori == '0,1': + #this is a horizontal guide + pos = int(guideNode.get('position').split(',')[1].split('.')[0]) + #GIMP doesn't like guides that are outside of the image + if pos > 0 and pos < pageHeight: + #the origin is at the top in GIMP land + hGuides.append(str(pageHeight - pos)) + elif ori == '1,0': + #this is a vertical guide + pos = int(guideNode.get('position').split(',')[0].split('.')[0]) + #GIMP doesn't like guides that are outside of the image + if pos > 0 and pos < pageWidth: + vGuides.append(str(pos)) + + hGList = ' '.join(hGuides) + vGList = ' '.join(vGuides) + + # Grid + gridSpacingFunc = '' + gridOriginFunc = '' + #GIMP only allows one rectangular grid + gridXpath = "sodipodi:namedview/inkscape:grid[@type='xygrid' and (not(@units) or @units='px')]" + if (self.options.saveGrid and self.document.xpath(gridXpath, namespaces=inkex.NSS)): + gridNode = self.xpathSingle(gridXpath) + if gridNode != None: + #these attributes could be nonexistant + spacingX = gridNode.get('spacingx') + if spacingX == None: spacingX = '1 ' + + spacingY = gridNode.get('spacingy') + if spacingY == None: spacingY = '1 ' + + originX = gridNode.get('originx') + if originX == None: originX = '0 ' + + originY = gridNode.get('originy') + if originY == None: originY = '0 ' + + gridSpacingFunc = '(gimp-image-grid-set-spacing img %s %s)' % (spacingX[:-2], spacingY[:-2]) + gridOriginFunc = '(gimp-image-grid-set-offset img %s %s)'% (originX[:-2], originY[:-2]) + + # Layers area = '--export-area-page' + opacity = '--export-background-opacity=' + if self.options.layerBackground: + opacity += "1" + else: + opacity += "0" pngs = [] names = [] + valid = 0 path = "/svg:svg/*[name()='g' or @style][@id]" for node in self.document.xpath(path, namespaces=inkex.NSS): - id = node.get('id') - name = "%s.png" % id - filename = os.path.join(tmp_dir, name) - command = "inkscape -i %s -j %s -e %s %s " % (id, area, filename, svg_file) - if bsubprocess: - p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) - return_code = p.wait() - f = p.stdout - err = p.stderr - else: - _,f,err = os.popen3(command,'r') - f.read() - f.close() - err.close() - pngs.append(filename) - names.append(id) + if len(node) > 0: # Get rid of empty layers + valid=1 + id = node.get('id') + if node.get("{" + inkex.NSS["inkscape"] + "}label"): + name = node.get("{" + inkex.NSS["inkscape"] + "}label") + else: + name = id + filename = os.path.join(self.tmp_dir, "%s.png" % id) + command = "inkscape -i %s -j %s %s -e %s %s " % (id, area, opacity, filename, svg_file) + if bsubprocess: + p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) + return_code = p.wait() + f = p.stdout + err = p.stderr + else: + _,f,err = os.popen3(command,'r') + f.read() + f.close() + err.close() + if os.name == 'nt': + filename = filename.replace("\\", "/") + pngs.append(filename) + names.append(name.encode('utf-8')) + + if (valid==0): + inkex.errormsg(gettext.gettext('This extension requires at least one non empty layer.')) + self.clear_tmp() + sys.exit(0) filelist = '"%s"' % '" "'.join(pngs) namelist = '"%s"' % '" "'.join(names) - xcf = os.path.join(tmp_dir, "%s.xcf" % docname) + xcf = os.path.join(self.tmp_dir, "%s.xcf" % docname) + if os.name == 'nt': + xcf = xcf.replace("\\", "/") script_fu = """ (tracing 1) (define @@ -167,7 +208,7 @@ class MyEffect(inkex.Effect): (gimp-quit 0) """ % (filelist, namelist, hGList, vGList, gridSpacingFunc, gridOriginFunc, xcf, xcf) - junk = os.path.join(tmp_dir, 'junk_from_gimp.txt') + junk = os.path.join(self.tmp_dir, 'junk_from_gimp.txt') f = os.popen('gimp -i --batch-interpreter plug-in-script-fu-eval -b - > %s 2>&1' % junk,'w') f.write(script_fu) f.close() @@ -176,9 +217,17 @@ class MyEffect(inkex.Effect): #inkex.debug(err.read()) #err.close() - x = open(xcf, 'r') + x = open(xcf, 'rb') + if os.name == 'nt': + try: + import msvcrt + msvcrt.setmode(1, os.O_BINARY) + except: + pass sys.stdout.write(x.read()) x.close() + self.clear_tmp() + if __name__ == '__main__': e = MyEffect() diff --git a/share/extensions/grid_cartesian.inx b/share/extensions/grid_cartesian.inx index ecec105de..445f50904 100644 --- a/share/extensions/grid_cartesian.inx +++ b/share/extensions/grid_cartesian.inx @@ -4,25 +4,27 @@ <id>grid.cartesian</id> <dependency type="executable" location="extensions">grid_cartesian.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="x_divs" type="int" min="1" max="1000" _gui-text="Major X Divisions">6</param> - <param name="dx" type="float" min="1" max="1000" _gui-text="Major X Division Spacing [px]">100.0</param> - <param name="x_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major X Division">2</param> + <param name="border_th" type="float" min="0" max="1000" _gui-text="Border Thickness (px):">3</param> + <_param name="x_axis" type="groupheader">X Axis</_param> + <param name="x_divs" type="int" min="1" max="1000" _gui-text="Major X Divisions:">6</param> + <param name="dx" type="float" min="1" max="1000" _gui-text="Major X Division Spacing (px):">100.0</param> + <param name="x_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major X Division:">2</param> <param name="x_log" type="boolean" _gui-text="Logarithmic X Subdiv. (Base given by entry above)">false</param> - <param name="x_subsubdivs" type="int" min="1" max="1000" _gui-text="Subsubdivs. per X Subdivision">5</param> - <param name="x_half_freq" type="int" min="1" max="1000" _gui-text="Halve X Subsubdiv. Frequency after 'n' Subdivs. (log only)">4</param> - <param name="x_divs_th" type="float" min="0" max="1000" _gui-text="Major X Division Thickness [px]">2</param> - <param name="x_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor X Division Thickness [px]">1</param> - <param name="x_subsubdivs_th" type="float" min="0" max="1000" _gui-text="Subminor X Division Thickness [px]">0.3</param> - <param name="y_divs" type="int" min="1" max="1000" _gui-text="Major Y Divisions">5</param> - <param name="dy" type="float" min="1" max="1000" _gui-text="Major Y Division Spacing [px]">100.0</param> - <param name="y_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Y Division">1</param> + <param name="x_subsubdivs" type="int" min="1" max="1000" _gui-text="Subsubdivs. per X Subdivision:">5</param> + <param name="x_half_freq" type="int" min="1" max="1000" _gui-text="Halve X Subsubdiv. Frequency after 'n' Subdivs. (log only):">4</param> + <param name="x_divs_th" type="float" min="0" max="1000" _gui-text="Major X Division Thickness (px):">2</param> + <param name="x_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor X Division Thickness (px):">1</param> + <param name="x_subsubdivs_th" type="float" min="0" max="1000" _gui-text="Subminor X Division Thickness (px):">0.3</param> + <_param name="y_axis" type="groupheader">Y Axis</_param> + <param name="y_divs" type="int" min="1" max="1000" _gui-text="Major Y Divisions:">5</param> + <param name="dy" type="float" min="1" max="1000" _gui-text="Major Y Division Spacing (px):">100.0</param> + <param name="y_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Y Division:">1</param> <param name="y_log" type="boolean" _gui-text="Logarithmic Y Subdiv. (Base given by entry above)">false</param> - <param name="y_subsubdivs" type="int" min="1" max="1000" _gui-text="Subsubdivs. per Y Subdivision">5</param> - <param name="y_half_freq" type="int" min="1" max="1000" _gui-text="Halve Y Subsubdiv. Frequency after 'n' Subdivs. (log only)">4</param> - <param name="y_divs_th" type="float" min="0" max="1000" _gui-text="Major Y Division Thickness [px]">2</param> - <param name="y_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Y Division Thickness [px]">1</param> - <param name="y_subsubdivs_th" type="float" min="0" max="1000" _gui-text="Subminor Y Division Thickness [px]">0.3</param> - <param name="border_th" type="float" min="0" max="1000" _gui-text="Border Thickness [px]">3</param> + <param name="y_subsubdivs" type="int" min="1" max="1000" _gui-text="Subsubdivs. per Y Subdivision:">5</param> + <param name="y_half_freq" type="int" min="1" max="1000" _gui-text="Halve Y Subsubdiv. Frequency after 'n' Subdivs. (log only):">4</param> + <param name="y_divs_th" type="float" min="0" max="1000" _gui-text="Major Y Division Thickness (px):">2</param> + <param name="y_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Y Division Thickness (px):">1</param> + <param name="y_subsubdivs_th" type="float" min="0" max="1000" _gui-text="Subminor Y Division Thickness (px):">0.3</param> <effect> <object-type>all</object-type> diff --git a/share/extensions/grid_cartesian.py b/share/extensions/grid_cartesian.py index 19adbbbe2..85716a6fd 100644 --- a/share/extensions/grid_cartesian.py +++ b/share/extensions/grid_cartesian.py @@ -261,4 +261,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/grid_polar.inx b/share/extensions/grid_polar.inx index ec73681fa..7eb0efe52 100644 --- a/share/extensions/grid_polar.inx +++ b/share/extensions/grid_polar.inx @@ -4,24 +4,28 @@ <id>grids.polar</id> <dependency type="executable" location="extensions">grid_polar.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="r_divs" type="int" min="1" max="1000" _gui-text="Major Circular Divisions">5</param> - <param name="dr" type="float" min="1" max="1000" _gui-text="Major Circular Division Spacing [px]">50.0</param> - <param name="r_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Circular Division">3</param> + <param name="c_dot_dia" type="float" min="1" max="1000" _gui-text="Centre Dot Diameter (px):">5.0</param> + <param name="a_labels" type="enum" _gui-text="Circumferential Labels:"> + <_item value="none">None</_item> + <_item value="deg">Degrees</_item> + </param> + <param name="a_label_size" type="int" min="1" max="1000" _gui-text="Circumferential Label Size (px):">18</param> + <param name="a_label_outset" type="float" min="0" max="1000" _gui-text="Circumferential Label Outset (px):">24</param> + <_param name="circ_divs_label" type="groupheader">Circular Divisions</_param> + <param name="r_divs" type="int" min="1" max="1000" _gui-text="Major Circular Divisions:">5</param> + <param name="dr" type="float" min="1" max="1000" _gui-text="Major Circular Division Spacing (px):">50.0</param> + <param name="r_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Circular Division:">3</param> <param name="r_log" type="boolean" _gui-text="Logarithmic Subdiv. (Base given by entry above)">false</param> - <param name="r_divs_th" type="float" min="0" max="1000" _gui-text="Major Circular Division Thickness [px]">2</param> - <param name="r_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Circular Division Thickness [px]">1</param> - <param name="a_divs" type="int" min="1" max="1000" _gui-text="Angle Divisions">24</param> - <param name="a_divs_cent" type="int" min="1" max="1000" _gui-text="Angle Divisions at Centre">4</param> - <param name="a_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Angular Division">1</param> - <param name="a_subdivs_cent" type="int" min="0" max="1000" _gui-text="Minor Angle Division End 'n' Divs. Before Centre">2</param> - <param name="a_divs_th" type="float" min="0" max="1000" _gui-text="Major Angular Division Thickness [px]">2</param> - <param name="a_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Angular Division Thickness [px]">1</param> - <param name="c_dot_dia" type="float" min="1" max="1000" _gui-text="Centre Dot Diameter [px]">5.0</param> - <param name="a_labels" type="optiongroup" _gui-text="Circumferential Labels"> - <_option value="none">None</_option> - <_option value="deg">Degrees</_option></param> - <param name="a_label_size" type="int" min="1" max="1000" _gui-text="Circumferential Label Size [px]">18</param> - <param name="a_label_outset" type="float" min="0" max="1000" _gui-text="Circumferential Label Outset [px]">24</param> + <param name="r_divs_th" type="float" min="0" max="1000" _gui-text="Major Circular Division Thickness (px):">2</param> + <param name="r_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Circular Division Thickness (px):">1</param> + <_param name="ang_divs_label" type="groupheader">Angular Divisions</_param> + <param name="a_divs" type="int" min="1" max="1000" _gui-text="Angle Divisions:">24</param> + <param name="a_divs_cent" type="int" min="1" max="1000" _gui-text="Angle Divisions at Centre:">4</param> + <param name="a_subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Angular Division:">1</param> + <param name="a_subdivs_cent" type="int" min="0" max="1000" _gui-text="Minor Angle Division End 'n' Divs. Before Centre:">2</param> + <param name="a_divs_th" type="float" min="0" max="1000" _gui-text="Major Angular Division Thickness (px):">2</param> + <param name="a_subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Angular Division Thickness (px):">1</param> + <effect> <object-type>all</object-type> diff --git a/share/extensions/grid_polar.py b/share/extensions/grid_polar.py index 4d7a3989c..3ae3fac34 100644 --- a/share/extensions/grid_polar.py +++ b/share/extensions/grid_polar.py @@ -195,4 +195,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/guides_creator.inx b/share/extensions/guides_creator.inx index 23fed9d56..11aa84e11 100644 --- a/share/extensions/guides_creator.inx +++ b/share/extensions/guides_creator.inx @@ -4,36 +4,36 @@ <id>org.inkscape.effect.guidescreator</id> <dependency type="executable" location="extensions">guides_creator.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="preset" type="optiongroup" appearance="minimal" _gui-text="Preset"> - <_option value="custom">Custom...</_option> - <_option value="golden">Golden ratio</_option> - <_option value="3;3">Rule-of-third</_option> - </param> - <param name="vertical_guides" type="optiongroup" appearance="minimal" _gui-text="Vertical guide each"> - <_option value="0">None</_option> - <_option value="2">1/2</_option> - <_option value="3">1/3</_option> - <_option value="4">1/4</_option> - <_option value="5">1/5</_option> - <_option value="6">1/6</_option> - <_option value="7">1/7</_option> - <_option value="8">1/8</_option> - <_option value="9">1/9</_option> - <_option value="10">1/10</_option> + <param name="preset" type="enum" _gui-text="Preset:"> + <_item value="custom">Custom...</_item> + <_item value="golden">Golden ratio</_item> + <_item value="3;3">Rule-of-third</_item> + </param> + <param name="vertical_guides" type="enum" _gui-text="Vertical guide each:"> + <_item value="0">None</_item> + <_item value="2">1/2</_item> + <_item value="3">1/3</_item> + <_item value="4">1/4</_item> + <_item value="5">1/5</_item> + <_item value="6">1/6</_item> + <_item value="7">1/7</_item> + <_item value="8">1/8</_item> + <_item value="9">1/9</_item> + <_item value="10">1/10</_item> </param> - <param name="horizontal_guides" type="optiongroup" appearance="minimal" _gui-text="Horizontal guide each"> - <_option value="0">None</_option> - <_option value="2">1/2</_option> - <_option value="3">1/3</_option> - <_option value="4">1/4</_option> - <_option value="5">1/5</_option> - <_option value="6">1/6</_option> - <_option value="7">1/7</_option> - <_option value="8">1/8</_option> - <_option value="9">1/9</_option> - <_option value="10">1/10</_option> + <param name="horizontal_guides" type="enum" _gui-text="Horizontal guide each:"> + <_item value="0">None</_item> + <_item value="2">1/2</_item> + <_item value="3">1/3</_item> + <_item value="4">1/4</_item> + <_item value="5">1/5</_item> + <_item value="6">1/6</_item> + <_item value="7">1/7</_item> + <_item value="8">1/8</_item> + <_item value="9">1/9</_item> + <_item value="10">1/10</_item> </param> - <param name="start_from_edges" type="boolean" _gui-text="Start from edges">false</param> + <param name="start_from_edges" type="boolean" _gui-text="Start from edges">false</param> <param name="delete_existing_guides" type="boolean" _gui-text="Delete existing guides">false</param> <effect> <object-type>all</object-type> diff --git a/share/extensions/guillotine.inx b/share/extensions/guillotine.inx new file mode 100644 index 000000000..6e2aa000e --- /dev/null +++ b/share/extensions/guillotine.inx @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Guillotine</_name> + <id>org.inkscape.guillotine</id> + + <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> + + <dependency type="executable" location="extensions">guillotine.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + + <param name="directory" type="string" _gui-text="Directory to save images to">~/</param> + <param name="image" type="string" _gui-text="Image name (without extension)">guillotined</param> + <param name="ignore" type="boolean" _gui-text="Ignore these settings and use export hints?">false</param> + + <effect needs-live-preview="false"> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Export"/> + </effects-menu> + </effect> + + <script> + <command reldir="extensions" interpreter="python">guillotine.py</command> + </script> + +</inkscape-extension> diff --git a/share/extensions/guillotine.py b/share/extensions/guillotine.py new file mode 100644 index 000000000..bda56b206 --- /dev/null +++ b/share/extensions/guillotine.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +''' +guillotine.py + +Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +----------------------- + +This script slices an inkscape drawing along the guides, similarly to +the GIMP plugin called "guillotine". It can optionally export to the +same directory as the SVG file with the same name, but with a number +suffix. e.g. + +/home/foo/drawing.svg + +will export to: + +/home/foo/drawing0.png +/home/foo/drawing1.png +/home/foo/drawing2.png +/home/foo/drawing3.png + +etc. + +''' + +import os +import sys +import inkex +import simplestyle +import locale +import gettext +_ = gettext.gettext + +locale.setlocale(locale.LC_ALL, '') + +try: + from subprocess import Popen, PIPE + bsubprocess = True +except: + bsubprocess = False + +def float_sort(a, b): + ''' + This is used to sort the horizontal and vertical guide positions, + which are floating point numbers, but which are held as text. + ''' + return cmp(float(a), float(b)) + +class Guillotine(inkex.Effect): + """Exports slices made using guides""" + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--directory", action="store", + type="string", dest="directory", + default=None, help="") + + self.OptionParser.add_option("--image", action="store", + type="string", dest="image", + default=None, help="") + + self.OptionParser.add_option("--ignore", action="store", + type="inkbool", dest="ignore", + default=None, help="") + + def get_guides(self): + ''' + Returns all guide elements as an iterable collection + ''' + root = self.document.getroot() + guides = [] + xpath = self.document.xpath("//sodipodi:guide", + namespaces=inkex.NSS) + for g in xpath: + guide = {} + (x, y) = g.attrib['position'].split(',') + if g.attrib['orientation'] == '0,1': + guide['orientation'] = 'horizontal' + guide['position'] = y + guides.append(guide) + elif g.attrib['orientation'] == '1,0': + guide['orientation'] = 'vertical' + guide['position'] = x + guides.append(guide) + return guides + + def get_all_horizontal_guides(self): + ''' + Returns all horizontal guides as a list of floats stored as + strings. Each value is the position from 0 in pixels. + ''' + guides = [] + for g in self.get_guides(): + if g['orientation'] == 'horizontal': + guides.append(g['position']) + return guides + + def get_all_vertical_guides(self): + ''' + Returns all vertical guides as a list of floats stored as + strings. Each value is the position from 0 in pixels. + ''' + guides = [] + for g in self.get_guides(): + if g['orientation'] == 'vertical': + guides.append(g['position']) + return guides + + def get_horizontal_slice_positions(self): + ''' + Make a sorted list of all horizontal guide positions, + including 0 and the document height, but not including + those outside of the canvas + ''' + root = self.document.getroot() + horizontals = ['0'] + height = inkex.unittouu(root.attrib['height']) + for h in self.get_all_horizontal_guides(): + if h >= 0 and float(h) <= float(height): + horizontals.append(h) + horizontals.append(height) + horizontals.sort(cmp=float_sort) + return horizontals + + def get_vertical_slice_positions(self): + ''' + Make a sorted list of all vertical guide positions, + including 0 and the document width, but not including + those outside of the canvas. + ''' + root = self.document.getroot() + verticals = ['0'] + width = inkex.unittouu(root.attrib['width']) + for v in self.get_all_vertical_guides(): + if v >= 0 and float(v) <= float(width): + verticals.append(v) + verticals.append(width) + verticals.sort(cmp=float_sort) + return verticals + + def get_slices(self): + ''' + Returns a list of all "slices" as denoted by the guides + on the page. Each slice is really just a 4 element list of + floats (stored as strings), consisting of the X and Y start + position and the X and Y end position. + ''' + hs = self.get_horizontal_slice_positions() + vs = self.get_vertical_slice_positions() + slices = [] + for i in range(len(hs)-1): + for j in range(len(vs)-1): + slices.append([vs[j], hs[i], vs[j+1], hs[i+1]]) + return slices + + def get_filename_parts(self): + ''' + Attempts to get directory and image as passed in by the inkscape + dialog. If the boolean ignore flag is set, then it will ignore + these settings and try to use the settings from the export + filename. + ''' + + if self.options.ignore == False: + if self.options.image == "" or self.options.image is None: + inkex.errormsg("Please enter an image name") + sys.exit(0) + return (self.options.directory, self.options.image) + else: + ''' + First get the export-filename from the document, if the + document has been exported before (TODO: Will not work if it + hasn't been exported yet), then uses this to return a tuple + consisting of the directory to export to, and the filename + without extension. + ''' + svg = self.document.getroot() + att = '{http://www.inkscape.org/namespaces/inkscape}export-filename' + try: + export_file = svg.attrib[att] + except KeyError: + inkex.errormsg("To use the export hints option, you " + + "need to have previously exported the document. " + + "Otherwise no export hints exist!") + sys.exit(-1) + dirname, filename = os.path.split(export_file) + filename = filename.rsplit(".", 1)[0] # Without extension + return (dirname, filename) + + def check_dir_exists(self, dir): + if not os.path.isdir(dir): + os.makedirs(dir) + + def get_localised_string(self, str): + return locale.format("%.f", float(str), 0) + + def export_slice(self, s, filename): + ''' + Runs inkscape's command line interface and exports the image + slice from the 4 coordinates in s, and saves as the filename + given. + ''' + svg_file = self.args[-1] + command = "inkscape -a %s:%s:%s:%s -e \"%s\" \"%s\" " % (self.get_localised_string(s[0]), self.get_localised_string(s[1]), self.get_localised_string(s[2]), self.get_localised_string(s[3]), filename, svg_file) + if bsubprocess: + p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) + return_code = p.wait() + f = p.stdout + err = p.stderr + else: + _, f, err = os.open3(command) + f.close() + + def export_slices(self, slices): + ''' + Takes the slices list and passes each one with a calculated + filename/directory into export_slice. + ''' + dirname, filename = self.get_filename_parts() + output_files = list() + if dirname == '' or dirname == None: + dirname = './' + + dirname = os.path.expanduser(dirname) + dirname = os.path.expandvars(dirname) + dirname = os.path.abspath(dirname) + if dirname[-1] != os.path.sep: + dirname += os.path.sep + self.check_dir_exists(dirname) + i = 0 + for s in slices: + f = dirname + filename + str(i) + ".png" + output_files.append(f) + self.export_slice(s, f) + i += 1 + inkex.errormsg(_("The sliced bitmaps have been saved as:") + "\n\n" + "\n".join(output_files)) + + def effect(self): + slices = self.get_slices() + self.export_slices(slices) + +if __name__ == "__main__": + e = Guillotine() + e.affect() diff --git a/share/extensions/handles.py b/share/extensions/handles.py index 256e3d422..0cbdef44c 100755 --- a/share/extensions/handles.py +++ b/share/extensions/handles.py @@ -55,4 +55,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py index 4f2eee8f9..bd28e3717 100644 --- a/share/extensions/hpgl_output.py +++ b/share/extensions/hpgl_output.py @@ -99,8 +99,8 @@ class MyEffect(inkex.Effect): mirror = 1.0 if self.options.mirror: mirror = -1.0 - if self.document.getroot().get('height'): - y0 -= float(self.document.getroot().get('height')) + if inkex.unittouu(self.document.getroot().xpath('@height', namespaces=inkex.NSS)[0]): + y0 -= float(inkex.unittouu(self.document.getroot().xpath('@height', namespaces=inkex.NSS)[0])) self.groupmat = [[[scale, 0.0, -x0*scale], [0.0, mirror*scale, -y0*scale]]] doc = self.document.getroot() self.process_group(doc) @@ -110,4 +110,4 @@ if __name__ == '__main__': #pragma: no cover e = MyEffect() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/inkex.py b/share/extensions/inkex.py index 49de51ef3..b2b59442b 100755 --- a/share/extensions/inkex.py +++ b/share/extensions/inkex.py @@ -1,9 +1,16 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- """ inkex.py A helper module for creating Inkscape extensions -Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org +Copyright (C) 2005,2010 Aaron Spike <aaron@ekips.org> and contributors + +Contributors: + Aurélio A. Heckert <aurium(a)gmail.com> + Bulia Byak <buliabyak@users.sf.net> + Nicolas Dufour, nicoduf@yahoo.fr + Peter J. R. Moulder <pjrm@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +29,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import sys, copy, optparse, random, re import gettext from math import * -_ = gettext.gettext + +gettext.install('inkscape') +# _ = gettext.gettext +# gettext.bindtextdomain('inkscape', '/usr/share/locale') +# gettext.textdomain('inkscape') #a dictionary of all of the xmlns prefixes in a standard inkscape doc NSS = { @@ -63,8 +74,9 @@ def uutounit(val, unit): try: from lxml import etree -except: - sys.exit(_('The fantastic lxml wrapper for libxml2 is required by inkex.py and therefore this extension. Please download and install the latest version from http://cheeseshop.python.org/pypi/lxml/, or install it through your package manager by a command like: sudo apt-get install python-lxml')) +except Exception, e: + sys.exit(_("The fantastic lxml wrapper for libxml2 is required by inkex.py and therefore this extension. Please download and install the latest version from http://cheeseshop.python.org/pypi/lxml/, or install it through your package manager by a command like: sudo apt-get install python-lxml\n\nTechnical details:\n%s" % (e,))) + def debug(what): sys.stderr.write(str(what) + "\n") @@ -232,4 +244,4 @@ class Effect: return retval -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/inkscape_help_keys.inx b/share/extensions/inkscape_help_keys.inx index 938a11077..30289aece 100644 --- a/share/extensions/inkscape_help_keys.inx +++ b/share/extensions/inkscape_help_keys.inx @@ -3,7 +3,7 @@ <_name>Keys and Mouse Reference</_name> <id>org.inkscape.help.keys</id> <dependency type="executable" location="extensions">launch_webbrowser.py</dependency> - <param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/keys048.html</param> + <_param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/keys048.html</_param> <effect needs-document="false"> <object-type>all</object-type> <effects-menu hidden="true"/> diff --git a/share/extensions/interp.inx b/share/extensions/interp.inx index 6c83f8a21..cd5d32343 100644 --- a/share/extensions/interp.inx +++ b/share/extensions/interp.inx @@ -4,9 +4,9 @@ <id>org.ekips.filter.interp</id> <dependency type="executable" location="extensions">interp.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="exponent" type="float" min="-100.0" max="100.0" _gui-text="Exponent">0.00</param> - <param name="steps" type="int" min="1" max="1000" _gui-text="Interpolation steps">5</param> - <param name="method" type="int" min="1" max="2" _gui-text="Interpolation method">2</param> + <param name="exponent" type="float" min="-100.0" max="100.0" _gui-text="Exponent:">0.00</param> + <param name="steps" type="int" min="1" max="1000" _gui-text="Interpolation steps:">5</param> + <param name="method" type="int" min="1" max="2" _gui-text="Interpolation method:">2</param> <param name="dup" type="boolean" _gui-text="Duplicate endpaths">true</param> <param name="style" type="boolean" _gui-text="Interpolate style">false</param> <effect> diff --git a/share/extensions/interp.py b/share/extensions/interp.py index bb05d8d84..8ca7f6aeb 100755 --- a/share/extensions/interp.py +++ b/share/extensions/interp.py @@ -313,4 +313,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/interp_att_g.inx b/share/extensions/interp_att_g.inx index cd78abccf..39c043519 100644 --- a/share/extensions/interp_att_g.inx +++ b/share/extensions/interp_att_g.inx @@ -1,51 +1,57 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Interpolate Attribute in a group</_name> - <id>org.inkscape.filter.interp-att-g</id> - <dependency type="executable" location="extensions">interp_att_g.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="intro" type="description">This effect applies a value for any interpolatable attribute for all elements inside the selected group or for all elements in a multiple selection</_param> - <param name="att" type="enum" _gui-text="Attribute to Interpolate"> - <_item value="width">Width</_item> - <_item value="height">Height</_item> - <_item value="scale">Scale</_item> - <_item value="trans-x">Translate X</_item> - <_item value="trans-y">Translate Y</_item> - <_item value="fill">Fill</_item> - <_item value="opacity">Opacity</_item> - <_item value="other">Other</_item> - </param> - <_param name="other-info" type="description">If you select "Other", you must know the SVG attributes to identify here this "other":</_param> - <param name="att-other" type="string" _gui-text="Other Attribute"></param> - <param name="att-other-type" type="enum" _gui-text="Other Attribute type"> - <_item value="color">Color</_item> - <_item value="int">Integer Number</_item> - <_item value="float">Float Number</_item> - </param> - <param name="att-other-where" type="enum" _gui-text="Where to apply?"> - <_item value="tag">Tag</_item> - <_item value="style">Style</_item> - <_item value="transform">Transformation</_item> - </param> - <_param name="sep" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> - <param name="start-val" type="string" _gui-text="Start Value"></param> - <param name="end-val" type="string" _gui-text="End Value"></param> - <param name="unit" type="enum" _gui-text="Unit"> - <_item value="none">No Unit</_item> - <_item value="color">Color</_item> - <item>px</item> - <item>pt</item> - <item>in</item> - <item>cm</item> - <item>mm</item> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">interp_att_g.py</command> - </script> + <_name>Interpolate Attribute in a group</_name> + <id>org.inkscape.filter.interp-att-g</id> + <dependency type="executable" location="extensions">interp_att_g.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="att" type="enum" _gui-text="Attribute to Interpolate:"> + <_item value="width">Width</_item> + <_item value="height">Height</_item> + <_item value="scale">Scale</_item> + <_item value="trans-x">Translate X</_item> + <_item value="trans-y">Translate Y</_item> + <_item value="fill">Fill</_item> + <_item value="opacity">Opacity</_item> + <_item value="other">Other</_item> + </param> + <_param name="other-info" type="description">If you select "Other", you must know the SVG attributes to identify here this "other".</_param> + <param name="att-other" type="string" _gui-text="Other Attribute:"></param> + <param name="att-other-type" type="enum" _gui-text="Other Attribute type:"> + <_item value="color">Color</_item> + <_item value="int">Integer Number</_item> + <_item value="float">Float Number</_item> + </param> + <param name="att-other-where" type="enum" _gui-text="Apply to:"> + <_item value="tag">Tag</_item> + <_item value="style">Style</_item> + <_item value="transform">Transformation</_item> + </param> + <_param name="sep" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> + <param name="start-val" type="string" _gui-text="Start Value:"></param> + <param name="end-val" type="string" _gui-text="End Value:"></param> + <param name="unit" type="enum" _gui-text="Unit:"> + <_item value="none">No Unit</_item> + <_item value="color">Color</_item> + <item>px</item> + <item>pt</item> + <item>in</item> + <item>cm</item> + <item>mm</item> + </param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="intro" type="description">This effect applies a value for any interpolatable attribute for all elements inside the selected group or for all elements in a multiple selection.</_param> + </page> + </param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">interp_att_g.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/interp_att_g.py b/share/extensions/interp_att_g.py index f23edaf36..9829de3e8 100755 --- a/share/extensions/interp_att_g.py +++ b/share/extensions/interp_att_g.py @@ -50,6 +50,10 @@ class InterpAttG(inkex.Effect): action="store", type="string", dest="unit", default="color", help="Values unit.") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def getColorValues(self): sv = string.replace( self.options.start_val, '#', '' ) diff --git a/share/extensions/jessyInk.js b/share/extensions/jessyInk.js index 51736ad4e..78b4bf896 100755 --- a/share/extensions/jessyInk.js +++ b/share/extensions/jessyInk.js @@ -38,6 +38,7 @@ var HOME_KEY = 36; // home keycode var END_KEY = 35; // end keycode var ENTER_KEY = 13; // next slide var SPACE_KEY = 32; +var ESCAPE_KEY = 27; // Presentation modes. var SLIDE_MODE = 1; @@ -948,7 +949,7 @@ function keydown(e) code = e.keyCode || e.charCode; if (!processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code]) - keyCodeDictionary[currentMode][code](); + return keyCodeDictionary[currentMode][code](); else document.onkeypress = keypress; } @@ -969,7 +970,7 @@ function keypress(e) str = String.fromCharCode(e.keyCode || e.charCode); if (!processingEffect && charCodeDictionary[currentMode] && charCodeDictionary[currentMode][str]) - charCodeDictionary[currentMode][str](); + return charCodeDictionary[currentMode][str](); } /** Function to supply the default char code dictionary. @@ -984,37 +985,37 @@ function getDefaultCharCodeDictionary() charCodeDict[INDEX_MODE] = new Object(); charCodeDict[DRAWING_MODE] = new Object(); - charCodeDict[SLIDE_MODE]["i"] = function () { toggleSlideIndex(); }; - charCodeDict[SLIDE_MODE]["d"] = function () { slideSwitchToDrawingMode(); }; - charCodeDict[SLIDE_MODE]["D"] = function () { slideQueryDuration(); }; - charCodeDict[SLIDE_MODE]["n"] = function () { slideAddSlide(activeSlide); }; - charCodeDict[SLIDE_MODE]["p"] = function () { slideToggleProgressBarVisibility(); }; - charCodeDict[SLIDE_MODE]["t"] = function () { slideResetTimer(); }; - charCodeDict[SLIDE_MODE]["e"] = function () { slideUpdateExportLayer(); }; - - charCodeDict[DRAWING_MODE]["d"] = function () { drawingSwitchToSlideMode(); }; - charCodeDict[DRAWING_MODE]["0"] = function () { drawingResetPathWidth(); }; - charCodeDict[DRAWING_MODE]["1"] = function () { drawingSetPathWidth(1.0); }; - charCodeDict[DRAWING_MODE]["3"] = function () { drawingSetPathWidth(3.0); }; - charCodeDict[DRAWING_MODE]["5"] = function () { drawingSetPathWidth(5.0); }; - charCodeDict[DRAWING_MODE]["7"] = function () { drawingSetPathWidth(7.0); }; - charCodeDict[DRAWING_MODE]["9"] = function () { drawingSetPathWidth(9.0); }; - charCodeDict[DRAWING_MODE]["b"] = function () { drawingSetPathColour("blue"); }; - charCodeDict[DRAWING_MODE]["c"] = function () { drawingSetPathColour("cyan"); }; - charCodeDict[DRAWING_MODE]["g"] = function () { drawingSetPathColour("green"); }; - charCodeDict[DRAWING_MODE]["k"] = function () { drawingSetPathColour("black"); }; - charCodeDict[DRAWING_MODE]["m"] = function () { drawingSetPathColour("magenta"); }; - charCodeDict[DRAWING_MODE]["o"] = function () { drawingSetPathColour("orange"); }; - charCodeDict[DRAWING_MODE]["r"] = function () { drawingSetPathColour("red"); }; - charCodeDict[DRAWING_MODE]["w"] = function () { drawingSetPathColour("white"); }; - charCodeDict[DRAWING_MODE]["y"] = function () { drawingSetPathColour("yellow"); }; - charCodeDict[DRAWING_MODE]["z"] = function () { drawingUndo(); }; - - charCodeDict[INDEX_MODE]["i"] = function () { toggleSlideIndex(); }; - charCodeDict[INDEX_MODE]["-"] = function () { indexDecreaseNumberOfColumns(); }; - charCodeDict[INDEX_MODE]["="] = function () { indexIncreaseNumberOfColumns(); }; - charCodeDict[INDEX_MODE]["+"] = function () { indexIncreaseNumberOfColumns(); }; - charCodeDict[INDEX_MODE]["0"] = function () { indexResetNumberOfColumns(); }; + charCodeDict[SLIDE_MODE]["i"] = function () { return toggleSlideIndex(); }; + charCodeDict[SLIDE_MODE]["d"] = function () { return slideSwitchToDrawingMode(); }; + charCodeDict[SLIDE_MODE]["D"] = function () { return slideQueryDuration(); }; + charCodeDict[SLIDE_MODE]["n"] = function () { return slideAddSlide(activeSlide); }; + charCodeDict[SLIDE_MODE]["p"] = function () { return slideToggleProgressBarVisibility(); }; + charCodeDict[SLIDE_MODE]["t"] = function () { return slideResetTimer(); }; + charCodeDict[SLIDE_MODE]["e"] = function () { return slideUpdateExportLayer(); }; + + charCodeDict[DRAWING_MODE]["d"] = function () { return drawingSwitchToSlideMode(); }; + charCodeDict[DRAWING_MODE]["0"] = function () { return drawingResetPathWidth(); }; + charCodeDict[DRAWING_MODE]["1"] = function () { return drawingSetPathWidth(1.0); }; + charCodeDict[DRAWING_MODE]["3"] = function () { return drawingSetPathWidth(3.0); }; + charCodeDict[DRAWING_MODE]["5"] = function () { return drawingSetPathWidth(5.0); }; + charCodeDict[DRAWING_MODE]["7"] = function () { return drawingSetPathWidth(7.0); }; + charCodeDict[DRAWING_MODE]["9"] = function () { return drawingSetPathWidth(9.0); }; + charCodeDict[DRAWING_MODE]["b"] = function () { return drawingSetPathColour("blue"); }; + charCodeDict[DRAWING_MODE]["c"] = function () { return drawingSetPathColour("cyan"); }; + charCodeDict[DRAWING_MODE]["g"] = function () { return drawingSetPathColour("green"); }; + charCodeDict[DRAWING_MODE]["k"] = function () { return drawingSetPathColour("black"); }; + charCodeDict[DRAWING_MODE]["m"] = function () { return drawingSetPathColour("magenta"); }; + charCodeDict[DRAWING_MODE]["o"] = function () { return drawingSetPathColour("orange"); }; + charCodeDict[DRAWING_MODE]["r"] = function () { return drawingSetPathColour("red"); }; + charCodeDict[DRAWING_MODE]["w"] = function () { return drawingSetPathColour("white"); }; + charCodeDict[DRAWING_MODE]["y"] = function () { return drawingSetPathColour("yellow"); }; + charCodeDict[DRAWING_MODE]["z"] = function () { return drawingUndo(); }; + + charCodeDict[INDEX_MODE]["i"] = function () { return toggleSlideIndex(); }; + charCodeDict[INDEX_MODE]["-"] = function () { return indexDecreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["="] = function () { return indexIncreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["+"] = function () { return indexIncreaseNumberOfColumns(); }; + charCodeDict[INDEX_MODE]["0"] = function () { return indexResetNumberOfColumns(); }; return charCodeDict; } @@ -1031,25 +1032,27 @@ function getDefaultKeyCodeDictionary() keyCodeDict[INDEX_MODE] = new Object(); keyCodeDict[DRAWING_MODE] = new Object(); - keyCodeDict[SLIDE_MODE][LEFT_KEY] = function() { dispatchEffects(-1); }; - keyCodeDict[SLIDE_MODE][RIGHT_KEY] = function() { dispatchEffects(1); }; - keyCodeDict[SLIDE_MODE][UP_KEY] = function() { skipEffects(-1); }; - keyCodeDict[SLIDE_MODE][DOWN_KEY] = function() { skipEffects(1); }; - keyCodeDict[SLIDE_MODE][PAGE_UP_KEY] = function() { dispatchEffects(-1); }; - keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY] = function() { dispatchEffects(1); }; - keyCodeDict[SLIDE_MODE][HOME_KEY] = function() { slideSetActiveSlide(0); }; - keyCodeDict[SLIDE_MODE][END_KEY] = function() { slideSetActiveSlide(slides.length - 1); }; - keyCodeDict[SLIDE_MODE][SPACE_KEY] = function() { dispatchEffects(1); }; - - keyCodeDict[INDEX_MODE][LEFT_KEY] = function() { indexSetPageSlide(activeSlide - 1); }; - keyCodeDict[INDEX_MODE][RIGHT_KEY] = function() { indexSetPageSlide(activeSlide + 1); }; - keyCodeDict[INDEX_MODE][UP_KEY] = function() { indexSetPageSlide(activeSlide - INDEX_COLUMNS); }; - keyCodeDict[INDEX_MODE][DOWN_KEY] = function() { indexSetPageSlide(activeSlide + INDEX_COLUMNS); }; - keyCodeDict[INDEX_MODE][PAGE_UP_KEY] = function() { indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); }; - keyCodeDict[INDEX_MODE][PAGE_DOWN_KEY] = function() { indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); }; - keyCodeDict[INDEX_MODE][HOME_KEY] = function() { indexSetPageSlide(0); }; - keyCodeDict[INDEX_MODE][END_KEY] = function() { indexSetPageSlide(slides.length - 1); }; - keyCodeDict[INDEX_MODE][ENTER_KEY] = function() { toggleSlideIndex(); }; + keyCodeDict[SLIDE_MODE][LEFT_KEY] = function() { return dispatchEffects(-1); }; + keyCodeDict[SLIDE_MODE][RIGHT_KEY] = function() { return dispatchEffects(1); }; + keyCodeDict[SLIDE_MODE][UP_KEY] = function() { return skipEffects(-1); }; + keyCodeDict[SLIDE_MODE][DOWN_KEY] = function() { return skipEffects(1); }; + keyCodeDict[SLIDE_MODE][PAGE_UP_KEY] = function() { return dispatchEffects(-1); }; + keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY] = function() { return dispatchEffects(1); }; + keyCodeDict[SLIDE_MODE][HOME_KEY] = function() { return slideSetActiveSlide(0); }; + keyCodeDict[SLIDE_MODE][END_KEY] = function() { return slideSetActiveSlide(slides.length - 1); }; + keyCodeDict[SLIDE_MODE][SPACE_KEY] = function() { return dispatchEffects(1); }; + + keyCodeDict[INDEX_MODE][LEFT_KEY] = function() { return indexSetPageSlide(activeSlide - 1); }; + keyCodeDict[INDEX_MODE][RIGHT_KEY] = function() { return indexSetPageSlide(activeSlide + 1); }; + keyCodeDict[INDEX_MODE][UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][PAGE_UP_KEY] = function() { return indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][PAGE_DOWN_KEY] = function() { return indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); }; + keyCodeDict[INDEX_MODE][HOME_KEY] = function() { return indexSetPageSlide(0); }; + keyCodeDict[INDEX_MODE][END_KEY] = function() { return indexSetPageSlide(slides.length - 1); }; + keyCodeDict[INDEX_MODE][ENTER_KEY] = function() { return toggleSlideIndex(); }; + + keyCodeDict[DRAWING_MODE][ESCAPE_KEY] = function () { return drawingSwitchToSlideMode(); }; return keyCodeDict; } @@ -1108,14 +1111,14 @@ function getDefaultMouseHandlerDictionary() mouseHandlerDict[INDEX_MODE] = new Object(); mouseHandlerDict[DRAWING_MODE] = new Object(); - mouseHandlerDict[SLIDE_MODE][MOUSE_DOWN] = function(evnt) { dispatchEffects(1); }; - mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL] = function(evnt) { slideMousewheel(evnt); }; + mouseHandlerDict[SLIDE_MODE][MOUSE_DOWN] = function(evnt) { return dispatchEffects(1); }; + mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL] = function(evnt) { return slideMousewheel(evnt); }; - mouseHandlerDict[INDEX_MODE][MOUSE_DOWN] = function(evnt) { toggleSlideIndex(); }; + mouseHandlerDict[INDEX_MODE][MOUSE_DOWN] = function(evnt) { return toggleSlideIndex(); }; - mouseHandlerDict[DRAWING_MODE][MOUSE_DOWN] = function(evnt) { drawingMousedown(evnt); }; - mouseHandlerDict[DRAWING_MODE][MOUSE_UP] = function(evnt) { drawingMouseup(evnt); }; - mouseHandlerDict[DRAWING_MODE][MOUSE_MOVE] = function(evnt) { drawingMousemove(evnt); }; + mouseHandlerDict[DRAWING_MODE][MOUSE_DOWN] = function(evnt) { return drawingMousedown(evnt); }; + mouseHandlerDict[DRAWING_MODE][MOUSE_UP] = function(evnt) { return drawingMouseup(evnt); }; + mouseHandlerDict[DRAWING_MODE][MOUSE_MOVE] = function(evnt) { return drawingMousemove(evnt); }; return mouseHandlerDict; } @@ -1370,6 +1373,18 @@ function slideUpdateExportLayer() { var nd = nodesToBeRemoved[ndCounter]; + // Before removing the node, check whether it contains any definitions. + var defs = nd.getElementsByTagNameNS(NSS["svg"], "defs"); + + for (var defsCounter = 0; defsCounter < defs.length; defsCounter++) + { + if (defs[defsCounter].id) + { + newDoc.appendChild(defs[defsCounter].cloneNode(true)); + } + } + + // Remove node. nd.parentNode.removeChild(nd); } @@ -1405,9 +1420,17 @@ function slideUpdateExportLayer() // Serialise the new document. var serializer = new XMLSerializer(); - var xml = serializer.serializeToString(newDoc); + var strm = + { + content : "", + close : function() {}, + flush : function() {}, + write : function(str, count) { this.content += str; } + }; - window.open('data:image/svg+xml;base64,' + window.btoa(xml), '_blank'); + var xml = serializer.serializeToStream(newDoc, strm, 'UTF-8'); + + window.location = 'data:application/svg+xml;base64;charset=utf-8,' + window.btoa(strm.content); // Unsuspend redraw. ROOT_NODE.unsuspendRedraw(suspendHandle); @@ -2165,17 +2188,6 @@ function calcCoord(e) svgPoint.x = e.clientX + window.pageXOffset; svgPoint.y = e.clientY + window.pageYOffset; - // The following is needed for Google Chrome, but causes problems - // with Firefox, as viewport is not implemented in Firefox 3.5. - try - { - svgPoint.x += document.rootElement.viewport.x; - svgPoint.y += document.rootElement.viewport.y; - } - catch (e) - { - } - var matrix = slides[activeSlide]["element"].getScreenCTM(); if (slides[activeSlide]["viewGroup"]) diff --git a/share/extensions/jessyInk_autoTexts.py b/share/extensions/jessyInk_autoTexts.py index a9873e2fc..cf41ad24f 100755 --- a/share/extensions/jessyInk_autoTexts.py +++ b/share/extensions/jessyInk_autoTexts.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_AutoTexts(inkex.Effect): def __init__(self): @@ -38,19 +40,19 @@ class JessyInk_AutoTexts(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) if len(self.selected) == 0: - sys.stderr.write("To assign an effect, please select an object.\n") + inkex.errormsg(_("To assign an effect, please select an object.\n\n")) for id, node in self.selected.items(): nodes = node.xpath("./svg:tspan", namespaces=inkex.NSS) if len(nodes) != 1: - sys.stderr.write("Node with id '" + str(id) + "' is not a suitable text node and was therefore ignored.\n") + inkex.errormsg(_("Node with id '{0}' is not a suitable text node and was therefore ignored.\n\n").format(str(id))) else: if self.options.autoText == "slideTitle": nodes[0].set("{" + inkex.NSS["jessyink"] + "}autoText","slideTitle") diff --git a/share/extensions/jessyInk_core_mouseHandler_zoomControl.js b/share/extensions/jessyInk_core_mouseHandler_zoomControl.js index 7944ae82f..fba33d34f 100644 --- a/share/extensions/jessyInk_core_mouseHandler_zoomControl.js +++ b/share/extensions/jessyInk_core_mouseHandler_zoomControl.js @@ -90,6 +90,8 @@ function jessyInk_core_mouseHandler_zoomControl(obj) startTime = (new Date()).getTime(); lastFrameTime = null; effect(1); + + return false; } /** Function to search for the element the user clicked on. @@ -306,17 +308,6 @@ function jessyInk_core_mouseHandler_zoomControl(obj) svgPoint.x = e.clientX + window.pageXOffset; svgPoint.y = e.clientY + window.pageYOffset; - // The following is needed for Google Chrome, but causes problems - // with Firefox, as viewport is not implemented in Firefox 3.5. - try - { - svgPoint.x += document.rootElement.viewport.x; - svgPoint.y += document.rootElement.viewport.y; - } - catch (ex) - { - } - return svgPoint; } diff --git a/share/extensions/jessyInk_effects.py b/share/extensions/jessyInk_effects.py index 862e55001..3af909bb2 100755 --- a/share/extensions/jessyInk_effects.py +++ b/share/extensions/jessyInk_effects.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_Effects(inkex.Effect): def __init__(self): @@ -43,13 +45,13 @@ class JessyInk_Effects(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) if len(self.selected) == 0: - sys.stderr.write("No object selected. Please select the object you want to assign an effect to and then press apply.\n") + inkex.errormsg(_("No object selected. Please select the object you want to assign an effect to and then press apply.\n")) for id, node in self.selected.items(): if (self.options.effectIn == "appear") or (self.options.effectIn == "fade") or (self.options.effectIn == "pop"): diff --git a/share/extensions/jessyInk_export.py b/share/extensions/jessyInk_export.py index 6f9bf9ecc..65247ab7e 100755 --- a/share/extensions/jessyInk_export.py +++ b/share/extensions/jessyInk_export.py @@ -30,6 +30,8 @@ import os import zipfile import glob import re +import gettext +_ = gettext.gettext def propStrToDict(inStr): dictio = {} @@ -77,7 +79,7 @@ class MyEffect(inkex.Effect): self.inkscapeCommand = self.findInkscapeCommand() if (self.inkscapeCommand == None): - sys.stderr.write("Could not find Inkscape command.\n") + inkex.errormsg(_("Could not find Inkscape command.\n")) sys.exit(1) def output(self): @@ -91,7 +93,7 @@ class MyEffect(inkex.Effect): scriptNodes = self.document.xpath("//svg:script[@jessyink:version]", namespaces=inkex.NSS) if len(scriptNodes) != 0: - sys.stderr.write("The JessyInk-script is present in this SVG file. This indicates that the presentation has not been properly exported. Please visit code.goolge.com/p/jessyink to find information on how to export a JessyInk presentation.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) zipFileDesc, zpFile = tempfile.mkstemp(suffix=".zip", prefix="jessyInk__") diff --git a/share/extensions/jessyInk_install.py b/share/extensions/jessyInk_install.py index f96615289..f1e951ec6 100755 --- a/share/extensions/jessyInk_install.py +++ b/share/extensions/jessyInk_install.py @@ -60,7 +60,7 @@ class JessyInk_Install(inkex.Effect): scriptElm = inkex.etree.Element(inkex.addNS("script", "svg")) scriptElm.text = open(os.path.join(os.path.dirname(__file__), "jessyInk.js")).read() scriptElm.set("id","JessyInk") - scriptElm.set("{" + inkex.NSS["jessyink"] + "}version", "1.5.1") + scriptElm.set("{" + inkex.NSS["jessyink"] + "}version", '1.5.5') self.document.getroot().append(scriptElm) # Remove "jessyInkInit()" in the "onload" attribute, if present. diff --git a/share/extensions/jessyInk_keyBindings.inx b/share/extensions/jessyInk_keyBindings.inx index 965079127..843957c0d 100644 --- a/share/extensions/jessyInk_keyBindings.inx +++ b/share/extensions/jessyInk_keyBindings.inx @@ -18,9 +18,10 @@ <param name="slide_addSlide" type="string" _gui-text="Add slide:">n</param> <param name="slide_toggleProgressBar" type="string" _gui-text="Toggle progress bar:">p</param> <param name="slide_resetTimer" type="string" _gui-text="Reset timer:">t</param> + <param name="slide_export" type="string" _gui-text="Export presentation:">e</param> </page> <page name="settings" _gui-text="Drawing mode"> - <param name="drawing_switchToSlideMode" type="string" _gui-text="Switch to slide mode:">d</param> + <param name="drawing_switchToSlideMode" type="string" _gui-text="Switch to slide mode:">ESCAPE, d</param> <param name="drawing_pathWidthDefault" type="string" _gui-text="Set path width to default:">0</param> <param name="drawing_pathWidth1" type="string" _gui-text="Set path width to 1:">1</param> <param name="drawing_pathWidth3" type="string" _gui-text="Set path width to 3:">3</param> diff --git a/share/extensions/jessyInk_keyBindings.py b/share/extensions/jessyInk_keyBindings.py index 45c0fe2ef..110ca3355 100755 --- a/share/extensions/jessyInk_keyBindings.py +++ b/share/extensions/jessyInk_keyBindings.py @@ -25,10 +25,12 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_CustomKeyBindings(inkex.Effect): modes = ('slide', 'index', 'drawing') - keyCodes = ('LEFT', 'RIGHT', 'DOWN', 'UP', 'HOME', 'END', 'ENTER', 'SPACE', 'PAGE_UP', 'PAGE_DOWN') + keyCodes = ('LEFT', 'RIGHT', 'DOWN', 'UP', 'HOME', 'END', 'ENTER', 'SPACE', 'PAGE_UP', 'PAGE_DOWN', 'ESCAPE') slideActions = {} slideCharCodes = {} slideKeyCodes = {} @@ -57,6 +59,7 @@ class JessyInk_CustomKeyBindings(inkex.Effect): self.OptionParser.add_option('--slide_addSlide', action = 'callback', type = 'string', callback = self.slideOptions, default = '') self.OptionParser.add_option('--slide_toggleProgressBar', action = 'callback', type = 'string', callback = self.slideOptions, default = '') self.OptionParser.add_option('--slide_resetTimer', action = 'callback', type = 'string', callback = self.slideOptions, default = '') + self.OptionParser.add_option('--slide_export', action = 'callback', type = 'string', callback = self.slideOptions, default = '') self.OptionParser.add_option('--drawing_switchToSlideMode', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') self.OptionParser.add_option('--drawing_pathWidthDefault', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') self.OptionParser.add_option('--drawing_pathWidth1', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') @@ -105,6 +108,7 @@ class JessyInk_CustomKeyBindings(inkex.Effect): self.slideActions["addSlide"] = "slideAddSlide(activeSlide);" self.slideActions["toggleProgressBar"] = "slideToggleProgressBarVisibility();" self.slideActions["resetTimer"] = "slideResetTimer();" + self.slideActions["export"] = "slideUpdateExportLayer();" self.drawingActions["switchToSlideMode"] = "drawingSwitchToSlideMode();" self.drawingActions["pathWidthDefault"] = "drawingResetPathWidth();" @@ -178,10 +182,10 @@ class JessyInk_CustomKeyBindings(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) # Remove old master slide property for node in self.document.xpath("//svg:g[@jessyink:customKeyBindings='customKeyBindings']", namespaces=inkex.NSS): diff --git a/share/extensions/jessyInk_masterSlide.py b/share/extensions/jessyInk_masterSlide.py index 9089215d9..c29922d94 100755 --- a/share/extensions/jessyInk_masterSlide.py +++ b/share/extensions/jessyInk_masterSlide.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_MasterSlide(inkex.Effect): def __init__(self): @@ -38,10 +40,10 @@ class JessyInk_MasterSlide(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) # Remove old master slide property for node in self.document.xpath("//*[@jessyink:masterSlide='masterSlide']", namespaces=inkex.NSS): @@ -51,9 +53,9 @@ class JessyInk_MasterSlide(inkex.Effect): if self.options.layerName != "": nodes = self.document.xpath("//*[@inkscape:groupmode='layer' and @inkscape:label='" + self.options.layerName + "']", namespaces=inkex.NSS) if len(nodes) == 0: - sys.stderr.write("Layer not found. Removed current master slide selection.\n") + inkex.errormsg(_("Layer not found. Removed current master slide selection.\n")) elif len(nodes) > 1: - sys.stderr.write("More than one layer with this name found. Removed current master slide selection.\n") + inkex.errormsg(_("More than one layer with this name found. Removed current master slide selection.\n")) else: nodes[0].set("{" + inkex.NSS["jessyink"] + "}masterSlide","masterSlide") diff --git a/share/extensions/jessyInk_mouseHandler.py b/share/extensions/jessyInk_mouseHandler.py index a0c06c196..4eff4c467 100755 --- a/share/extensions/jessyInk_mouseHandler.py +++ b/share/extensions/jessyInk_mouseHandler.py @@ -27,6 +27,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_CustomMouseHandler(inkex.Effect): def __init__(self): @@ -40,10 +42,10 @@ class JessyInk_CustomMouseHandler(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) # Remove old mouse handler for node in self.document.xpath("//jessyink:mousehandler", namespaces=inkex.NSS): diff --git a/share/extensions/jessyInk_summary.inx b/share/extensions/jessyInk_summary.inx index 37bc206fc..e661efd3e 100644 --- a/share/extensions/jessyInk_summary.inx +++ b/share/extensions/jessyInk_summary.inx @@ -6,7 +6,8 @@ <dependency type="executable" location="extensions">jessyInk_summary.py</dependency> <param name="tab" type="notebook"> <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to obtain information about the JessyInk script, effects and transitions contained in this SVG file. Please see code.google.com/p/jessyink for more details.</_param> + <_param name="help_text" type="description">This extension allows you to obtain information about the JessyInk script, effects and transitions contained in this SVG file. Please see code.google.com/p/jessyink for more details. + </_param> </page> </param> <effect> diff --git a/share/extensions/jessyInk_summary.py b/share/extensions/jessyInk_summary.py index 56cec0308..48478c41e 100755 --- a/share/extensions/jessyInk_summary.py +++ b/share/extensions/jessyInk_summary.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext def propStrToList(str): list = [] @@ -56,19 +58,17 @@ class JessyInk_Summary(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) # Find the script node, if present for node in self.document.xpath("//svg:script[@id='JessyInk']", namespaces=inkex.NSS): - sys.stderr.write("JessyInk script ") - if node.get("{" + inkex.NSS["jessyink"] + "}version"): - sys.stderr.write("version " + node.get("{" + inkex.NSS["jessyink"] + "}version") + " ") - - sys.stderr.write("installed.\n") + inkex.errormsg(_("JessyInk script version {0} installed.").format(node.get("{" + inkex.NSS["jessyink"] + "}version"))) + else: + inkex.errormsg(_("JessyInk script installed.")) slides = [] masterSlide = None @@ -80,50 +80,47 @@ class JessyInk_Summary(inkex.Effect): slides.append(node) if masterSlide is not None: - sys.stderr.write("\nMaster slide:\n") + inkex.errormsg(_("\nMaster slide:")) self.describeNode(masterSlide, "\t", "<the number of the slide>", str(len(slides)), "<the title of the slide>") slideCounter = 1 for slide in slides: - sys.stderr.write("\nSlide " + str(slideCounter) + ":\n") + inkex.errormsg(_("\nSlide {0!s}:").format(slideCounter)) self.describeNode(slide, "\t", str(slideCounter), str(len(slides)), slide.get("{" + inkex.NSS["inkscape"] + "}label")) slideCounter += 1 def describeNode(self, node, prefix, slideNumber, numberOfSlides, slideTitle): - sys.stderr.write(prefix + "Layer name: " + node.get("{" + inkex.NSS["inkscape"] + "}label") + "\n") + inkex.errormsg(_(u"{0}Layer name: {1}").format(prefix, node.get("{" + inkex.NSS["inkscape"] + "}label"))) # Display information about transitions. transitionInAttribute = node.get("{" + inkex.NSS["jessyink"] + "}transitionIn") if transitionInAttribute: transInDict = propListToDict(propStrToList(transitionInAttribute)) - sys.stderr.write(prefix + "Transition in: " + transInDict["name"]) if (transInDict["name"] != "appear") and transInDict.has_key("length"): - sys.stderr.write(" (" + str(int(transInDict["length"]) / 1000.0) + " s)") - - sys.stderr.write("\n") + inkex.errormsg(_("{0}Transition in: {1} ({2!s} s)").format(prefix, transInDict["name"], int(transInDict["length"]) / 1000.0)) + else: + inkex.errormsg(_("{0}Transition in: {1}").format(prefix, transInDict["name"])) transitionOutAttribute = node.get("{" + inkex.NSS["jessyink"] + "}transitionOut") if transitionOutAttribute: transOutDict = propListToDict(propStrToList(transitionOutAttribute)) - sys.stderr.write(prefix + "Transition out: " + transOutDict["name"]) if (transOutDict["name"] != "appear") and transOutDict.has_key("length"): - sys.stderr.write(" (" + str(int(transOutDict["length"]) / 1000.0) + " s)") - - sys.stderr.write("\n") + inkex.errormsg(_("{0}Transition out: {1} ({2!s} s)").format(prefix, transOutDict["name"], int(transOutDict["length"]) / 1000.0)) + else: + inkex.errormsg(_("{0}Transition out: {1}").format(prefix, transOutDict["name"])) # Display information about auto-texts. autoTexts = {"slideNumber" : slideNumber, "numberOfSlides" : numberOfSlides, "slideTitle" : slideTitle} autoTextNodes = node.xpath(".//*[@jessyink:autoText]", namespaces=inkex.NSS) if (len(autoTextNodes) > 0): - sys.stderr.write("\n" + prefix + "Auto-texts:\n") + inkex.errormsg(_("\n{0}Auto-texts:").format(prefix)) for atNode in autoTextNodes: - sys.stderr.write(prefix + "\t\"" + atNode.text + "\" (object id \"" + atNode.getparent().get("id") + "\") will be replaced by") - sys.stderr.write(" \"" + autoTexts[atNode.get("{" + inkex.NSS["jessyink"] + "}autoText")] + "\".\n") + inkex.errormsg(_("{0}\t\"{1}\" (object id \"{2}\") will be replaced by \"{3}\".").format(prefix, atNode.text, atNode.getparent().get("id"), autoTexts[atNode.get("{" + inkex.NSS["jessyink"] + "}autoText")])) # Collect information about effects. effects = {} @@ -165,29 +162,31 @@ class JessyInk_Summary(inkex.Effect): # Display information about effects. for orderItem in order: + tmpStr = "" + if orderNumber == 0: - sys.stderr.write("\n" + prefix + "Initial effect (order number " + effects[orderItem][0]["order"] + "):\n") + tmpStr += _("\n{0}Initial effect (order number {1}):").format(prefix, effects[orderItem][0]["order"]) else: - sys.stderr.write("\n" + prefix + "Effect " + str(orderNumber) + " (order number " + effects[orderItem][0]["order"] + "):\n") + tmpStr += _("\n{0}Effect {1!s} (order number {2}):").format(prefix, orderNumber, effects[orderItem][0]["order"]) for item in effects[orderItem]: if item["type"] == "view": - sys.stderr.write(prefix + "\tView will be set according to object \"" + item["id"] + "\"") + tmpStr += _("{0}\tView will be set according to object \"{1}\"").format(prefix, item["id"]) else: - sys.stderr.write(prefix + "\tObject \"" + item["id"] + "\"") + tmpStr += _("{0}\tObject \"{1}\"").format(prefix, item["id"]) if item["direction"] == "in": - sys.stderr.write(" will appear") + tmpStr += _(" will appear") elif item["direction"] == "out": - sys.stderr.write(" will disappear") + tmpStr += _(" will disappear") if item["name"] != "appear": - sys.stderr.write(" using effect \"" + item["name"] + "\"") + tmpStr += _(" using effect \"{0}\"").format(item["name"]) if item.has_key("length"): - sys.stderr.write(" in " + str(int(item["length"]) / 1000.0) + " s") + tmpStr += _(" in {0!s} s").format(int(item["length"]) / 1000.0) - sys.stderr.write(".\n") + inkex.errormsg(tmpStr + ".\n") orderNumber += 1 diff --git a/share/extensions/jessyInk_transitions.py b/share/extensions/jessyInk_transitions.py index d35477d20..18cd3f880 100755 --- a/share/extensions/jessyInk_transitions.py +++ b/share/extensions/jessyInk_transitions.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext class JessyInk_Transitions(inkex.Effect): def __init__(self): @@ -42,17 +44,17 @@ class JessyInk_Transitions(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) if self.options.layerName != "": - nodes = self.document.xpath("//*[@inkscape:groupmode='layer' and @inkscape:label='" + self.options.layerName + "']", namespaces=inkex.NSS) + nodes = self.document.xpath(unicode("//*[@inkscape:groupmode='layer' and @inkscape:label='" + self.options.layerName + "']", 'utf-8'), namespaces=inkex.NSS) if len(nodes) == 0: - sys.stderr.write("Layer not found.\n") + inkex.errormsg(_("Layer not found.\n")) elif len(nodes) > 1: - sys.stderr.write("More than one layer with this name found.\n") + inkex.errormsg(_("More than one layer with this name found.\n")) else: if self.options.effectIn == "default": if nodes[0].get("{" + inkex.NSS["jessyink"] + "}transitionIn"): @@ -65,7 +67,7 @@ class JessyInk_Transitions(inkex.Effect): else: nodes[0].set("{" + inkex.NSS["jessyink"] + "}transitionOut","name:" + self.options.effectOut + ";length:" + str(int(self.options.effectOutDuration * 1000))) else: - sys.stderr.write("Please enter a layer name.\n") + inkex.errormsg(_("Please enter a layer name.\n")) # Create effect instance effect = JessyInk_Transitions() diff --git a/share/extensions/jessyInk_video.py b/share/extensions/jessyInk_video.py index 1d4ae0ee3..51c73494b 100755 --- a/share/extensions/jessyInk_video.py +++ b/share/extensions/jessyInk_video.py @@ -29,6 +29,8 @@ import os import re from lxml import etree from copy import deepcopy +import gettext +_ = gettext.gettext class JessyInk_Effects(inkex.Effect): def __init__(self): @@ -41,20 +43,20 @@ class JessyInk_Effects(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) baseView = self.document.xpath("//sodipodi:namedview[@id='base']", namespaces=inkex.NSS) if len(baseView) != 1: - sys.stderr.write("Could not obtain the selected layer for inclusion of the video element.\n\n") + inkex.errormsg(_("Could not obtain the selected layer for inclusion of the video element.\n\n")) layer = self.document.xpath("//svg:g[@id='" + baseView[0].attrib["{" + inkex.NSS["inkscape"] + "}current-layer"] + "']", namespaces=inkex.NSS) if (len(layer) != 1): - sys.stderr.write("Could not obtain the selected layer for inclusion of the video element.\n\n") + inkex.errormsg(_("Could not obtain the selected layer for inclusion of the video element.\n\n")) # Parse template file. tmplFile = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'jessyInk_video.svg'), 'r') diff --git a/share/extensions/jessyInk_view.py b/share/extensions/jessyInk_view.py index 639cb6b47..04adc27ae 100755 --- a/share/extensions/jessyInk_view.py +++ b/share/extensions/jessyInk_view.py @@ -25,6 +25,8 @@ sys.path.append('C:\Program Files\Inkscape\share\extensions') # We will use the inkex module with the predefined Effect base class. import inkex +import gettext +_ = gettext.gettext def propStrToList(str): list = [] @@ -59,10 +61,10 @@ class JessyInk_Effects(inkex.Effect): def effect(self): # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.1']", namespaces=inkex.NSS) + scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) if len(scriptNodes) != 1: - sys.stderr.write("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Effects\" menu to install or update the JessyInk script.\n\n") + inkex.errormsg(_("The JessyInk script is not installed in this SVG file or has a different version than the JessyInk extensions. Please select \"install/update...\" from the \"JessyInk\" sub-menu of the \"Extensions\" menu to install or update the JessyInk script.\n\n")) rect = None @@ -70,11 +72,11 @@ class JessyInk_Effects(inkex.Effect): if rect == None: rect = node else: - sys.stderr.write("More than one object selected. Please select only one object.\n") + inkex.errormsg(_("More than one object selected. Please select only one object.\n")) exit() if rect == None: - sys.stderr.write("No object selected. Please select the object you want to assign a view to and then press apply.\n") + inkex.errormsg(_("No object selected. Please select the object you want to assign a view to and then press apply.\n")) exit() if not self.options.removeView: diff --git a/share/extensions/launch_webbrowser.py b/share/extensions/launch_webbrowser.py index 0deea3c8f..8de5611be 100644 --- a/share/extensions/launch_webbrowser.py +++ b/share/extensions/launch_webbrowser.py @@ -18,4 +18,4 @@ vwswli = VisitWebSiteWithoutLockingInkscape() vwswli.start() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/lindenmayer.inx b/share/extensions/lindenmayer.inx index 4cebaf3fe..6dba2d5f9 100644 --- a/share/extensions/lindenmayer.inx +++ b/share/extensions/lindenmayer.inx @@ -4,19 +4,19 @@ <id>org.ekips.filter.turtle.lindenmayer</id> <dependency type="executable" location="extensions">lindenmayer.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="rules" _gui-text="Axiom and rules"> - <param name="axiom" type="string" _gui-text="Axiom">++F</param> - <param name="rules" type="string" _gui-text="Rules">F=FF-[-F+F+F]+[+F-F-F]</param> - <param name="order" type="int" min="0" max="100" _gui-text="Order">3</param> - <param name="step" type="float" min="0.0" max="1000.0" _gui-text="Step length (px)">25.0</param> - <param name="randomizestep" type="float" min="0.0" max="100.0" _gui-text="Randomize step (%)">0.0</param> - <param name="langle" type="float" min="0.0" max="360.0" _gui-text="Left angle">16.0</param> - <param name="rangle" type="float" min="0.0" max="360.0" _gui-text="Right angle">16.0</param> - <param name="randomizeangle" type="float" min="0.0" max="100.0" _gui-text="Randomize angle (%)">0.0</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="lhelp" type="description" xml:space="preserve"> + <param name="tab" type="notebook"> + <page name="rules" _gui-text="Axiom and rules"> + <param name="axiom" type="string" _gui-text="Axiom:">++F</param> + <param name="rules" type="string" _gui-text="Rules:">F=FF-[-F+F+F]+[+F-F-F]</param> + <param name="order" type="int" min="0" max="100" _gui-text="Order:">3</param> + <param name="step" type="float" min="0.0" max="1000.0" _gui-text="Step length (px):">25.0</param> + <param name="randomizestep" type="float" min="0.0" max="100.0" _gui-text="Randomize step (%):">0.0</param> + <param name="langle" type="float" min="0.0" max="360.0" _gui-text="Left angle:">16.0</param> + <param name="rangle" type="float" min="0.0" max="360.0" _gui-text="Right angle:">16.0</param> + <param name="randomizeangle" type="float" min="0.0" max="100.0" _gui-text="Randomize angle (%):">0.0</param> + </page> + <page name="help" _gui-text="Help"> + <_param name="lhelp" type="description" xml:space="preserve"> The path is generated by applying the substitutions of Rules to the Axiom, Order times. The following commands are @@ -36,15 +36,15 @@ Any of G,H,I,J,K,L: move forward ]: return to remembered point </_param> - </page> - </param> - <effect> + </page> + </param> + <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">lindenmayer.py</command> - </script> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">lindenmayer.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/lindenmayer.py b/share/extensions/lindenmayer.py index daa002b89..f9abce3ec 100755 --- a/share/extensions/lindenmayer.py +++ b/share/extensions/lindenmayer.py @@ -116,4 +116,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/lorem_ipsum.inx b/share/extensions/lorem_ipsum.inx index b36ff079e..2833af16c 100644 --- a/share/extensions/lorem_ipsum.inx +++ b/share/extensions/lorem_ipsum.inx @@ -4,10 +4,16 @@ <id>com.kaioa.lorem_ipsum</id> <dependency type="executable" location="extensions">lorem_ipsum.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title" type="description">This effect creates the standard "Lorem Ipsum" pseudolatin placeholder text. If a flowed text is selected, Lorem Ipsum is added to it; otherwise a new flowed text object, the size of the page, is created in a new layer.</_param> - <param name="num" type="int" min="1" max="1000" _gui-text="Number of paragraphs">5</param> - <param name="sentencecount" type="int" min="2" max="100" _gui-text="Sentences per paragraph">16</param> - <param name="fluctuation" type="int" min="1" max="100" _gui-text="Paragraph length fluctuation (sentences)">4</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="num" type="int" min="1" max="1000" _gui-text="Number of paragraphs:">5</param> + <param name="sentencecount" type="int" min="2" max="100" _gui-text="Sentences per paragraph:">16</param> + <param name="fluctuation" type="int" min="1" max="100" _gui-text="Paragraph length fluctuation (sentences):">4</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="title" type="description">This effect creates the standard "Lorem Ipsum" pseudolatin placeholder text. If a flowed text is selected, Lorem Ipsum is added to it; otherwise a new flowed text object, the size of the page, is created in a new layer.</_param> + </page> + </param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/lorem_ipsum.py b/share/extensions/lorem_ipsum.py index 52d1bb190..20a2fdd18 100644 --- a/share/extensions/lorem_ipsum.py +++ b/share/extensions/lorem_ipsum.py @@ -189,6 +189,11 @@ class MyEffect(inkex.Effect): action="store", type="int", dest="fluctuation", default=4, help="+/-") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") + self.first_sentence = 1 def makePara(self): diff --git a/share/extensions/markers_strokepaint.py b/share/extensions/markers_strokepaint.py index 265b4d433..5f85d69db 100644 --- a/share/extensions/markers_strokepaint.py +++ b/share/extensions/markers_strokepaint.py @@ -78,4 +78,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/measure.inx b/share/extensions/measure.inx index af325a00e..264e33ab6 100644 --- a/share/extensions/measure.inx +++ b/share/extensions/measure.inx @@ -10,13 +10,13 @@ <_item value="length">Length</_item> <_item value="area">Area</_item> </param> - <param name="fontsize" type="int" min="1" max="1000" _gui-text="Font size [px]">12</param> - <param name="offset" type="float" min="-10000" max="10000" _gui-text="Offset [px]">-6</param> - <param name="precision" type="int" min="0" max="25" _gui-text="Precision">2</param> + <param name="fontsize" type="int" min="1" max="1000" _gui-text="Font size (px):">12</param> + <param name="offset" type="float" min="-10000" max="10000" _gui-text="Offset (px):">-6</param> + <param name="precision" type="int" min="0" max="25" _gui-text="Precision:">2</param> <param name="scale" type="float" min="1e-8" max="1e10" _gui-text="Scale Factor (Drawing:Real Length) = 1:">1</param> <!--<param name="orient" type="boolean" _gui-text="Keep text orientation upright">true</param>--> <!--<param name="unit" type="string" _gui-text="Unit {km|m|cm|mm|in|px|pt}">mm</param>--> - <param name="unit" type="enum" _gui-text="Length Unit: "> + <param name="unit" type="enum" _gui-text="Length Unit:"> <item value="px">px</item> <item value="pt">pt</item> <item value="in">in</item> diff --git a/share/extensions/measure.py b/share/extensions/measure.py index 0335f3fe9..147027fb6 100644 --- a/share/extensions/measure.py +++ b/share/extensions/measure.py @@ -198,4 +198,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/motion.inx b/share/extensions/motion.inx index effeb3937..8ffeb16ce 100644 --- a/share/extensions/motion.inx +++ b/share/extensions/motion.inx @@ -4,8 +4,8 @@ <id>org.ekips.filter.motion</id> <dependency type="executable" location="extensions">motion.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="magnitude" type="float" min="0" max="1000" _gui-text="Magnitude">100</param> - <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Angle">45</param> + <param name="magnitude" type="float" min="0" max="1000" _gui-text="Magnitude:">100</param> + <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Angle:">45</param> <effect> <object-type>path</object-type> <effects-menu> diff --git a/share/extensions/motion.py b/share/extensions/motion.py index 5e0e73731..9bf31e008 100755 --- a/share/extensions/motion.py +++ b/share/extensions/motion.py @@ -110,4 +110,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/param_curves.inx b/share/extensions/param_curves.inx index 0d21329cd..25018c5e5 100644 --- a/share/extensions/param_curves.inx +++ b/share/extensions/param_curves.inx @@ -1,29 +1,28 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Parametric Curves</_name>
- <id>org.inkscape.effect.param_curves</id>
- <dependency type="executable" location="extensions">param_curves.py</dependency>
- <dependency type="executable" location="extensions">inkex.py</dependency>
- <param name="tab" type="notebook">
- <page name="sampling" _gui-text="Range and Sampling">
- <param name="t_start" type="float" min="-1000.0" max="1000.0" _gui-text="Start t-value">0.0</param>
- <param name="t_end" type="float" min="-1000.0" max="1000.0" _gui-text="End t-value">1.0</param>
- <param name="times2pi" type="boolean" _gui-text="Multiply t-range by 2*pi">true</param>
- <param name="xleft" type="float" min="-1000.0" max="1000.0" _gui-text="x-value of rectangle's left">-1.0</param>
- <param name="xright" type="float" min="-1000.0" max="1000.0" _gui-text="x-value of rectangle's right">1.0</param>
- <param name="ybottom" type="float" min="-1000.0" max="1000.0" _gui-text="y-value of rectangle's bottom">-1.0</param>
- <param name="ytop" type="float" min="-1000.0" max="1000.0" _gui-text="y-value of rectangle's top">1.0</param>
- <param name="samples" type="int" min="2" max="1000" _gui-text="Samples">30</param>
- <param name="isoscale" type="boolean" _gui-text="Isotropic scaling (uses smallest: width/xrange or height/yrange)">false</param>
- </page>
- <page name="use" _gui-text="Use">
- <_param name="funcplotuse" type="description" xml:space="preserve">Select a rectangle before calling the extension, -it will determine X and Y scales. - -First derivatives are always determined numerically.</_param>
- </page>
- <page name="desc" _gui-text="Functions">
- <_param name="pythonfunctions" type="description" xml:space="preserve">Standard Python math functions are available: +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Parametric Curves</_name> + <id>org.inkscape.effect.param_curves</id> + <dependency type="executable" location="extensions">param_curves.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="sampling" _gui-text="Range and Sampling"> + <param name="t_start" type="float" min="-1000.0" max="1000.0" _gui-text="Start t-value:">0.0</param> + <param name="t_end" type="float" min="-1000.0" max="1000.0" _gui-text="End t-value:">1.0</param> + <param name="times2pi" type="boolean" _gui-text="Multiply t-range by 2*pi:">true</param> + <param name="xleft" type="float" min="-1000.0" max="1000.0" _gui-text="x-value of rectangle's left:">-1.0</param> + <param name="xright" type="float" min="-1000.0" max="1000.0" _gui-text="x-value of rectangle's right:">1.0</param> + <param name="ybottom" type="float" min="-1000.0" max="1000.0" _gui-text="y-value of rectangle's bottom:">-1.0</param> + <param name="ytop" type="float" min="-1000.0" max="1000.0" _gui-text="y-value of rectangle's top:">1.0</param> + <param name="samples" type="int" min="2" max="1000" _gui-text="Samples:">30</param> + <param name="isoscale" type="boolean" _gui-text="Isotropic scaling">false</param> + <_param name="isoscaledesc" type="description">When set, Isotropic scaling uses smallest of width/xrange or height/yrange</_param> + </page> + <page name="use" _gui-text="Use"> + <_param name="funcplotuse" type="description" xml:space="preserve">Select a rectangle before calling the extension, it will determine X and Y scales. +First derivatives are always determined numerically.</_param> + </page> + <page name="desc" _gui-text="Functions"> + <_param name="pythonfunctions" type="description" xml:space="preserve">Standard Python math functions are available: ceil(x); fabs(x); floor(x); fmod(x,y); frexp(x); ldexp(x,i); modf(x); exp(x); log(x [, base]); log10(x); pow(x,y); sqrt(x); @@ -31,20 +30,20 @@ acos(x); asin(x); atan(x); atan2(y,x); hypot(x,y); cos(x); sin(x); tan(x); degrees(x); radians(x); cosh(x); sinh(x); tanh(x). -The constants pi and e are also available.</_param>
- </page>
- </param>
- <param name="fofx" type="string" _gui-text="x-Function">cos(3*t)</param>
- <param name="fofy" type="string" _gui-text="y-Function">sin(5*t)</param>
- <param name="remove" type="boolean" _gui-text="Remove rectangle">true</param>
- <param name="drawaxis" type="boolean" _gui-text="Draw Axes">false</param>
- <effect>
- <object-type>rect</object-type>
- <effects-menu>
- <submenu _name="Render"/>
- </effects-menu>
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">param_curves.py</command>
- </script>
-</inkscape-extension>
+The constants pi and e are also available.</_param> + </page> + </param> + <param name="fofx" type="string" _gui-text="x-Function:">cos(3*t)</param> + <param name="fofy" type="string" _gui-text="y-Function:">sin(5*t)</param> + <param name="remove" type="boolean" _gui-text="Remove rectangle">true</param> + <param name="drawaxis" type="boolean" _gui-text="Draw Axes">false</param> + <effect> + <object-type>rect</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">param_curves.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/param_curves.py b/share/extensions/param_curves.py index 32f4b8c80..d8f880d0c 100644 --- a/share/extensions/param_curves.py +++ b/share/extensions/param_curves.py @@ -1,252 +1,252 @@ -#!/usr/bin/env python
-'''
-Copyright (C) 2009 Michel Chatelain.
-Copyright (C) 2007 Tavmjong Bah, tavmjong@free.fr
-Copyright (C) 2006 Georg Wiora, xorx@quarkbox.de
-Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl
-Copyright (C) 2005 Aaron Spike, aaron@ekips.org
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Changes:
- * This program is derived by Michel Chatelain from funcplot.py. His changes are in the Public Domain.
- * Michel Chatelain, 17-18 janvier 2009, a partir de funcplot.py
- * 20 janvier 2009 : adaptation a la version 0.46 a partir de la nouvelle version de funcplot.py
-
-'''
-
-import inkex, simplepath, simplestyle
-from math import *
-from random import *
-
-def drawfunction(t_start, t_end, xleft, xright, ybottom, ytop, samples, width, height, left, bottom,
- fx = "cos(3*t)", fy = "sin(5*t)", times2pi = False, isoscale = True, drawaxis = True):
-
- if times2pi == True:
- t_start = 2 * pi * t_start
- t_end = 2 * pi * t_end
-
- # coords and scales based on the source rect
- scalex = width / (xright - xleft)
- xoff = left
- coordx = lambda x: (x - xleft) * scalex + xoff #convert x-value to coordinate
- scaley = height / (ytop - ybottom)
- yoff = bottom
- coordy = lambda y: (ybottom - y) * scaley + yoff #convert y-value to coordinate
-
- # Check for isotropic scaling and use smaller of the two scales, correct ranges
- if isoscale:
- if scaley<scalex:
- # compute zero location
- xzero = coordx(0)
- # set scale
- scalex = scaley
- # correct x-offset
- xleft = (left-xzero)/scalex
- xright = (left+width-xzero)/scalex
- else :
- # compute zero location
- yzero = coordy(0)
- # set scale
- scaley = scalex
- # correct x-offset
- ybottom = (yzero-bottom)/scaley
- ytop = (bottom+height-yzero)/scaley
-
- # functions specified by the user
- if fx != "":
- f1 = eval('lambda t: ' + fx.strip('"'))
- if fy != "":
- f2 = eval('lambda t: ' + fy.strip('"'))
-
- # step is increment of t
- step = (t_end - t_start) / (samples-1)
- third = step / 3.0
- ds = step * 0.001 # Step used in calculating derivatives
-
- a = [] # path array
- # add axis
- if drawaxis :
- # check for visibility of x-axis
- if ybottom<=0 and ytop>=0:
- # xaxis
- a.append(['M ',[left, coordy(0)]])
- a.append([' l ',[width, 0]])
- # check for visibility of y-axis
- if xleft<=0 and xright>=0:
- # xaxis
- a.append([' M ',[coordx(0),bottom]])
- a.append([' l ',[0, -height]])
-
- # initialize functions and derivatives for 0;
- # they are carried over from one iteration to the next, to avoid extra function calculations.
- x0 = f1(t_start)
- y0 = f2(t_start)
-
- # numerical derivatives, using 0.001*step as the small differential
- t1 = t_start + ds # Second point AFTER first point (Good for first point)
- x1 = f1(t1)
- y1 = f2(t1)
- dx0 = (x1 - x0)/ds
- dy0 = (y1 - y0)/ds
-
- # Start curve
- a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto
- for i in range(int(samples-1)):
- t1 = (i+1) * step + t_start
- t2 = t1 - ds # Second point BEFORE first point (Good for last point)
- x1 = f1(t1)
- x2 = f1(t2)
- y1 = f2(t1)
- y2 = f2(t2)
-
- # numerical derivatives
- dx1 = (x1 - x2)/ds
- dy1 = (y1 - y2)/ds
-
- # create curve
- a.append([' C ',
- [coordx(x0 + (dx0 * third)), coordy(y0 + (dy0 * third)),
- coordx(x1 - (dx1 * third)), coordy(y1 - (dy1 * third)),
- coordx(x1), coordy(y1)]
- ])
- t0 = t1 # Next segment's start is this segments end
- x0 = x1
- y0 = y1
- dx0 = dx1 # Assume the functions are smooth everywhere, so carry over the derivatives too
- dy0 = dy1
- return a
-
-class ParamCurves(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("--t_start",
- action="store", type="float",
- dest="t_start", default=0.0,
- help="Start t-value")
- self.OptionParser.add_option("--t_end",
- action="store", type="float",
- dest="t_end", default=1.0,
- help="End t-value")
- self.OptionParser.add_option("--times2pi",
- action="store", type="inkbool",
- dest="times2pi", default=True,
- help="Multiply t-range by 2*pi")
- self.OptionParser.add_option("--xleft",
- action="store", type="float",
- dest="xleft", default=-1.0,
- help="x-value of rectangle's left")
- self.OptionParser.add_option("--xright",
- action="store", type="float",
- dest="xright", default=1.0,
- help="x-value of rectangle's right")
- self.OptionParser.add_option("--ybottom",
- action="store", type="float",
- dest="ybottom", default=-1.0,
- help="y-value of rectangle's bottom")
- self.OptionParser.add_option("--ytop",
- action="store", type="float",
- dest="ytop", default=1.0,
- help="y-value of rectangle's top")
- self.OptionParser.add_option("-s", "--samples",
- action="store", type="int",
- dest="samples", default=8,
- help="Samples")
- self.OptionParser.add_option("--fofx",
- action="store", type="string",
- dest="fofx", default="cos(3*t)",
- help="fx(t) for plotting")
- self.OptionParser.add_option("--fofy",
- action="store", type="string",
- dest="fofy", default="sin(5*t)",
- help="fy(t) for plotting")
- self.OptionParser.add_option("--remove",
- action="store", type="inkbool",
- dest="remove", default=True,
- help="If True, source rectangle is removed")
- self.OptionParser.add_option("--isoscale",
- action="store", type="inkbool",
- dest="isoscale", default=True,
- help="If True, isotropic scaling is used")
- self.OptionParser.add_option("--drawaxis",
- action="store", type="inkbool",
- dest="drawaxis", default=True,
- help="If True, axis are drawn")
- self.OptionParser.add_option("--tab",
- action="store", type="string",
- dest="tab", default="sampling",
- help="The selected UI-tab when OK was pressed")
- self.OptionParser.add_option("--paramcurvesuse",
- action="store", type="string",
- dest="paramcurvesuse", default="",
- help="dummy")
- self.OptionParser.add_option("--pythonfunctions",
- action="store", type="string",
- dest="pythonfunctions", default="",
- help="dummy")
-
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tag == inkex.addNS('rect','svg'):
- # create new path with basic dimensions of selected rectangle
- newpath = inkex.etree.Element(inkex.addNS('path','svg'))
- x = float(node.get('x'))
- y = float(node.get('y'))
- w = float(node.get('width'))
- h = float(node.get('height'))
-
- #copy attributes of rect
- s = node.get('style')
- if s:
- newpath.set('style', s)
-
- t = node.get('transform')
- if t:
- newpath.set('transform', t)
-
- # top and bottom were exchanged
- newpath.set('d', simplepath.formatPath(
- drawfunction(self.options.t_start,
- self.options.t_end,
- self.options.xleft,
- self.options.xright,
- self.options.ybottom,
- self.options.ytop,
- self.options.samples,
- w,h,x,y+h,
- self.options.fofx,
- self.options.fofy,
- self.options.times2pi,
- self.options.isoscale,
- self.options.drawaxis)))
- newpath.set('title', self.options.fofx + " " + self.options.fofy)
-
- #newpath.set('desc', '!func;' + self.options.fofx + ';' + self.options.fofy + ';'
- # + `self.options.t_start` + ';'
- # + `self.options.t_end` + ';'
- # + `self.options.samples`)
-
- # add path into SVG structure
- node.getparent().append(newpath)
- # option wether to remove the rectangle or not.
- if self.options.remove:
- node.getparent().remove(node)
-
-if __name__ == '__main__':
- e = ParamCurves()
- e.affect()
-
-
-# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
+#!/usr/bin/env python +''' +Copyright (C) 2009 Michel Chatelain. +Copyright (C) 2007 Tavmjong Bah, tavmjong@free.fr +Copyright (C) 2006 Georg Wiora, xorx@quarkbox.de +Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl +Copyright (C) 2005 Aaron Spike, aaron@ekips.org + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Changes: + * This program is derived by Michel Chatelain from funcplot.py. His changes are in the Public Domain. + * Michel Chatelain, 17-18 janvier 2009, a partir de funcplot.py + * 20 janvier 2009 : adaptation a la version 0.46 a partir de la nouvelle version de funcplot.py + +''' + +import inkex, simplepath, simplestyle +from math import * +from random import * + +def drawfunction(t_start, t_end, xleft, xright, ybottom, ytop, samples, width, height, left, bottom, + fx = "cos(3*t)", fy = "sin(5*t)", times2pi = False, isoscale = True, drawaxis = True): + + if times2pi == True: + t_start = 2 * pi * t_start + t_end = 2 * pi * t_end + + # coords and scales based on the source rect + scalex = width / (xright - xleft) + xoff = left + coordx = lambda x: (x - xleft) * scalex + xoff #convert x-value to coordinate + scaley = height / (ytop - ybottom) + yoff = bottom + coordy = lambda y: (ybottom - y) * scaley + yoff #convert y-value to coordinate + + # Check for isotropic scaling and use smaller of the two scales, correct ranges + if isoscale: + if scaley<scalex: + # compute zero location + xzero = coordx(0) + # set scale + scalex = scaley + # correct x-offset + xleft = (left-xzero)/scalex + xright = (left+width-xzero)/scalex + else : + # compute zero location + yzero = coordy(0) + # set scale + scaley = scalex + # correct x-offset + ybottom = (yzero-bottom)/scaley + ytop = (bottom+height-yzero)/scaley + + # functions specified by the user + if fx != "": + f1 = eval('lambda t: ' + fx.strip('"')) + if fy != "": + f2 = eval('lambda t: ' + fy.strip('"')) + + # step is increment of t + step = (t_end - t_start) / (samples-1) + third = step / 3.0 + ds = step * 0.001 # Step used in calculating derivatives + + a = [] # path array + # add axis + if drawaxis : + # check for visibility of x-axis + if ybottom<=0 and ytop>=0: + # xaxis + a.append(['M ',[left, coordy(0)]]) + a.append([' l ',[width, 0]]) + # check for visibility of y-axis + if xleft<=0 and xright>=0: + # xaxis + a.append([' M ',[coordx(0),bottom]]) + a.append([' l ',[0, -height]]) + + # initialize functions and derivatives for 0; + # they are carried over from one iteration to the next, to avoid extra function calculations. + x0 = f1(t_start) + y0 = f2(t_start) + + # numerical derivatives, using 0.001*step as the small differential + t1 = t_start + ds # Second point AFTER first point (Good for first point) + x1 = f1(t1) + y1 = f2(t1) + dx0 = (x1 - x0)/ds + dy0 = (y1 - y0)/ds + + # Start curve + a.append([' M ',[coordx(x0), coordy(y0)]]) # initial moveto + for i in range(int(samples-1)): + t1 = (i+1) * step + t_start + t2 = t1 - ds # Second point BEFORE first point (Good for last point) + x1 = f1(t1) + x2 = f1(t2) + y1 = f2(t1) + y2 = f2(t2) + + # numerical derivatives + dx1 = (x1 - x2)/ds + dy1 = (y1 - y2)/ds + + # create curve + a.append([' C ', + [coordx(x0 + (dx0 * third)), coordy(y0 + (dy0 * third)), + coordx(x1 - (dx1 * third)), coordy(y1 - (dy1 * third)), + coordx(x1), coordy(y1)] + ]) + t0 = t1 # Next segment's start is this segments end + x0 = x1 + y0 = y1 + dx0 = dx1 # Assume the functions are smooth everywhere, so carry over the derivatives too + dy0 = dy1 + return a + +class ParamCurves(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--t_start", + action="store", type="float", + dest="t_start", default=0.0, + help="Start t-value") + self.OptionParser.add_option("--t_end", + action="store", type="float", + dest="t_end", default=1.0, + help="End t-value") + self.OptionParser.add_option("--times2pi", + action="store", type="inkbool", + dest="times2pi", default=True, + help="Multiply t-range by 2*pi") + self.OptionParser.add_option("--xleft", + action="store", type="float", + dest="xleft", default=-1.0, + help="x-value of rectangle's left") + self.OptionParser.add_option("--xright", + action="store", type="float", + dest="xright", default=1.0, + help="x-value of rectangle's right") + self.OptionParser.add_option("--ybottom", + action="store", type="float", + dest="ybottom", default=-1.0, + help="y-value of rectangle's bottom") + self.OptionParser.add_option("--ytop", + action="store", type="float", + dest="ytop", default=1.0, + help="y-value of rectangle's top") + self.OptionParser.add_option("-s", "--samples", + action="store", type="int", + dest="samples", default=8, + help="Samples") + self.OptionParser.add_option("--fofx", + action="store", type="string", + dest="fofx", default="cos(3*t)", + help="fx(t) for plotting") + self.OptionParser.add_option("--fofy", + action="store", type="string", + dest="fofy", default="sin(5*t)", + help="fy(t) for plotting") + self.OptionParser.add_option("--remove", + action="store", type="inkbool", + dest="remove", default=True, + help="If True, source rectangle is removed") + self.OptionParser.add_option("--isoscale", + action="store", type="inkbool", + dest="isoscale", default=True, + help="If True, isotropic scaling is used") + self.OptionParser.add_option("--drawaxis", + action="store", type="inkbool", + dest="drawaxis", default=True, + help="If True, axis are drawn") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", default="sampling", + help="The selected UI-tab when OK was pressed") + self.OptionParser.add_option("--paramcurvesuse", + action="store", type="string", + dest="paramcurvesuse", default="", + help="dummy") + self.OptionParser.add_option("--pythonfunctions", + action="store", type="string", + dest="pythonfunctions", default="", + help="dummy") + + def effect(self): + for id, node in self.selected.iteritems(): + if node.tag == inkex.addNS('rect','svg'): + # create new path with basic dimensions of selected rectangle + newpath = inkex.etree.Element(inkex.addNS('path','svg')) + x = float(node.get('x')) + y = float(node.get('y')) + w = float(node.get('width')) + h = float(node.get('height')) + + #copy attributes of rect + s = node.get('style') + if s: + newpath.set('style', s) + + t = node.get('transform') + if t: + newpath.set('transform', t) + + # top and bottom were exchanged + newpath.set('d', simplepath.formatPath( + drawfunction(self.options.t_start, + self.options.t_end, + self.options.xleft, + self.options.xright, + self.options.ybottom, + self.options.ytop, + self.options.samples, + w,h,x,y+h, + self.options.fofx, + self.options.fofy, + self.options.times2pi, + self.options.isoscale, + self.options.drawaxis))) + newpath.set('title', self.options.fofx + " " + self.options.fofy) + + #newpath.set('desc', '!func;' + self.options.fofx + ';' + self.options.fofy + ';' + # + `self.options.t_start` + ';' + # + `self.options.t_end` + ';' + # + `self.options.samples`) + + # add path into SVG structure + node.getparent().append(newpath) + # option wether to remove the rectangle or not. + if self.options.remove: + node.getparent().remove(node) + +if __name__ == '__main__': + e = ParamCurves() + e.affect() + + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/pathalongpath.inx b/share/extensions/pathalongpath.inx index a4ee40852..b555b9445 100644 --- a/share/extensions/pathalongpath.inx +++ b/share/extensions/pathalongpath.inx @@ -1,33 +1,39 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Pattern along Path</_name> - <id>math.univ-lille1.barraud.pathdeform</id> - <dependency type="executable" location="extensions">pathmodifier.py</dependency> - <dependency type="executable" location="extensions">pathalongpath.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title" type="description">This effect bends a pattern object along arbitrary "skeleton" paths. The pattern is the topmost object in the selection. (groups of paths/shapes/clones... allowed)</_param> - <param name="copymode" type="enum" _gui-text="Copies of the pattern:"> - <_item value="Single">Single</_item> - <_item value="Single, stretched">Single, stretched</_item> - <_item value="Repeated">Repeated</_item> - <_item value="Repeated, stretched">Repeated, stretched</_item> - </param> - <param name="kind" type="enum" _gui-text="Deformation type:"> - <_item value="Snake">Snake</_item> - <_item value="Ribbon">Ribbon</_item> - </param> - <param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0">0.0</param> - <param name="noffset" type="float" _gui-text="Normal offset" min="-10000.0" max="10000.0">0.0</param> - <param name="toffset" type="float" _gui-text="Tangential offset" min="-10000.0" max="10000.0">0.0</param> - <param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param> - <param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param> - <effect> + <_name>Pattern along Path</_name> + <id>math.univ-lille1.barraud.pathdeform</id> + <dependency type="executable" location="extensions">pathmodifier.py</dependency> + <dependency type="executable" location="extensions">pathalongpath.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="copymode" type="enum" _gui-text="Copies of the pattern:"> + <_item value="Single">Single</_item> + <_item value="Single, stretched">Single, stretched</_item> + <_item value="Repeated">Repeated</_item> + <_item value="Repeated, stretched">Repeated, stretched</_item> + </param> + <param name="kind" type="enum" _gui-text="Deformation type:"> + <_item value="Snake">Snake</_item> + <_item value="Ribbon">Ribbon</_item> + </param> + <param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0">0.0</param> + <param name="noffset" type="float" _gui-text="Normal offset:" min="-10000.0" max="10000.0">0.0</param> + <param name="toffset" type="float" _gui-text="Tangential offset:" min="-10000.0" max="10000.0">0.0</param> + <param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param> + <param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="title" type="description">This effect bends a pattern object along arbitrary "skeleton" paths. The pattern is the topmost object in the selection (groups of paths/shapes/clones... allowed).</_param> + </page> + </param> + <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">pathalongpath.py</command> - </script> + <effects-menu> + <submenu _name="Generate from Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">pathalongpath.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/pathalongpath.py b/share/extensions/pathalongpath.py index f8a8a2c32..7a2fa09ea 100644 --- a/share/extensions/pathalongpath.py +++ b/share/extensions/pathalongpath.py @@ -117,6 +117,10 @@ class PathAlongPath(pathmodifier.Diffeo): action="store", type="inkbool", dest="duplicate", default=False, help="duplicate pattern before deformation") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def prepareSelectionList(self): @@ -216,9 +220,11 @@ class PathAlongPath(pathmodifier.Diffeo): if self.options.vertical: #flipxy(bbox)... bbox=(-bbox[3],-bbox[2],-bbox[1],-bbox[0]) - + width=bbox[1]-bbox[0] dx=width+self.options.space + if dx < 0.01: + exit(_("The total length of the pattern is too small :\nPlease choose a larger object or set 'Space between copies' > 0")) for id, node in self.patterns.iteritems(): if node.tag == inkex.addNS('path','svg') or node.tag=='path': @@ -278,4 +284,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/pathmodifier.py b/share/extensions/pathmodifier.py index 128c1b754..ceb0994e6 100644 --- a/share/extensions/pathmodifier.py +++ b/share/extensions/pathmodifier.py @@ -307,4 +307,4 @@ class Diffeo(PathModifier): #e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/pathscatter.inx b/share/extensions/pathscatter.inx index 8f45aa75a..02d00a3ca 100644 --- a/share/extensions/pathscatter.inx +++ b/share/extensions/pathscatter.inx @@ -1,30 +1,41 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Scatter</_name> - <id>math.univ-lille1.barraud.pathScatter</id> - <dependency type="executable" location="extensions">pathmodifier.py</dependency> - <dependency type="executable" location="extensions">pathscatter.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title" type="description">This effect scatters a pattern along arbitrary "skeleton" paths. The pattern must be the topmost object in the selection. Groups of paths, shapes, clones are allowed.</_param> - <param name="follow" type="boolean" _gui-text="Follow path orientation">false</param> - <param name="stretch" type="boolean" _gui-text="Stretch spaces to fit skeleton length">false</param> - <param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0">0.0</param> - <param name="noffset" type="float" _gui-text="Normal offset" min="-10000.0" max="10000.0">0.0</param> - <param name="toffset" type="float" _gui-text="Tangential offset" min="-10000.0" max="10000.0">0.0</param> - <param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param> - <param name="copymode" type="optiongroup" _gui-text="Original pattern will be:"> - <_option value="move">Moved</_option> - <_option value="copy">Copied</_option> - <_option value="clone">Cloned</_option> - </param> - <param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">pathscatter.py</command> - </script> + <_name>Scatter</_name> + <id>math.univ-lille1.barraud.pathScatter</id> + <dependency type="executable" location="extensions">pathmodifier.py</dependency> + <dependency type="executable" location="extensions">pathscatter.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="follow" type="boolean" _gui-text="Follow path orientation">false</param> + <param name="stretch" type="boolean" _gui-text="Stretch spaces to fit skeleton length">false</param> + <param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0">0.0</param> + <param name="noffset" type="float" _gui-text="Normal offset:" min="-10000.0" max="10000.0">0.0</param> + <param name="toffset" type="float" _gui-text="Tangential offset:" min="-10000.0" max="10000.0">0.0</param> + <param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param> + <param name="copymode" type="enum" _gui-text="Original pattern will be:"> + <_item value="move">Moved</_item> + <_item value="copy">Copied</_item> + <_item value="clone">Cloned</_item> + </param> + <param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param> + <param name="grouppick" type="boolean" _gui-text="If pattern is a group, pick group members">false</param> + <param name="pickmode" type="enum" _gui-text="Pick group members:"> + <_item value="rand">Randomly</_item> + <_item value="seq">Sequentially</_item> + </param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="title" type="description">This effect scatters a pattern along arbitrary "skeleton" paths. The pattern must be the topmost object in the selection. Groups of paths, shapes, clones are allowed.</_param> + </page> + </param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Generate from Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">pathscatter.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/pathscatter.py b/share/extensions/pathscatter.py index 03da822c5..6ed3cc8ac 100644 --- a/share/extensions/pathscatter.py +++ b/share/extensions/pathscatter.py @@ -111,6 +111,14 @@ class PathScatter(pathmodifier.Diffeo): self.OptionParser.add_option("-t", "--toffset", action="store", type="float", dest="toffset", default=0.0, help="tangential offset") + self.OptionParser.add_option("-g", "--grouppick", + action="store", type="inkbool", + dest="grouppick", default=False, + help="if pattern is a group then randomly pick group members") + self.OptionParser.add_option("-m", "--pickmode", + action="store", type="string", + dest="pickmode", default="rand", + help="group pick mode (rand=random seq=sequentially)") self.OptionParser.add_option("-f", "--follow", action="store", type="inkbool", dest="follow", default=True, @@ -134,6 +142,10 @@ class PathScatter(pathmodifier.Diffeo): action="store", type="string", dest="copymode", default="clone", help="duplicate pattern before deformation") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def prepareSelectionList(self): @@ -144,7 +156,7 @@ class PathScatter(pathmodifier.Diffeo): #id = self.options.ids[-1] id = idList[-1] self.patternNode=self.selected[id] - + self.gNode = etree.Element('{http://www.w3.org/2000/svg}g') self.patternNode.getparent().append(self.gNode) @@ -208,7 +220,7 @@ class PathScatter(pathmodifier.Diffeo): inkex.errormsg(_("This extension requires two selected paths.")) return self.prepareSelectionList() - + #center at (0,0) bbox=pathmodifier.computeBBox([self.patternNode]) mat=[[1,0,-(bbox[0]+bbox[1])/2],[0,1,-(bbox[2]+bbox[3])/2]] @@ -221,6 +233,18 @@ class PathScatter(pathmodifier.Diffeo): width=bbox[1]-bbox[0] dx=width+self.options.space + #check if group and expand it + patternList = [] + if self.options.grouppick and (self.patternNode.tag == inkex.addNS('g','svg') or self.patternNode.tag=='g') : + mat=simpletransform.parseTransform(self.patternNode.get("transform")) + for child in self.patternNode: + simpletransform.applyTransformToNode(mat,child) + patternList.append(child) + else : + patternList.append(self.patternNode) + #inkex.debug(patternList) + + counter=0 for skelnode in self.skeletons.itervalues(): self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) for comp in self.curSekeleton: @@ -242,11 +266,16 @@ class PathScatter(pathmodifier.Diffeo): s=self.options.toffset while s<=length: mat=self.localTransformAt(s,self.options.follow) + if self.options.pickmode=="rand": + clone=copy.deepcopy(patternList[random.randint(0, len(patternList)-1)]) - clone=copy.deepcopy(self.patternNode) + if self.options.pickmode=="seq": + clone=copy.deepcopy(patternList[counter]) + counter=(counter+1)%len(patternList) + #!!!--> should it be given an id? #seems to work without this!?! - myid = self.patternNode.tag.split('}')[-1] + myid = patternList[random.randint(0, len(patternList)-1)].tag.split('}')[-1] clone.set("id", self.uniqueId(myid)) self.gNode.append(clone) @@ -260,4 +289,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/perfectboundcover.inx b/share/extensions/perfectboundcover.inx index 15886a632..4cbe27a7f 100644 --- a/share/extensions/perfectboundcover.inx +++ b/share/extensions/perfectboundcover.inx @@ -1,41 +1,41 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Perfect-Bound Cover Template</_name> - <id>org.coswellproductions.inkscape.effects.perfectboundcover</id> - <dependency type="executable" location="extensions">perfectboundcover.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="book" type="description">Book Properties</_param> - <param name="width" precision="3" type="float" min="0.0" max="100.000" _gui-text="Book Width (inches)">6</param> - <param name="height" precision="3" type="float" min="0.0" max="100.000" _gui-text="Book Height (inches)">9</param> - <param name="pages" type="int" min="4" max="6000" _gui-text="Number of Pages">64</param> - <param name="removeguides" type="boolean" _gui-text="Remove existing guides">true</param> - <_param name="paper" type="description">Interior Pages</_param> - <param name="paperthicknessmeasurement" _gui-text="Paper Thickness Measurement" type="optiongroup" appearance="minimal"> - <_option value="ppi">Pages Per Inch (PPI)</_option> - <_option value="caliper">Caliper (inches)</_option> - <_option value="points">Points</_option> - <_option value="bond_weight">Bond Weight #</_option> - <_option value="width">Specify Width</_option> - </param> - <param precision="4" name="paperthickness" type="float" min="0.000" max="1000.000" _gui-text="Value">0</param> - <_param name="cover" type="description">Cover</_param> - <param name="coverthicknessmeasurement" _gui-text="Cover Thickness Measurement" type="optiongroup" appearance="minimal"> - <_option value="ppi">Pages Per Inch (PPI)</_option> - <_option value="caliper">Caliper (inches)</_option> - <_option value="points">Points</_option> - <_option value="bond_weight">Bond Weight #</_option> - <_option value="width">Specify Width</_option> - </param> - <param precision="4" name="coverthickness" type="float" min="0.000" max="1000.000" _gui-text="Value">0</param> - <param precision="3" name="bleed" type="float" min="0.000" max="1.000" _gui-text="Bleed (in)">.25</param> - <_param name="warning" type="description">Note: Bond Weight # calculations are a best-guess estimate.</_param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> + <_name>Perfect-Bound Cover Template</_name> + <id>org.coswellproductions.inkscape.effects.perfectboundcover</id> + <dependency type="executable" location="extensions">perfectboundcover.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <_param name="book" type="groupheader">Book Properties</_param> + <param name="width" precision="3" type="float" min="0.0" max="100.000" _gui-text="Book Width (inches):">6</param> + <param name="height" precision="3" type="float" min="0.0" max="100.000" _gui-text="Book Height (inches):">9</param> + <param name="pages" type="int" min="4" max="6000" _gui-text="Number of Pages:">64</param> + <param name="removeguides" type="boolean" _gui-text="Remove existing guides">true</param> + <_param name="paper" type="groupheader">Interior Pages</_param> + <param name="paperthicknessmeasurement" _gui-text="Paper Thickness Measurement:" type="enum"> + <_item value="ppi">Pages Per Inch (PPI)</_item> + <_item value="caliper">Caliper (inches)</_item> + <_item value="points">Points</_item> + <_item value="bond_weight">Bond Weight #</_item> + <_item value="width">Specify Width</_item> + </param> + <param precision="4" name="paperthickness" type="float" min="0.000" max="1000.000" _gui-text="Value:">0</param> + <_param name="cover" type="groupheader">Cover</_param> + <param name="coverthicknessmeasurement" _gui-text="Cover Thickness Measurement:" type="enum"> + <_item value="ppi">Pages Per Inch (PPI)</_item> + <_item value="caliper">Caliper (inches)</_item> + <_item value="points">Points</_item> + <_item value="bond_weight">Bond Weight #</_item> + <_item value="width">Specify Width</_item> + </param> + <param precision="4" name="coverthickness" type="float" min="0.000" max="1000.000" _gui-text="Value:">0</param> + <param precision="3" name="bleed" type="float" min="0.000" max="1.000" _gui-text="Bleed (in):">.25</param> + <_param name="warning" type="description">Note: Bond Weight # calculations are a best-guess estimate.</_param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> <command reldir="extensions" interpreter="python">perfectboundcover.py</command> - </script> + </script> </inkscape-extension> diff --git a/share/extensions/perfectboundcover.py b/share/extensions/perfectboundcover.py index 694040434..6cdab7eab 100644 --- a/share/extensions/perfectboundcover.py +++ b/share/extensions/perfectboundcover.py @@ -169,4 +169,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/perspective.py b/share/extensions/perspective.py index ae47cacfb..4caaa68a1 100755 --- a/share/extensions/perspective.py +++ b/share/extensions/perspective.py @@ -158,4 +158,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/pixelsnap.inx b/share/extensions/pixelsnap.inx index c46fb36f6..65ce401be 100644 --- a/share/extensions/pixelsnap.inx +++ b/share/extensions/pixelsnap.inx @@ -3,7 +3,7 @@ <_name>PixelSnap</_name> <id>bryhoyt.pixelsnap</id> <dependency type="executable" location="extensions">pixelsnap.py</dependency> - <_param name="title" type="description">Snap all paths in selection to pixels. Snaps borders to half-points and fills to full points</_param> + <_param name="title" type="description">Snap all paths in selection to pixels. Snaps borders to half-points and fills to full points.</_param> <effect> <effects-menu> <submenu _name="Modify Path"/> diff --git a/share/extensions/plt_output.py b/share/extensions/plt_output.py index 86a674f23..49ac1f604 100644 --- a/share/extensions/plt_output.py +++ b/share/extensions/plt_output.py @@ -27,4 +27,4 @@ from uniconv_output import run, get_command cmd = get_command() run((cmd + ' "%s" ') % sys.argv[1], "UniConvertor", ".plt") -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
\ No newline at end of file +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
\ No newline at end of file diff --git a/share/extensions/polyhedron_3d.inx b/share/extensions/polyhedron_3d.inx index 10a054f8a..0ded2848d 100644 --- a/share/extensions/polyhedron_3d.inx +++ b/share/extensions/polyhedron_3d.inx @@ -6,29 +6,29 @@ <dependency type="executable" location="extensions">inkex.py</dependency> <param name="tab" type="notebook"> <page name="common" _gui-text="Model file"> - <param name="obj" type="optiongroup" appearance="minimal" _gui-text="Object:"> - <_option value="cube">Cube</_option> - <_option value="trunc_cube">Truncated Cube</_option> - <_option value="snub_cube">Snub Cube</_option> - <_option value="cuboct">Cuboctahedron</_option> - <_option value="tet">Tetrahedron</_option> - <_option value="trunc_tet">Truncated Tetrahedron</_option> - <_option value="oct">Octahedron</_option> - <_option value="trunc_oct">Truncated Octahedron</_option> - <_option value="icos">Icosahedron</_option> - <_option value="trunc_icos">Truncated Icosahedron</_option> - <_option value="small_triam_icos">Small Triambic Icosahedron</_option> - <_option value="dodec">Dodecahedron</_option> - <_option value="trunc_dodec">Truncated Dodecahedron</_option> - <_option value="snub_dodec">Snub Dodecahedron</_option> - <_option value="great_dodec">Great Dodecahedron</_option> - <_option value="great_stel_dodec">Great Stellated Dodecahedron</_option> - <_option value="from_file">Load from file</_option> + <param name="obj" type="enum" _gui-text="Object:"> + <_item value="cube">Cube</_item> + <_item value="trunc_cube">Truncated Cube</_item> + <_item value="snub_cube">Snub Cube</_item> + <_item value="cuboct">Cuboctahedron</_item> + <_item value="tet">Tetrahedron</_item> + <_item value="trunc_tet">Truncated Tetrahedron</_item> + <_item value="oct">Octahedron</_item> + <_item value="trunc_oct">Truncated Octahedron</_item> + <_item value="icos">Icosahedron</_item> + <_item value="trunc_icos">Truncated Icosahedron</_item> + <_item value="small_triam_icos">Small Triambic Icosahedron</_item> + <_item value="dodec">Dodecahedron</_item> + <_item value="trunc_dodec">Truncated Dodecahedron</_item> + <_item value="snub_dodec">Snub Dodecahedron</_item> + <_item value="great_dodec">Great Dodecahedron</_item> + <_item value="great_stel_dodec">Great Stellated Dodecahedron</_item> + <_item value="from_file">Load from file</_item> </param> - <param name="spec_file" type="string" _gui-text="Filename:">great_rhombicuboct.obj</param> - <param name="type" type="optiongroup" appearance="minimal" _gui-text="Object Type"> - <_option value="face">Face-Specified</_option> - <_option value="edge">Edge-Specified</_option></param> + <param name="spec_file" type="string" _gui-text="Filename:">great_rhombicuboct.obj</param> + <param name="type" type="enum" _gui-text="Object Type:"> + <_item value="face">Face-Specified</_item> + <_item value="edge">Edge-Specified</_item></param> <param name="cw_wound" type="boolean" _gui-text="Clockwise wound object">0</param> </page> <page name="view" _gui-text="View"> @@ -36,61 +36,62 @@ <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r1_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r1_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> <param name="r2_ax" type="optiongroup" appearance="minimal" _gui-text="Then rotate around:"> <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r2_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r2_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> <param name="r3_ax" type="optiongroup" appearance="minimal" _gui-text="Then rotate around:"> <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r3_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r3_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> <param name="r4_ax" type="optiongroup" appearance="minimal" _gui-text="Then rotate around:"> <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r4_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r4_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> <param name="r5_ax" type="optiongroup" appearance="minimal" _gui-text="Then rotate around:"> <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r5_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r5_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> <param name="r6_ax" type="optiongroup" appearance="minimal" _gui-text="Then rotate around:"> <_option value="x">X-Axis</_option> <_option value="y">Y-Axis</_option> <_option value="z">Z-Axis</_option></param> - <param name="r6_ang" type="float" min="-360" max="360" _gui-text="Rotation, degrees">0</param> + <param name="r6_ang" type="float" min="-360" max="360" _gui-text="Rotation (deg):">0</param> </page> <page name="style" _gui-text="Style"> - <param name="scl" type="float" min="0" max="10000" _gui-text="Scaling factor">100</param> - <param name="f_r" type="int" min="0" max="255" _gui-text="Fill color, Red">255</param> - <param name="f_g" type="int" min="0" max="255" _gui-text="Fill color, Green">0</param> - <param name="f_b" type="int" min="0" max="255" _gui-text="Fill color, Blue">0</param> - <param name="f_opac" type="int" min="0" max="100" _gui-text="Fill opacity, %">100</param> - <param name="s_opac" type="int" min="0" max="100" _gui-text="Stroke opacity, %">100</param> - <param name="th" type="float" min="0" max="100" _gui-text="Stroke width, px">2</param> - <param name="shade" type="boolean" _gui-text="Shading">1</param> - <param name="lv_x" type="float" min="-100" max="100" _gui-text="Light X">1</param> - <param name="lv_y" type="float" min="-100" max="100" _gui-text="Light Y">1</param> - <param name="lv_z" type="float" min="-100" max="100" _gui-text="Light Z">-2</param> - <param name="show" type="optiongroup" appearance="minimal" _gui-text="Show:"> - <_option value="fce">Faces</_option></param> - <_option value="edg">Edges</_option> - <_option value="vtx">Vertices</_option> + <param name="scl" type="float" min="0" max="10000" _gui-text="Scaling factor:">100</param> + <param name="f_r" type="int" min="0" max="255" _gui-text="Fill color, Red:">255</param> + <param name="f_g" type="int" min="0" max="255" _gui-text="Fill color, Green:">0</param> + <param name="f_b" type="int" min="0" max="255" _gui-text="Fill color, Blue:">0</param> + <param name="f_opac" type="int" min="0" max="100" _gui-text="Fill opacity (%):">100</param> + <param name="s_opac" type="int" min="0" max="100" _gui-text="Stroke opacity (%):">100</param> + <param name="th" type="float" min="0" max="100" _gui-text="Stroke width (px):">2</param> + <param name="shade" type="boolean" _gui-text="Shading">1</param> + <param name="lv_x" type="float" min="-100" max="100" _gui-text="Light X:">1</param> + <param name="lv_y" type="float" min="-100" max="100" _gui-text="Light Y:">1</param> + <param name="lv_z" type="float" min="-100" max="100" _gui-text="Light Z:">-2</param> + <param name="show" type="enum" _gui-text="Show:"> + <_item value="fce">Faces</_item> + <_item value="edg">Edges</_item> + <_item value="vtx">Vertices</_item> + </param> <param name="back" type="boolean" _gui-text="Draw back-facing polygons">0</param> - <param name="z_sort" type="optiongroup" appearance="minimal" _gui-text="Z-sort faces by:"> - <_option value="max">Maximum</_option> - <_option value="min">Minimum</_option> - <_option value="mean">Mean</_option></param> + <param name="z_sort" type="enum" _gui-text="Z-sort faces by:"> + <_item value="max">Maximum</_item> + <_item value="min">Minimum</_item> + <_item value="mean">Mean</_item></param> </page> </param> <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">polyhedron_3d.py</command> diff --git a/share/extensions/polyhedron_3d.py b/share/extensions/polyhedron_3d.py index b64cf413e..1efce876f 100644 --- a/share/extensions/polyhedron_3d.py +++ b/share/extensions/polyhedron_3d.py @@ -520,4 +520,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/printing-marks.inx b/share/extensions/printing-marks.inx index e652945d8..612ae84f5 100644 --- a/share/extensions/printing-marks.inx +++ b/share/extensions/printing-marks.inx @@ -1,49 +1,49 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Printing Marks</_name> - <id>org.inkscape.printing.marks</id> - <dependency type="executable" location="extensions">printing-marks.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> + <_name>Printing Marks</_name> + <id>org.inkscape.printing.marks</id> + <dependency type="executable" location="extensions">printing-marks.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="tab" _gui-text="Marks"> - <param name="crop_marks" type="boolean" _gui-text="Crop Marks">true</param> - <param name="bleed_marks" type="boolean" _gui-text="Bleed Marks">false</param> - <param name="registration_marks" type="boolean" _gui-text="Registration Marks">true</param> - <param name="star_target" type="boolean" _gui-text="Star Target">false</param> - <param name="colour_bars" type="boolean" _gui-text="Color Bars">true</param> - <param name="page_info" type="boolean" _gui-text="Page Information">false</param> - </page> - <page name="tab" _gui-text="Positioning"> - <param name="where" type="enum" _gui-text="Set crop marks to"> - <_item value="canvas">Canvas</_item> - <_item value="selection">Selection</_item> - </param> - <param name="unit" _gui-text="Unit" type="optiongroup" appearance="minimal"> - <option value="px">px</option> - <option value="pt">pt</option> - <option value="in">in</option> - <option value="cm">cm</option> - <option value="mm">mm</option> - </param> - <param name="crop_offset" type="float" min="0.0" max="9999.0" _gui-text="Offset:">5</param> - <_param name="bleed_settings" type="description">Bleed Margin</_param> - <param name="bleed_top" type="float" min="0.0" max="9999.0" _gui-text="Top:">5</param> - <param name="bleed_bottom" type="float" min="0.0" max="9999.0" _gui-text="Bottom:">5</param> - <param name="bleed_left" type="float" min="0.0" max="9999.0" _gui-text="Left:">5</param> - <param name="bleed_right" type="float" min="0.0" max="9999.0" _gui-text="Right:">5</param> - </page> - </param> + <param name="tab" type="notebook"> + <page name="marks" _gui-text="Marks"> + <param name="crop_marks" type="boolean" _gui-text="Crop Marks">true</param> + <param name="bleed_marks" type="boolean" _gui-text="Bleed Marks">false</param> + <param name="registration_marks" type="boolean" _gui-text="Registration Marks">true</param> + <param name="star_target" type="boolean" _gui-text="Star Target">false</param> + <param name="colour_bars" type="boolean" _gui-text="Color Bars">true</param> + <param name="page_info" type="boolean" _gui-text="Page Information">false</param> + </page> + <page name="pos" _gui-text="Positioning"> + <param name="where" type="enum" _gui-text="Set crop marks to:"> + <_item value="canvas">Canvas</_item> + <_item value="selection">Selection</_item> + </param> + <param name="unit" _gui-text="Unit:" type="enum"> + <item value="px">px</item> + <item value="pt">pt</item> + <item value="in">in</item> + <item value="cm">cm</item> + <item value="mm">mm</item> + </param> + <param name="crop_offset" type="float" min="0.0" max="9999.0" _gui-text="Offset:">5</param> + <_param name="bleed_settings" type="groupheader">Bleed Margin</_param> + <param name="bleed_top" type="float" min="0.0" max="9999.0" _gui-text="Top:">5</param> + <param name="bleed_bottom" type="float" min="0.0" max="9999.0" _gui-text="Bottom:">5</param> + <param name="bleed_left" type="float" min="0.0" max="9999.0" _gui-text="Left:">5</param> + <param name="bleed_right" type="float" min="0.0" max="9999.0" _gui-text="Right:">5</param> + </page> + </param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> + <effect needs-live-preview="false"> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> - <script> - <command reldir="extensions" interpreter="python">printing-marks.py</command> - </script> + <script> + <command reldir="extensions" interpreter="python">printing-marks.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/printing-marks.py b/share/extensions/printing-marks.py index 775f6b643..041025708 100644 --- a/share/extensions/printing-marks.py +++ b/share/extensions/printing-marks.py @@ -36,9 +36,6 @@ class Printing_Marks (inkex.Effect): def __init__(self): inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab") self.OptionParser.add_option("--where", action="store", type="string", dest="where_to_crop", default=True, @@ -91,7 +88,10 @@ class Printing_Marks (inkex.Effect): action="store", type="float", dest="bleed_right", default=0, help="Bleed Right Size") - + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def draw_crop_line(self, x1, y1, x2, y2, name, parent): style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width), diff --git a/share/extensions/ps2pdf-ext.py b/share/extensions/ps2pdf-ext.py index d3bc3d052..3c699c8ff 100644 --- a/share/extensions/ps2pdf-ext.py +++ b/share/extensions/ps2pdf-ext.py @@ -24,6 +24,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import sys from run_command import run -run('ps2pdf "%s" "%%s"' % sys.argv[1].replace("%","%%"), "ps2pdf") +cmd = 'ps2pdf' +if (sys.argv[1] == "--dEPSCrop=true"): cmd += ' -dEPSCrop ' -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +run((cmd+' "%s" "%%s"') % sys.argv[-1].replace("%","%%"), "ps2pdf") + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/pturtle.py b/share/extensions/pturtle.py index 8c67d3bc9..b2740a4bc 100755 --- a/share/extensions/pturtle.py +++ b/share/extensions/pturtle.py @@ -80,4 +80,4 @@ class pTurtle: pd = pendown -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/radiusrand.inx b/share/extensions/radiusrand.inx index 3349f4549..38e7d6c4c 100644 --- a/share/extensions/radiusrand.inx +++ b/share/extensions/radiusrand.inx @@ -1,22 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Jitter nodes</_name> - <id>org.ekips.filter.radiusrand</id> - <dependency type="executable" location="extensions">radiusrand.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title" type="description">This effect randomly shifts the nodes (and optionally node handles) of the selected path.</_param> - <param name="radiusx" type="float" min="0.0" max="1000.0" _gui-text="Maximum displacement in X, px">10.0</param> - <param name="radiusy" type="float" min="0.0" max="1000.0" _gui-text="Maximum displacement in Y, px">10.0</param> - <param name="end" type="boolean" _gui-text="Shift nodes">true</param> - <param name="ctrl" type="boolean" _gui-text="Shift node handles">false</param> - <param name="norm" type="boolean" _gui-text="Use normal distribution">true</param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">radiusrand.py</command> - </script> + <_name>Jitter nodes</_name> + <id>org.ekips.filter.radiusrand</id> + <dependency type="executable" location="extensions">radiusrand.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="radiusx" type="float" min="0.0" max="1000.0" _gui-text="Maximum displacement in X (px):">10.0</param> + <param name="radiusy" type="float" min="0.0" max="1000.0" _gui-text="Maximum displacement in Y (px):">10.0</param> + <param name="end" type="boolean" _gui-text="Shift nodes">true</param> + <param name="ctrl" type="boolean" _gui-text="Shift node handles">false</param> + <param name="norm" type="boolean" _gui-text="Use normal distribution">true</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="title" type="description">This effect randomly shifts the nodes (and optionally node handles) of the selected path.</_param> + </page> + </param> + <effect> + <object-type>path</object-type> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">radiusrand.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/radiusrand.py b/share/extensions/radiusrand.py index 15b816853..e272a50c4 100755 --- a/share/extensions/radiusrand.py +++ b/share/extensions/radiusrand.py @@ -52,6 +52,11 @@ class RadiusRandomize(inkex.Effect): action="store", type="inkbool", dest="norm", default=True, help="Use normal distribution") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") + def effect(self): for id, node in self.selected.iteritems(): if node.tag == inkex.addNS('path','svg'): @@ -77,4 +82,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/render_alphabetsoup.inx b/share/extensions/render_alphabetsoup.inx index e1c919c71..58bc938f0 100644 --- a/share/extensions/render_alphabetsoup.inx +++ b/share/extensions/render_alphabetsoup.inx @@ -5,9 +5,9 @@ <dependency type="executable" location="extensions">render_alphabetsoup.py</dependency> <dependency type="executable" location="extensions">render_alphabetsoup_config.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="text" type="string" _gui-text="Text">Inkscape</param> - <param name="zoom" type="float" min="0.0" max="1000.0" _gui-text="Scale">8.0</param> - <param name="seed" type="int" min="0" max="65535" _gui-text="Random Seed">0</param> + <param name="text" type="string" _gui-text="Text:">Inkscape</param> + <param name="zoom" type="float" min="0.0" max="1000.0" _gui-text="Scale:">8.0</param> + <param name="seed" type="int" min="0" max="65535" _gui-text="Random Seed:">0</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/render_alphabetsoup.py b/share/extensions/render_alphabetsoup.py index 7e4009328..ffc20323b 100644 --- a/share/extensions/render_alphabetsoup.py +++ b/share/extensions/render_alphabetsoup.py @@ -1,463 +1,463 @@ -#!/usr/bin/env python
-'''
-Copyright (C) 2001-2002 Matt Chisholm matt@theory.org
-Copyright (C) 2008 Joel Holdsworth joel@airwebreathe.org.uk
- for AP
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-'''
-
-import copy
-import inkex
-import simplestyle
-import math
-import cmath
-import string
-import random
-import render_alphabetsoup_config
-import bezmisc
-import simplepath
-import os
-import sys
-import gettext
-_ = gettext.gettext
-
-syntax = render_alphabetsoup_config.syntax
-alphabet = render_alphabetsoup_config.alphabet
-units = render_alphabetsoup_config.units
-font = render_alphabetsoup_config.font
-
-# Loads a super-path from a given SVG file
-def loadPath( svgPath ):
- extensionDir = os.path.normpath(
- os.path.join( os.getcwd(), os.path.dirname(__file__) )
- )
- # __file__ is better then sys.argv[0] because this file may be a module
- # for another one.
- tree = inkex.etree.parse( extensionDir + "/" + svgPath )
- root = tree.getroot()
- pathElement = root.find('{http://www.w3.org/2000/svg}path')
- if pathElement == None:
- return None, 0, 0
- d = pathElement.get("d")
- width = float(root.get("width"))
- height = float(root.get("height"))
- return simplepath.parsePath(d), width, height # Currently we only support a single path
-
-def combinePaths( pathA, pathB ):
- if pathA == None and pathB == None:
- return None
- elif pathA == None:
- return pathB
- elif pathB == None:
- return pathA
- else:
- return pathA + pathB
-
-def flipLeftRight( sp, width ):
- for cmd,params in sp:
- defs = simplepath.pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- params[i] = width - params[i]
-
-def flipTopBottom( sp, height ):
- for cmd,params in sp:
- defs = simplepath.pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'y':
- params[i] = height - params[i]
-
-def solveQuadratic(a, b, c):
- det = b*b - 4.0*a*c
- if det >= 0: # real roots
- sdet = math.sqrt(det)
- else: # complex roots
- sdet = cmath.sqrt(det)
- return (-b + sdet) / (2*a), (-b - sdet) / (2*a)
-
-def cbrt(x):
- if x >= 0:
- return x**(1.0/3.0)
- else:
- return -((-x)**(1.0/3.0))
-
-def findRealRoots(a,b,c,d):
- if a != 0:
- a, b, c, d = 1, b/float(a), c/float(a), d/float(a) # Divide through by a
- t = b / 3.0
- p, q = c - 3 * t**2, d - c * t + 2 * t**3
- u, v = solveQuadratic(1, q, -(p/3.0)**3)
- if type(u) == type(0j): # Complex Cubic Root
- r = math.sqrt(u.real**2 + u.imag**2)
- w = math.atan2(u.imag, u.real)
- y1 = 2 * cbrt(r) * math.cos(w / 3.0)
- else: # Complex Real Root
- y1 = cbrt(u) + cbrt(v)
-
- y2, y3 = solveQuadratic(1, y1, p + y1**2)
-
- if type(y2) == type(0j): # Are y2 and y3 complex?
- return [y1 - t]
- return [y1 - t, y2 - t, y3 - t]
- elif b != 0:
- det=c*c - 4.0*b*d
- if det >= 0:
- return [(-c + math.sqrt(det))/(2.0*b),(-c - math.sqrt(det))/(2.0*b)]
- elif c != 0:
- return [-d/c]
- return []
-
-def getPathBoundingBox( sp ):
-
- box = None
- last = None
- lostctrl = None
-
- for cmd,params in sp:
-
- segmentBox = None
-
- if cmd == 'M':
- # A move cannot contribute to the bounding box
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'L':
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'C':
- if last:
- segmentBox = (min(params[4], last[0]), max(params[4], last[0]), min(params[5], last[1]), max(params[5], last[1]))
-
- bx0, by0 = last[:]
- bx1, by1, bx2, by2, bx3, by3 = params[:]
-
- # Compute the x limits
- a = (-bx0 + 3*bx1 - 3*bx2 + bx3)*3
- b = (3*bx0 - 6*bx1 + 3*bx2)*2
- c = (-3*bx0 + 3*bx1)
- ts = findRealRoots(0, a, b, c)
- for t in ts:
- if t >= 0 and t <= 1:
- x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
- (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
- (-3*bx0 + 3*bx1)*t + \
- bx0
- segmentBox = (min(segmentBox[0], x), max(segmentBox[1], x), segmentBox[2], segmentBox[3])
-
- # Compute the y limits
- a = (-by0 + 3*by1 - 3*by2 + by3)*3
- b = (3*by0 - 6*by1 + 3*by2)*2
- c = (-3*by0 + 3*by1)
- ts = findRealRoots(0, a, b, c)
- for t in ts:
- if t >= 0 and t <= 1:
- y = (-by0 + 3*by1 - 3*by2 + by3)*(t**3) + \
- (3*by0 - 6*by1 + 3*by2)*(t**2) + \
- (-3*by0 + 3*by1)*t + \
- by0
- segmentBox = (segmentBox[0], segmentBox[1], min(segmentBox[2], y), max(segmentBox[3], y))
-
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'Q':
- # Provisional
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'A':
- # Provisional
- if last:
- segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1]))
- last = params[-2:]
- lastctrl = params[2:4]
-
- if segmentBox:
- if box:
- box = (min(segmentBox[0],box[0]), max(segmentBox[1],box[1]), min(segmentBox[2],box[2]), max(segmentBox[3],box[3]))
- else:
- box = segmentBox
- return box
-
-def mxfm( image, width, height, stack ): # returns possibly transformed image
- tbimage = image
- if ( stack[0] == "-" ): # top-bottom flip
- flipTopBottom(tbimage, height)
- stack.pop( 0 )
-
- lrimage = tbimage
- if ( stack[0] == "|" ): # left-right flip
- flipLeftRight(tbimage, width)
- stack.pop( 0 )
- return lrimage
-
-def comparerule( rule, nodes ): # compare node list to nodes in rule
- for i in range( 0, len(nodes)): # range( a, b ) = (a, a+1, a+2 ... b-2, b-1)
- if (nodes[i] == rule[i][0]):
- pass
- else: return 0
- return 1
-
-def findrule( state, nodes ): # find the rule which generated this subtree
- ruleset = syntax[state][1]
- nodelen = len(nodes)
- for rule in ruleset:
- rulelen = len(rule)
- if ((rulelen == nodelen) and (comparerule( rule, nodes ))):
- return rule
- return
-
-def generate( state ): # generate a random tree (in stack form)
- stack = [ state ]
- if ( len(syntax[state]) == 1 ): # if this is a stop symbol
- return stack
- else:
- stack.append( "[" )
- path = random.randint(0, (len(syntax[state][1])-1)) # choose randomly from next states
- for symbol in syntax[state][1][path]: # recurse down each non-terminal
- if ( symbol != 0 ): # 0 denotes end of list ###
- substack = generate( symbol[0] ) # get subtree
- for elt in substack:
- stack.append( elt )
- if (symbol[3]):stack.append( "-" ) # top-bottom flip
- if (symbol[4]):stack.append( "|" ) # left-right flip
- #else:
- #inkex.debug("found end of list in generate( state =", state, ")") # this should be deprecated/never happen
- stack.append("]")
- return stack
-
-def draw( stack ): # draw a character based on a tree stack
- state = stack.pop(0)
- #print state,
-
- image, width, height = loadPath( font+syntax[state][0] ) # load the image
- if (stack[0] != "["): # terminal stack element
- if (len(syntax[state]) == 1): # this state is a terminal node
- return image, width, height
- else:
- substack = generate( state ) # generate random substack
- return draw( substack ) # draw random substack
- else:
- #inkex.debug("[")
- stack.pop(0)
- images = [] # list of daughter images
- nodes = [] # list of daughter names
- while (stack[0] != "]"): # for all nodes in stack
- newstate = stack[0] # the new state
- newimage, width, height = draw( stack ) # draw the daughter state
- if (newimage):
- tfimage = mxfm( newimage, width, height, stack ) # maybe transform daughter state
- images.append( [tfimage, width, height] ) # list of daughter images
- nodes.append( newstate ) # list of daughter nodes
- else:
- #inkex.debug(("recurse on",newstate,"failed")) # this should never happen
- return None, 0, 0
- rule = findrule( state, nodes ) # find the rule for this subtree
-
- for i in range( 0, len(images)):
- currimg, width, height = images[i]
-
- if currimg:
- #box = getPathBoundingBox(currimg)
- dx = rule[i][1]*units
- dy = rule[i][2]*units
- #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy))
- simplepath.translatePath(currimg, dx, dy)
- image = combinePaths( image, currimg )
-
- stack.pop( 0 )
- return image, width, height
-
-def draw_crop_scale( stack, zoom ): # draw, crop and scale letter image
- image, width, height = draw(stack)
- bbox = getPathBoundingBox(image)
- simplepath.translatePath(image, -bbox[0], 0)
- simplepath.scalePath(image, zoom/units, zoom/units)
- return image, bbox[1] - bbox[0], bbox[3] - bbox[2]
-
-def randomize_input_string( str, zoom ): # generate list of images based on input string
- imagelist = []
-
- for i in range(0,len(str)):
- char = str[i]
- #if ( re.match("[a-zA-Z0-9?]", char)):
- if ( alphabet.has_key(char)):
- if ((i > 0) and (char == str[i-1])): # if this letter matches previous letter
- imagelist.append(imagelist[len(stack)-1])# make them the same image
- else: # generate image for letter
- stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-1))] , "." )
- #stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-2))] , "." )
- imagelist.append( draw_crop_scale( stack, zoom ))
- elif( char == " "): # add a " " space to the image list
- imagelist.append( " " )
- else: # this character is not in config.alphabet, skip it
- inkex.errormsg(_("bad character") + " = 0x%x" % ord(char))
- return imagelist
-
-def optikern( image, width, zoom ): # optical kerning algorithm
- left = []
- right = []
-
- for i in range( 0, 36 ):
- y = 0.5 * (i + 0.5) * zoom
- xmin = None
- xmax = None
-
- for cmd,params in image:
-
- segmentBox = None
-
- if cmd == 'M':
- # A move cannot contribute to the bounding box
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'L':
- if (y >= last[1] and y <= params[1]) or (y >= params[1] and y <= last[1]):
- if params[0] == last[0]:
- x = params[0]
- else:
- a = (params[1] - last[1]) / (params[0] - last[0])
- b = last[1] - a * last[0]
- if a != 0:
- x = (y - b) / a
- else: x = None
-
- if x:
- if xmin == None or x < xmin: xmin = x
- if xmax == None or x > xmax: xmax = x
-
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'C':
- if last:
- bx0, by0 = last[:]
- bx1, by1, bx2, by2, bx3, by3 = params[:]
-
- d = by0 - y
- c = -3*by0 + 3*by1
- b = 3*by0 - 6*by1 + 3*by2
- a = -by0 + 3*by1 - 3*by2 + by3
-
- ts = findRealRoots(a, b, c, d)
-
- for t in ts:
- if t >= 0 and t <= 1:
- x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \
- (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \
- (-3*bx0 + 3*bx1)*t + \
- bx0
- if xmin == None or x < xmin: xmin = x
- if xmax == None or x > xmax: xmax = x
-
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'Q':
- # Quadratic beziers are ignored
- last = params[-2:]
- lastctrl = params[2:4]
-
- elif cmd == 'A':
- # Arcs are ignored
- last = params[-2:]
- lastctrl = params[2:4]
-
-
- if xmin != None and xmax != None:
- left.append( xmin ) # distance from left edge of region to left edge of bbox
- right.append( width - xmax ) # distance from right edge of region to right edge of bbox
- else:
- left.append( width )
- right.append( width )
-
- return (left, right)
-
-def layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning
- kernlist = []
- length = zoom
- for entry in imagelist:
- if (entry == " "): # leaving room for " " space characters
- length = length + (zoom * render_alphabetsoup_config.space)
- else:
- image, width, height = entry
- length = length + width + zoom # add letter length to overall length
- kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image
-
- workspace = None
-
- position = zoom
- for i in range(0, len(kernlist)):
- while(imagelist[i] == " "):
- position = position + (zoom * render_alphabetsoup_config.space )
- imagelist.pop(i)
- image, width, height = imagelist[i]
-
- # set the kerning
- if i == 0: kern = 0 # for first image, kerning is zero
- else:
- kerncompare = [] # kerning comparison array
- for j in range( 0, len(kernlist[i][0])):
- kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] )
- kern = min( kerncompare )
-
- position = position - kern # move position back by kern amount
- thisimage = copy.deepcopy(image)
- simplepath.translatePath(thisimage, position, 0)
- workspace = combinePaths(workspace, thisimage)
- position = position + width + zoom # advance position by letter width
-
- return workspace
-
-class AlphabetSoup(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-t", "--text",
- action="store", type="string",
- dest="text", default="Inkscape",
- help="The text for alphabet soup")
- self.OptionParser.add_option("-z", "--zoom",
- action="store", type="float",
- dest="zoom", default="8.0",
- help="The zoom on the output graphics")
- self.OptionParser.add_option("-s", "--seed",
- action="store", type="int",
- dest="seed", default="0",
- help="The random seed for the soup")
-
- def effect(self):
- zoom = self.options.zoom
- random.seed(self.options.seed)
-
- imagelist = randomize_input_string(self.options.text, zoom)
- image = layoutstring( imagelist, zoom )
-
- if image:
- s = { 'stroke': 'none', 'fill': '#000000' }
-
- new = inkex.etree.Element(inkex.addNS('path','svg'))
- new.set('style', simplestyle.formatStyle(s))
-
- new.set('d', simplepath.formatPath(image))
- self.current_layer.append(new)
-
-if __name__ == '__main__':
- e = AlphabetSoup()
- e.affect()
-
+#!/usr/bin/env python +''' +Copyright (C) 2001-2002 Matt Chisholm matt@theory.org +Copyright (C) 2008 Joel Holdsworth joel@airwebreathe.org.uk + for AP + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +import copy +import inkex +import simplestyle +import math +import cmath +import string +import random +import render_alphabetsoup_config +import bezmisc +import simplepath +import os +import sys +import gettext +_ = gettext.gettext + +syntax = render_alphabetsoup_config.syntax +alphabet = render_alphabetsoup_config.alphabet +units = render_alphabetsoup_config.units +font = render_alphabetsoup_config.font + +# Loads a super-path from a given SVG file +def loadPath( svgPath ): + extensionDir = os.path.normpath( + os.path.join( os.getcwd(), os.path.dirname(__file__) ) + ) + # __file__ is better then sys.argv[0] because this file may be a module + # for another one. + tree = inkex.etree.parse( extensionDir + "/" + svgPath ) + root = tree.getroot() + pathElement = root.find('{http://www.w3.org/2000/svg}path') + if pathElement == None: + return None, 0, 0 + d = pathElement.get("d") + width = float(root.get("width")) + height = float(root.get("height")) + return simplepath.parsePath(d), width, height # Currently we only support a single path + +def combinePaths( pathA, pathB ): + if pathA == None and pathB == None: + return None + elif pathA == None: + return pathB + elif pathB == None: + return pathA + else: + return pathA + pathB + +def flipLeftRight( sp, width ): + for cmd,params in sp: + defs = simplepath.pathdefs[cmd] + for i in range(defs[1]): + if defs[3][i] == 'x': + params[i] = width - params[i] + +def flipTopBottom( sp, height ): + for cmd,params in sp: + defs = simplepath.pathdefs[cmd] + for i in range(defs[1]): + if defs[3][i] == 'y': + params[i] = height - params[i] + +def solveQuadratic(a, b, c): + det = b*b - 4.0*a*c + if det >= 0: # real roots + sdet = math.sqrt(det) + else: # complex roots + sdet = cmath.sqrt(det) + return (-b + sdet) / (2*a), (-b - sdet) / (2*a) + +def cbrt(x): + if x >= 0: + return x**(1.0/3.0) + else: + return -((-x)**(1.0/3.0)) + +def findRealRoots(a,b,c,d): + if a != 0: + a, b, c, d = 1, b/float(a), c/float(a), d/float(a) # Divide through by a + t = b / 3.0 + p, q = c - 3 * t**2, d - c * t + 2 * t**3 + u, v = solveQuadratic(1, q, -(p/3.0)**3) + if type(u) == type(0j): # Complex Cubic Root + r = math.sqrt(u.real**2 + u.imag**2) + w = math.atan2(u.imag, u.real) + y1 = 2 * cbrt(r) * math.cos(w / 3.0) + else: # Complex Real Root + y1 = cbrt(u) + cbrt(v) + + y2, y3 = solveQuadratic(1, y1, p + y1**2) + + if type(y2) == type(0j): # Are y2 and y3 complex? + return [y1 - t] + return [y1 - t, y2 - t, y3 - t] + elif b != 0: + det=c*c - 4.0*b*d + if det >= 0: + return [(-c + math.sqrt(det))/(2.0*b),(-c - math.sqrt(det))/(2.0*b)] + elif c != 0: + return [-d/c] + return [] + +def getPathBoundingBox( sp ): + + box = None + last = None + lostctrl = None + + for cmd,params in sp: + + segmentBox = None + + if cmd == 'M': + # A move cannot contribute to the bounding box + last = params[:] + lastctrl = params[:] + elif cmd == 'L': + if last: + segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1])) + last = params[:] + lastctrl = params[:] + elif cmd == 'C': + if last: + segmentBox = (min(params[4], last[0]), max(params[4], last[0]), min(params[5], last[1]), max(params[5], last[1])) + + bx0, by0 = last[:] + bx1, by1, bx2, by2, bx3, by3 = params[:] + + # Compute the x limits + a = (-bx0 + 3*bx1 - 3*bx2 + bx3)*3 + b = (3*bx0 - 6*bx1 + 3*bx2)*2 + c = (-3*bx0 + 3*bx1) + ts = findRealRoots(0, a, b, c) + for t in ts: + if t >= 0 and t <= 1: + x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \ + (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \ + (-3*bx0 + 3*bx1)*t + \ + bx0 + segmentBox = (min(segmentBox[0], x), max(segmentBox[1], x), segmentBox[2], segmentBox[3]) + + # Compute the y limits + a = (-by0 + 3*by1 - 3*by2 + by3)*3 + b = (3*by0 - 6*by1 + 3*by2)*2 + c = (-3*by0 + 3*by1) + ts = findRealRoots(0, a, b, c) + for t in ts: + if t >= 0 and t <= 1: + y = (-by0 + 3*by1 - 3*by2 + by3)*(t**3) + \ + (3*by0 - 6*by1 + 3*by2)*(t**2) + \ + (-3*by0 + 3*by1)*t + \ + by0 + segmentBox = (segmentBox[0], segmentBox[1], min(segmentBox[2], y), max(segmentBox[3], y)) + + last = params[-2:] + lastctrl = params[2:4] + + elif cmd == 'Q': + # Provisional + if last: + segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1])) + last = params[-2:] + lastctrl = params[2:4] + + elif cmd == 'A': + # Provisional + if last: + segmentBox = (min(params[0], last[0]), max(params[0], last[0]), min(params[1], last[1]), max(params[1], last[1])) + last = params[-2:] + lastctrl = params[2:4] + + if segmentBox: + if box: + box = (min(segmentBox[0],box[0]), max(segmentBox[1],box[1]), min(segmentBox[2],box[2]), max(segmentBox[3],box[3])) + else: + box = segmentBox + return box + +def mxfm( image, width, height, stack ): # returns possibly transformed image + tbimage = image + if ( stack[0] == "-" ): # top-bottom flip + flipTopBottom(tbimage, height) + stack.pop( 0 ) + + lrimage = tbimage + if ( stack[0] == "|" ): # left-right flip + flipLeftRight(tbimage, width) + stack.pop( 0 ) + return lrimage + +def comparerule( rule, nodes ): # compare node list to nodes in rule + for i in range( 0, len(nodes)): # range( a, b ) = (a, a+1, a+2 ... b-2, b-1) + if (nodes[i] == rule[i][0]): + pass + else: return 0 + return 1 + +def findrule( state, nodes ): # find the rule which generated this subtree + ruleset = syntax[state][1] + nodelen = len(nodes) + for rule in ruleset: + rulelen = len(rule) + if ((rulelen == nodelen) and (comparerule( rule, nodes ))): + return rule + return + +def generate( state ): # generate a random tree (in stack form) + stack = [ state ] + if ( len(syntax[state]) == 1 ): # if this is a stop symbol + return stack + else: + stack.append( "[" ) + path = random.randint(0, (len(syntax[state][1])-1)) # choose randomly from next states + for symbol in syntax[state][1][path]: # recurse down each non-terminal + if ( symbol != 0 ): # 0 denotes end of list ### + substack = generate( symbol[0] ) # get subtree + for elt in substack: + stack.append( elt ) + if (symbol[3]):stack.append( "-" ) # top-bottom flip + if (symbol[4]):stack.append( "|" ) # left-right flip + #else: + #inkex.debug("found end of list in generate( state =", state, ")") # this should be deprecated/never happen + stack.append("]") + return stack + +def draw( stack ): # draw a character based on a tree stack + state = stack.pop(0) + #print state, + + image, width, height = loadPath( font+syntax[state][0] ) # load the image + if (stack[0] != "["): # terminal stack element + if (len(syntax[state]) == 1): # this state is a terminal node + return image, width, height + else: + substack = generate( state ) # generate random substack + return draw( substack ) # draw random substack + else: + #inkex.debug("[") + stack.pop(0) + images = [] # list of daughter images + nodes = [] # list of daughter names + while (stack[0] != "]"): # for all nodes in stack + newstate = stack[0] # the new state + newimage, width, height = draw( stack ) # draw the daughter state + if (newimage): + tfimage = mxfm( newimage, width, height, stack ) # maybe transform daughter state + images.append( [tfimage, width, height] ) # list of daughter images + nodes.append( newstate ) # list of daughter nodes + else: + #inkex.debug(("recurse on",newstate,"failed")) # this should never happen + return None, 0, 0 + rule = findrule( state, nodes ) # find the rule for this subtree + + for i in range( 0, len(images)): + currimg, width, height = images[i] + + if currimg: + #box = getPathBoundingBox(currimg) + dx = rule[i][1]*units + dy = rule[i][2]*units + #newbox = ((box[0]+dx),(box[1]+dy),(box[2]+dx),(box[3]+dy)) + simplepath.translatePath(currimg, dx, dy) + image = combinePaths( image, currimg ) + + stack.pop( 0 ) + return image, width, height + +def draw_crop_scale( stack, zoom ): # draw, crop and scale letter image + image, width, height = draw(stack) + bbox = getPathBoundingBox(image) + simplepath.translatePath(image, -bbox[0], 0) + simplepath.scalePath(image, zoom/units, zoom/units) + return image, bbox[1] - bbox[0], bbox[3] - bbox[2] + +def randomize_input_string( str, zoom ): # generate list of images based on input string + imagelist = [] + + for i in range(0,len(str)): + char = str[i] + #if ( re.match("[a-zA-Z0-9?]", char)): + if ( alphabet.has_key(char)): + if ((i > 0) and (char == str[i-1])): # if this letter matches previous letter + imagelist.append(imagelist[len(stack)-1])# make them the same image + else: # generate image for letter + stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-1))] , "." ) + #stack = string.split( alphabet[char][random.randint(0,(len(alphabet[char])-2))] , "." ) + imagelist.append( draw_crop_scale( stack, zoom )) + elif( char == " "): # add a " " space to the image list + imagelist.append( " " ) + else: # this character is not in config.alphabet, skip it + inkex.errormsg(_("bad character") + " = 0x%x" % ord(char)) + return imagelist + +def optikern( image, width, zoom ): # optical kerning algorithm + left = [] + right = [] + + for i in range( 0, 36 ): + y = 0.5 * (i + 0.5) * zoom + xmin = None + xmax = None + + for cmd,params in image: + + segmentBox = None + + if cmd == 'M': + # A move cannot contribute to the bounding box + last = params[:] + lastctrl = params[:] + elif cmd == 'L': + if (y >= last[1] and y <= params[1]) or (y >= params[1] and y <= last[1]): + if params[0] == last[0]: + x = params[0] + else: + a = (params[1] - last[1]) / (params[0] - last[0]) + b = last[1] - a * last[0] + if a != 0: + x = (y - b) / a + else: x = None + + if x: + if xmin == None or x < xmin: xmin = x + if xmax == None or x > xmax: xmax = x + + last = params[:] + lastctrl = params[:] + elif cmd == 'C': + if last: + bx0, by0 = last[:] + bx1, by1, bx2, by2, bx3, by3 = params[:] + + d = by0 - y + c = -3*by0 + 3*by1 + b = 3*by0 - 6*by1 + 3*by2 + a = -by0 + 3*by1 - 3*by2 + by3 + + ts = findRealRoots(a, b, c, d) + + for t in ts: + if t >= 0 and t <= 1: + x = (-bx0 + 3*bx1 - 3*bx2 + bx3)*(t**3) + \ + (3*bx0 - 6*bx1 + 3*bx2)*(t**2) + \ + (-3*bx0 + 3*bx1)*t + \ + bx0 + if xmin == None or x < xmin: xmin = x + if xmax == None or x > xmax: xmax = x + + last = params[-2:] + lastctrl = params[2:4] + + elif cmd == 'Q': + # Quadratic beziers are ignored + last = params[-2:] + lastctrl = params[2:4] + + elif cmd == 'A': + # Arcs are ignored + last = params[-2:] + lastctrl = params[2:4] + + + if xmin != None and xmax != None: + left.append( xmin ) # distance from left edge of region to left edge of bbox + right.append( width - xmax ) # distance from right edge of region to right edge of bbox + else: + left.append( width ) + right.append( width ) + + return (left, right) + +def layoutstring( imagelist, zoom ): # layout string of letter-images using optical kerning + kernlist = [] + length = zoom + for entry in imagelist: + if (entry == " "): # leaving room for " " space characters + length = length + (zoom * render_alphabetsoup_config.space) + else: + image, width, height = entry + length = length + width + zoom # add letter length to overall length + kernlist.append( optikern(image, width, zoom) ) # append kerning data for this image + + workspace = None + + position = zoom + for i in range(0, len(kernlist)): + while(imagelist[i] == " "): + position = position + (zoom * render_alphabetsoup_config.space ) + imagelist.pop(i) + image, width, height = imagelist[i] + + # set the kerning + if i == 0: kern = 0 # for first image, kerning is zero + else: + kerncompare = [] # kerning comparison array + for j in range( 0, len(kernlist[i][0])): + kerncompare.append( kernlist[i][0][j]+kernlist[i-1][1][j] ) + kern = min( kerncompare ) + + position = position - kern # move position back by kern amount + thisimage = copy.deepcopy(image) + simplepath.translatePath(thisimage, position, 0) + workspace = combinePaths(workspace, thisimage) + position = position + width + zoom # advance position by letter width + + return workspace + +class AlphabetSoup(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("-t", "--text", + action="store", type="string", + dest="text", default="Inkscape", + help="The text for alphabet soup") + self.OptionParser.add_option("-z", "--zoom", + action="store", type="float", + dest="zoom", default="8.0", + help="The zoom on the output graphics") + self.OptionParser.add_option("-s", "--seed", + action="store", type="int", + dest="seed", default="0", + help="The random seed for the soup") + + def effect(self): + zoom = self.options.zoom + random.seed(self.options.seed) + + imagelist = randomize_input_string(self.options.text, zoom) + image = layoutstring( imagelist, zoom ) + + if image: + s = { 'stroke': 'none', 'fill': '#000000' } + + new = inkex.etree.Element(inkex.addNS('path','svg')) + new.set('style', simplestyle.formatStyle(s)) + + new.set('d', simplepath.formatPath(image)) + self.current_layer.append(new) + +if __name__ == '__main__': + e = AlphabetSoup() + e.affect() + diff --git a/share/extensions/render_alphabetsoup_config.py b/share/extensions/render_alphabetsoup_config.py index a56120ea3..63f3fe5c1 100644 --- a/share/extensions/render_alphabetsoup_config.py +++ b/share/extensions/render_alphabetsoup_config.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # Syntax format: (raise your hand if you know lisp :-) # # 'state0': ("file.svg", ( ( ('state1', dx, dy, T-B, L|R),), @@ -580,4 +581,4 @@ units = 36 # pixels per unit box in font font = "alphabet_soup/" # location of font images -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/render_barcode.py b/share/extensions/render_barcode.py index cdcb022cb..3de1a07da 100644 --- a/share/extensions/render_barcode.py +++ b/share/extensions/render_barcode.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ''' Copyright (C) 2007 Martin Owens diff --git a/share/extensions/render_barcode_datamatrix.inx b/share/extensions/render_barcode_datamatrix.inx index ea2aa4705..58699e4a9 100644 --- a/share/extensions/render_barcode_datamatrix.inx +++ b/share/extensions/render_barcode_datamatrix.inx @@ -4,10 +4,10 @@ <id>il.datamatrix</id> <dependency type="executable" location="extensions">render_barcode_datamatrix.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="text" type="string" _gui-text="Text">Inkscape</param> - <param name="rows" type="int" min="8" max="144" _gui-text="Rows">10</param> - <param name="cols" type="int" min="10" max="144" _gui-text="Cols">10</param> - <param name="size" type="int" min="1" max="1000" _gui-text="Square Size / px">4</param> + <param name="text" type="string" _gui-text="Text:">Inkscape</param> + <param name="rows" type="int" min="8" max="144" _gui-text="Rows:">10</param> + <param name="cols" type="int" min="10" max="144" _gui-text="Cols:">10</param> + <param name="size" type="int" min="1" max="1000" _gui-text="Square Size (px):">4</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/render_barcode_datamatrix.py b/share/extensions/render_barcode_datamatrix.py index e5365546e..785d7de56 100644 --- a/share/extensions/render_barcode_datamatrix.py +++ b/share/extensions/render_barcode_datamatrix.py @@ -651,4 +651,4 @@ if __name__ == '__main__': e = DataMatrix() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/render_barcode_qrcode.inx b/share/extensions/render_barcode_qrcode.inx new file mode 100644 index 000000000..b0085f6bd --- /dev/null +++ b/share/extensions/render_barcode_qrcode.inx @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Barcode - QR Code</_name> + <id>org.inkscape.qrcode</id> + <dependency type="executable" location="extensions">render_barcode_qrcode.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <_param name="generalhint" type="description" xml:space="preserve">See http://www.denso-wave.com/qrcode/index-e.html for details</_param> + <param name="text" type="string" _gui-text="Text:">www.inkscape.org</param> + <param name="typenumber" type="enum" _gui-text="Size, in unit squares:"> + <_item value="0">Auto</_item> + <item value="1">21x21</item> + <item value="2">25x25</item> + <item value="3">29x29</item> + <item value="4">33x33</item> + <item value="5">37x37</item> + <item value="6">41x41</item> + <item value="7">45x45</item> + <item value="8">49x49</item> + <item value="9">53x53</item> + <item value="10">57x37</item> + <item value="11">61x61</item> + <item value="12">65x65</item> + <item value="13">69x69</item> + <item value="14">73x73</item> + <item value="15">77x77</item> + <item value="16">81x81</item> + <item value="17">85x85</item> + <item value="18">89x89</item> + <item value="19">93x93</item> + <item value="20">97x97</item> + <item value="21">101x101</item> + <item value="22">105x105</item> + <item value="23">109x109</item> + <item value="24">113x113</item> + <item value="25">117x117</item> + <item value="26">121x121</item> + <item value="27">125x125</item> + <item value="28">129x129</item> + <item value="29">133x133</item> + <item value="30">137x137</item> + <item value="31">141x141</item> + <item value="32">145x145</item> + <item value="33">149x149</item> + <item value="34">153x153</item> + <item value="35">157x157</item> + <item value="36">161x161</item> + <item value="37">165x165</item> + <item value="38">169x169</item> + <item value="39">173x173</item> + <item value="40">177x177</item> + </param> + <_param name="sizehint" type="description" xml:space="preserve">With "Auto", the size of the barcode depends on the length of the text and the error correction level</_param> + <param name="correctionlevel" type="enum" _gui-text="Error correction level:"> + <_item value="1">L (Approx. 7%)</_item> + <_item value="0">M (Approx. 15%)</_item> + <_item value="3">Q (Approx. 25%)</_item> + <_item value="2">H (Approx. 30%)</_item> + </param> + <param name="modulesize" type="float" min="0" max="1000" _gui-text="Square size (px):">4</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">render_barcode_qrcode.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/render_barcode_qrcode.py b/share/extensions/render_barcode_qrcode.py new file mode 100644 index 000000000..50570ca02 --- /dev/null +++ b/share/extensions/render_barcode_qrcode.py @@ -0,0 +1,1068 @@ +import math, sys +import inkex + +#QRCode for Python +# +#Ported from the Javascript library by Sam Curren +# +#QRCode for Javascript +#http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js +# +#Copyright (c) 2009 Kazuhiko Arase +# +#URL: http://www.d-project.com/ +# +# Copyright (c) 2010 buliabyak@gmail.com: +# adapting for Inkscape extension, SVG output, Auto mode +# +#Licensed under the MIT license: +# http://www.opensource.org/licenses/mit-license.php +# +# The word "QR Code" is registered trademark of +# DENSO WAVE INCORPORATED +# http://www.denso-wave.com/qrcode/faqpatent-e.html + +class QR8bitByte: + + def __init__(self, data): + self.mode = QRMode.MODE_8BIT_BYTE + self.data = data + + def getLength(self): + return len(self.data) + + def write(self, buffer): + for i in range(len(self.data)): + #// not JIS ... + buffer.put(ord(self.data[i]), 8) + def __repr__(self): + return self.data + +class QRCode: + def __init__(self, typeNumber, errorCorrectLevel): + self.typeNumber = typeNumber + self.errorCorrectLevel = errorCorrectLevel + self.modules = None + self.moduleCount = 0 + self.dataCache = None + self.dataList = [] + def addData(self, data): + newData = QR8bitByte(data) + self.dataList.append(newData) + self.dataCache = None + def isDark(self, row, col): + if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col): + raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) + return self.modules[row][col] + def getModuleCount(self): + return self.moduleCount + def make(self): + self.makeImpl(False, self.getBestMaskPattern() ) + def makeImpl(self, test, maskPattern): + + if self.typeNumber == 0: + self.typeNumber = QRCode.autoNumber(self.errorCorrectLevel, self.dataList) + self.moduleCount = self.typeNumber * 4 + 17 + self.modules = [None for x in range(self.moduleCount)] + + for row in range(self.moduleCount): + + self.modules[row] = [None for x in range(self.moduleCount)] + + for col in range(self.moduleCount): + self.modules[row][col] = None #//(col + row) % 3; + + self.setupPositionProbePattern(0, 0) + self.setupPositionProbePattern(self.moduleCount - 7, 0) + self.setupPositionProbePattern(0, self.moduleCount - 7) + self.setupPositionAdjustPattern() + self.setupTimingPattern() + self.setupTypeInfo(test, maskPattern) + + if (self.typeNumber >= 7): + self.setupTypeNumber(test) + + if (self.dataCache == None): + self.dataCache = QRCode.createData(self.typeNumber, self.errorCorrectLevel, self.dataList) + self.mapData(self.dataCache, maskPattern) + + def setupPositionProbePattern(self, row, col): + + for r in range(-1, 8): + + if (row + r <= -1 or self.moduleCount <= row + r): continue + + for c in range(-1, 8): + + if (col + c <= -1 or self.moduleCount <= col + c): continue + + if ( (0 <= r and r <= 6 and (c == 0 or c == 6) ) + or (0 <= c and c <= 6 and (r == 0 or r == 6) ) + or (2 <= r and r <= 4 and 2 <= c and c <= 4) ): + self.modules[row + r][col + c] = True; + else: + self.modules[row + r][col + c] = False; + + def getBestMaskPattern(self): + + minLostPoint = 0 + pattern = 0 + + for i in range(8): + + self.makeImpl(True, i); + + lostPoint = QRUtil.getLostPoint(self); + + if (i == 0 or minLostPoint > lostPoint): + minLostPoint = lostPoint + pattern = i + + return pattern + + def makeSVG(self, grp, boxsize): + margin = 4 + pixelsize = (self.getModuleCount() + 2*margin) * boxsize #self.getModuleCount() * boxsize + + # white background providing margin: + rect = inkex.etree.SubElement(grp, inkex.addNS('rect', 'svg')) + rect.set('x', '0') + rect.set('y', '0') + rect.set('width', str(pixelsize)) + rect.set('height', str(pixelsize)) + rect.set('style', 'fill:white;stroke:none') + + for r in range(self.getModuleCount()): + for c in range(self.getModuleCount()): + if (self.isDark(r, c) ): + x = (c + margin) * boxsize + y = (r + margin) * boxsize + rect = inkex.etree.SubElement(grp, inkex.addNS('rect', 'svg')) + rect.set('x', str(x)) + rect.set('y', str(y)) + rect.set('width', str(boxsize)) + rect.set('height', str(boxsize)) + rect.set('style', 'fill:black;stroke:none') + + def setupTimingPattern(self): + + for r in range(8, self.moduleCount - 8): + if (self.modules[r][6] != None): + continue + self.modules[r][6] = (r % 2 == 0) + + for c in range(8, self.moduleCount - 8): + if (self.modules[6][c] != None): + continue + self.modules[6][c] = (c % 2 == 0) + + def setupPositionAdjustPattern(self): + + pos = QRUtil.getPatternPosition(self.typeNumber) + + for i in range(len(pos)): + + for j in range(len(pos)): + + row = pos[i] + col = pos[j] + + if (self.modules[row][col] != None): + continue + + for r in range(-2, 3): + + for c in range(-2, 3): + + if (r == -2 or r == 2 or c == -2 or c == 2 or (r == 0 and c == 0) ): + self.modules[row + r][col + c] = True + else: + self.modules[row + r][col + c] = False + + def setupTypeNumber(self, test): + + bits = QRUtil.getBCHTypeNumber(self.typeNumber) + + for i in range(18): + mod = (not test and ( (bits >> i) & 1) == 1) + self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = mod; + + for i in range(18): + mod = (not test and ( (bits >> i) & 1) == 1) + self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = mod; + + def setupTypeInfo(self, test, maskPattern): + + data = (self.errorCorrectLevel << 3) | maskPattern + bits = QRUtil.getBCHTypeInfo(data) + + #// vertical + for i in range(15): + + mod = (not test and ( (bits >> i) & 1) == 1) + + if (i < 6): + self.modules[i][8] = mod + elif (i < 8): + self.modules[i + 1][8] = mod + else: + self.modules[self.moduleCount - 15 + i][8] = mod + + #// horizontal + for i in range(15): + + mod = (not test and ( (bits >> i) & 1) == 1); + + if (i < 8): + self.modules[8][self.moduleCount - i - 1] = mod + elif (i < 9): + self.modules[8][15 - i - 1 + 1] = mod + else: + self.modules[8][15 - i - 1] = mod + + #// fixed module + self.modules[self.moduleCount - 8][8] = (not test) + + def mapData(self, data, maskPattern): + + inc = -1 + row = self.moduleCount - 1 + bitIndex = 7 + byteIndex = 0 + + for col in range(self.moduleCount - 1, 0, -2): + + if (col == 6): col-=1 + + while (True): + + for c in range(2): + + if (self.modules[row][col - c] == None): + + dark = False + + if (byteIndex < len(data)): + dark = ( ( (data[byteIndex] >> bitIndex) & 1) == 1) + + mask = QRUtil.getMask(maskPattern, row, col - c) + + if (mask): + dark = not dark + + self.modules[row][col - c] = dark + bitIndex-=1 + + if (bitIndex == -1): + byteIndex+=1 + bitIndex = 7 + + row += inc + + if (row < 0 or self.moduleCount <= row): + row -= inc + inc = -inc + break + PAD0 = 0xEC + PAD1 = 0x11 + + @staticmethod + def autoNumber(errorCorrectLevel, dataList): + + for tn in range (1, 40): + + rsBlocks = QRRSBlock.getRSBlocks(tn, errorCorrectLevel) + + buffer = QRBitBuffer(); + + for i in range(len(dataList)): + data = dataList[i] + buffer.put(data.mode, 4) + buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, tn) ) + data.write(buffer) + + #// calc num max data. + totalDataCount = 0; + for i in range(len(rsBlocks)): + totalDataCount += rsBlocks[i].dataCount + + if (buffer.getLengthInBits() <= totalDataCount * 8): + return tn + + inkex.errormsg("Even the largest size won't take this much data (" + + str(buffer.getLengthInBits()) + + ">" + + str(totalDataCount * 8) + + ")") + sys.exit() + + + + @staticmethod + def createData(typeNumber, errorCorrectLevel, dataList): + + rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel) + + buffer = QRBitBuffer(); + + for i in range(len(dataList)): + data = dataList[i] + buffer.put(data.mode, 4) + buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) ) + data.write(buffer) + + #// calc num max data. + totalDataCount = 0; + for i in range(len(rsBlocks)): + totalDataCount += rsBlocks[i].dataCount + + if (buffer.getLengthInBits() > totalDataCount * 8): + inkex.errormsg("Text is too long for this size (" + + str(buffer.getLengthInBits()) + + ">" + + str(totalDataCount * 8) + + ")") + sys.exit() + + #// end code + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8): + buffer.put(0, 4) + + #// padding + while (buffer.getLengthInBits() % 8 != 0): + buffer.putBit(False) + + #// padding + while (True): + + if (buffer.getLengthInBits() >= totalDataCount * 8): + break + buffer.put(QRCode.PAD0, 8) + + if (buffer.getLengthInBits() >= totalDataCount * 8): + break + buffer.put(QRCode.PAD1, 8) + + return QRCode.createBytes(buffer, rsBlocks) + + @staticmethod + def createBytes(buffer, rsBlocks): + + offset = 0 + + maxDcCount = 0 + maxEcCount = 0 + + dcdata = [0 for x in range(len(rsBlocks))] + ecdata = [0 for x in range(len(rsBlocks))] + + for r in range(len(rsBlocks)): + + dcCount = rsBlocks[r].dataCount + ecCount = rsBlocks[r].totalCount - dcCount + + maxDcCount = max(maxDcCount, dcCount) + maxEcCount = max(maxEcCount, ecCount) + + dcdata[r] = [0 for x in range(dcCount)] + + for i in range(len(dcdata[r])): + dcdata[r][i] = 0xff & buffer.buffer[i + offset] + offset += dcCount + + rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount) + rawPoly = QRPolynomial(dcdata[r], rsPoly.getLength() - 1) + + modPoly = rawPoly.mod(rsPoly) + ecdata[r] = [0 for x in range(rsPoly.getLength()-1)] + for i in range(len(ecdata[r])): + modIndex = i + modPoly.getLength() - len(ecdata[r]) + if (modIndex >= 0): + ecdata[r][i] = modPoly.get(modIndex) + else: + ecdata[r][i] = 0 + + totalCodeCount = 0 + for i in range(len(rsBlocks)): + totalCodeCount += rsBlocks[i].totalCount + + data = [None for x in range(totalCodeCount)] + index = 0 + + for i in range(maxDcCount): + for r in range(len(rsBlocks)): + if (i < len(dcdata[r])): + data[index] = dcdata[r][i] + index+=1 + + for i in range(maxEcCount): + for r in range(len(rsBlocks)): + if (i < len(ecdata[r])): + data[index] = ecdata[r][i] + index+=1 + + return data + + +class QRMode: + MODE_NUMBER = 1 << 0 + MODE_ALPHA_NUM = 1 << 1 + MODE_8BIT_BYTE = 1 << 2 + MODE_KANJI = 1 << 3 + +class QRErrorCorrectLevel: + L = 1 + M = 0 + Q = 3 + H = 2 + +class QRMaskPattern: + PATTERN000 = 0 + PATTERN001 = 1 + PATTERN010 = 2 + PATTERN011 = 3 + PATTERN100 = 4 + PATTERN101 = 5 + PATTERN110 = 6 + PATTERN111 = 7 + +class QRUtil(object): + PATTERN_POSITION_TABLE = [ + [], + [6, 18], + [6, 22], + [6, 26], + [6, 30], + [6, 34], + [6, 22, 38], + [6, 24, 42], + [6, 26, 46], + [6, 28, 50], + [6, 30, 54], + [6, 32, 58], + [6, 34, 62], + [6, 26, 46, 66], + [6, 26, 48, 70], + [6, 26, 50, 74], + [6, 30, 54, 78], + [6, 30, 56, 82], + [6, 30, 58, 86], + [6, 34, 62, 90], + [6, 28, 50, 72, 94], + [6, 26, 50, 74, 98], + [6, 30, 54, 78, 102], + [6, 28, 54, 80, 106], + [6, 32, 58, 84, 110], + [6, 30, 58, 86, 114], + [6, 34, 62, 90, 118], + [6, 26, 50, 74, 98, 122], + [6, 30, 54, 78, 102, 126], + [6, 26, 52, 78, 104, 130], + [6, 30, 56, 82, 108, 134], + [6, 34, 60, 86, 112, 138], + [6, 30, 58, 86, 114, 142], + [6, 34, 62, 90, 118, 146], + [6, 30, 54, 78, 102, 126, 150], + [6, 24, 50, 76, 102, 128, 154], + [6, 28, 54, 80, 106, 132, 158], + [6, 32, 58, 84, 110, 136, 162], + [6, 26, 54, 82, 110, 138, 166], + [6, 30, 58, 86, 114, 142, 170] + ] + + G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0) + G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0) + G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1) + + @staticmethod + def getBCHTypeInfo(data): + d = data << 10; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0): + d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) ) + + return ( (data << 10) | d) ^ QRUtil.G15_MASK + @staticmethod + def getBCHTypeNumber(data): + d = data << 12; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0): + d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) ) + return (data << 12) | d + @staticmethod + def getBCHDigit(data): + digit = 0; + while (data != 0): + digit += 1 + data >>= 1 + return digit + @staticmethod + def getPatternPosition(typeNumber): + return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1] + @staticmethod + def getMask(maskPattern, i, j): + if maskPattern == QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0 + if maskPattern == QRMaskPattern.PATTERN001 : return i % 2 == 0 + if maskPattern == QRMaskPattern.PATTERN010 : return j % 3 == 0 + if maskPattern == QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0 + if maskPattern == QRMaskPattern.PATTERN100 : return (math.floor(i / 2) + math.floor(j / 3) ) % 2 == 0 + if maskPattern == QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0 + if maskPattern == QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0 + if maskPattern == QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0 + raise Exception("bad maskPattern:" + maskPattern); + @staticmethod + def getErrorCorrectPolynomial(errorCorrectLength): + a = QRPolynomial([1], 0); + for i in range(errorCorrectLength): + a = a.multiply(QRPolynomial([1, QRMath.gexp(i)], 0) ) + return a + @staticmethod + def getLengthInBits(mode, type): + + if 1 <= type and type < 10: + + #// 1 - 9 + + if mode == QRMode.MODE_NUMBER : return 10 + if mode == QRMode.MODE_ALPHA_NUM : return 9 + if mode == QRMode.MODE_8BIT_BYTE : return 8 + if mode == QRMode.MODE_KANJI : return 8 + raise Exception("mode:" + mode) + + elif (type < 27): + + #// 10 - 26 + + if mode == QRMode.MODE_NUMBER : return 12 + if mode == QRMode.MODE_ALPHA_NUM : return 11 + if mode == QRMode.MODE_8BIT_BYTE : return 16 + if mode == QRMode.MODE_KANJI : return 10 + raise Exception("mode:" + mode) + + elif (type < 41): + + #// 27 - 40 + + if mode == QRMode.MODE_NUMBER : return 14 + if mode == QRMode.MODE_ALPHA_NUM : return 13 + if mode == QRMode.MODE_8BIT_BYTE : return 16 + if mode == QRMode.MODE_KANJI : return 12 + raise Exception("mode:" + mode) + + else: + raise Exception("type:" + type) + @staticmethod + def getLostPoint(qrCode): + + moduleCount = qrCode.getModuleCount(); + + lostPoint = 0; + + #// LEVEL1 + + for row in range(moduleCount): + + for col in range(moduleCount): + + sameCount = 0; + dark = qrCode.isDark(row, col); + + for r in range(-1, 2): + + if (row + r < 0 or moduleCount <= row + r): + continue + + for c in range(-1, 2): + + if (col + c < 0 or moduleCount <= col + c): + continue + if (r == 0 and c == 0): + continue + + if (dark == qrCode.isDark(row + r, col + c) ): + sameCount+=1 + if (sameCount > 5): + lostPoint += (3 + sameCount - 5) + + #// LEVEL2 + + for row in range(moduleCount - 1): + for col in range(moduleCount - 1): + count = 0; + if (qrCode.isDark(row, col ) ): count+=1 + if (qrCode.isDark(row + 1, col ) ): count+=1 + if (qrCode.isDark(row, col + 1) ): count+=1 + if (qrCode.isDark(row + 1, col + 1) ): count+=1 + if (count == 0 or count == 4): + lostPoint += 3 + + #// LEVEL3 + + for row in range(moduleCount): + for col in range(moduleCount - 6): + if (qrCode.isDark(row, col) + and not qrCode.isDark(row, col + 1) + and qrCode.isDark(row, col + 2) + and qrCode.isDark(row, col + 3) + and qrCode.isDark(row, col + 4) + and not qrCode.isDark(row, col + 5) + and qrCode.isDark(row, col + 6) ): + lostPoint += 40 + + for col in range(moduleCount): + for row in range(moduleCount - 6): + if (qrCode.isDark(row, col) + and not qrCode.isDark(row + 1, col) + and qrCode.isDark(row + 2, col) + and qrCode.isDark(row + 3, col) + and qrCode.isDark(row + 4, col) + and not qrCode.isDark(row + 5, col) + and qrCode.isDark(row + 6, col) ): + lostPoint += 40 + + #// LEVEL4 + + darkCount = 0; + + for col in range(moduleCount): + for row in range(moduleCount): + if (qrCode.isDark(row, col) ): + darkCount+=1 + + ratio = abs(100 * darkCount / moduleCount / moduleCount - 50) / 5 + lostPoint += ratio * 10 + + return lostPoint + +class QRMath: + + @staticmethod + def glog(n): + if (n < 1): + raise Exception("glog(" + n + ")") + return LOG_TABLE[n]; + @staticmethod + def gexp(n): + while n < 0: + n += 255 + while n >= 256: + n -= 255 + return EXP_TABLE[n]; + +EXP_TABLE = [x for x in range(256)] + +LOG_TABLE = [x for x in range(256)] + +for i in range(8): + EXP_TABLE[i] = 1 << i; + +for i in range(8, 256): + EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8] + +for i in range(255): + LOG_TABLE[EXP_TABLE[i] ] = i + +class QRPolynomial: + + def __init__(self, num, shift): + + if (len(num) == 0): + raise Exception(num.length + "/" + shift) + + offset = 0 + + while offset < len(num) and num[offset] == 0: + offset += 1 + + self.num = [0 for x in range(len(num)-offset+shift)] + for i in range(len(num) - offset): + self.num[i] = num[i + offset] + + + def get(self, index): + return self.num[index] + def getLength(self): + return len(self.num) + def multiply(self, e): + num = [0 for x in range(self.getLength() + e.getLength() - 1)]; + + for i in range(self.getLength()): + for j in range(e.getLength()): + num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) + QRMath.glog(e.get(j) ) ) + + return QRPolynomial(num, 0); + def mod(self, e): + + if (self.getLength() - e.getLength() < 0): + return self; + + ratio = QRMath.glog(self.get(0) ) - QRMath.glog(e.get(0) ) + + num = [0 for x in range(self.getLength())] + + for i in range(self.getLength()): + num[i] = self.get(i); + + for i in range(e.getLength()): + num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio) + + # recursive call + return QRPolynomial(num, 0).mod(e); + +class QRRSBlock: + + RS_BLOCK_TABLE = [ + + #// L + #// M + #// Q + #// H + + #// 1 + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + + #// 2 + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + + #// 3 + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + + #// 4 + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + + #// 5 + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + + #// 6 + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + + #// 7 + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + + #// 8 + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + + #// 9 + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + + #// 10 + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + + # 11 + [4, 101, 81], + [1, 80, 50, 4, 81, 51], + [4, 50, 22, 4, 51, 23], + [3, 36, 12, 8, 37, 13], + + # 12 + [2, 116, 92, 2, 117, 93], + [6, 58, 36, 2, 59, 37], + [4, 46, 20, 6, 47, 21], + [7, 42, 14, 4, 43, 15], + + # 13 + [4, 133, 107], + [8, 59, 37, 1, 60, 38], + [8, 44, 20, 4, 45, 21], + [12, 33, 11, 4, 34, 12], + + # 14 + [3, 145, 115, 1, 146, 116], + [4, 64, 40, 5, 65, 41], + [11, 36, 16, 5, 37, 17], + [11, 36, 12, 5, 37, 13], + + # 15 + [5, 109, 87, 1, 110, 88], + [5, 65, 41, 5, 66, 42], + [5, 54, 24, 7, 55, 25], + [11, 36, 12], + + # 16 + [5, 122, 98, 1, 123, 99], + [7, 73, 45, 3, 74, 46], + [15, 43, 19, 2, 44, 20], + [3, 45, 15, 13, 46, 16], + + # 17 + [1, 135, 107, 5, 136, 108], + [10, 74, 46, 1, 75, 47], + [1, 50, 22, 15, 51, 23], + [2, 42, 14, 17, 43, 15], + + # 18 + [5, 150, 120, 1, 151, 121], + [9, 69, 43, 4, 70, 44], + [17, 50, 22, 1, 51, 23], + [2, 42, 14, 19, 43, 15], + + # 19 + [3, 141, 113, 4, 142, 114], + [3, 70, 44, 11, 71, 45], + [17, 47, 21, 4, 48, 22], + [9, 39, 13, 16, 40, 14], + + # 20 + [3, 135, 107, 5, 136, 108], + [3, 67, 41, 13, 68, 42], + [15, 54, 24, 5, 55, 25], + [15, 43, 15, 10, 44, 16], + + # 21 + [4, 144, 116, 4, 145, 117], + [17, 68, 42], + [17, 50, 22, 6, 51, 23], + [19, 46, 16, 6, 47, 17], + + # 22 + [2, 139, 111, 7, 140, 112], + [17, 74, 46], + [7, 54, 24, 16, 55, 25], + [34, 37, 13], + + # 23 + [4, 151, 121, 5, 152, 122], + [4, 75, 47, 14, 76, 48], + [11, 54, 24, 14, 55, 25], + [16, 45, 15, 14, 46, 16], + + # 24 + [6, 147, 117, 4, 148, 118], + [6, 73, 45, 14, 74, 46], + [11, 54, 24, 16, 55, 25], + [30, 46, 16, 2, 47, 17], + + # 25 + [8, 132, 106, 4, 133, 107], + [8, 75, 47, 13, 76, 48], + [7, 54, 24, 22, 55, 25], + [22, 45, 15, 13, 46, 16], + + # 26 + [10, 142, 114, 2, 143, 115], + [19, 74, 46, 4, 75, 47], + [28, 50, 22, 6, 51, 23], + [33, 46, 16, 4, 47, 17], + + # 27 + [8, 152, 122, 4, 153, 123], + [22, 73, 45, 3, 74, 46], + [8, 53, 23, 26, 54, 24], + [12, 45, 15, 28, 46, 16], + + # 28 + [3, 147, 117, 10, 148, 118], + [3, 73, 45, 23, 74, 46], + [4, 54, 24, 31, 55, 25], + [11, 45, 15, 31, 46, 16], + + # 29 + [7, 146, 116, 7, 147, 117], + [21, 73, 45, 7, 74, 46], + [1, 53, 23, 37, 54, 24], + [19, 45, 15, 26, 46, 16], + + # 30 + [5, 145, 115, 10, 146, 116], + [19, 75, 47, 10, 76, 48], + [15, 54, 24, 25, 55, 25], + [23, 45, 15, 25, 46, 16], + + # 31 + [13, 145, 115, 3, 146, 116], + [2, 74, 46, 29, 75, 47], + [42, 54, 24, 1, 55, 25], + [23, 45, 15, 28, 46, 16], + + # 32 + [17, 145, 115], + [10, 74, 46, 23, 75, 47], + [10, 54, 24, 35, 55, 25], + [19, 45, 15, 35, 46, 16], + + # 33 + [17, 145, 115, 1, 146, 116], + [14, 74, 46, 21, 75, 47], + [29, 54, 24, 19, 55, 25], + [11, 45, 15, 46, 46, 16], + + # 34 + [13, 145, 115, 6, 146, 116], + [14, 74, 46, 23, 75, 47], + [44, 54, 24, 7, 55, 25], + [59, 46, 16, 1, 47, 17], + + # 35 + [12, 151, 121, 7, 152, 122], + [12, 75, 47, 26, 76, 48], + [39, 54, 24, 14, 55, 25], + [22, 45, 15, 41, 46, 16], + + # 36 + [6, 151, 121, 14, 152, 122], + [6, 75, 47, 34, 76, 48], + [46, 54, 24, 10, 55, 25], + [2, 45, 15, 64, 46, 16], + + # 37 + [17, 152, 122, 4, 153, 123], + [29, 74, 46, 14, 75, 47], + [49, 54, 24, 10, 55, 25], + [24, 45, 15, 46, 46, 16], + + # 38 + [4, 152, 122, 18, 153, 123], + [13, 74, 46, 32, 75, 47], + [48, 54, 24, 14, 55, 25], + [42, 45, 15, 32, 46, 16], + + # 39 + [20, 147, 117, 4, 148, 118], + [40, 75, 47, 7, 76, 48], + [43, 54, 24, 22, 55, 25], + [10, 45, 15, 67, 46, 16], + + # 40 + [19, 148, 118, 6, 149, 119], + [18, 75, 47, 31, 76, 48], + [34, 54, 24, 34, 55, 25], + [20, 45, 15, 61, 46, 16] + + ] + + def __init__(self, totalCount, dataCount): + self.totalCount = totalCount + self.dataCount = dataCount + + @staticmethod + def getRSBlocks(typeNumber, errorCorrectLevel): + rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); + if rsBlock == None: + raise Exception("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel) + + length = len(rsBlock) / 3 + + list = [] + + for i in range(length): + + count = rsBlock[i * 3 + 0] + totalCount = rsBlock[i * 3 + 1] + dataCount = rsBlock[i * 3 + 2] + + for j in range(count): + list.append(QRRSBlock(totalCount, dataCount)) + + return list; + + @staticmethod + def getRsBlockTable(typeNumber, errorCorrectLevel): + if errorCorrectLevel == QRErrorCorrectLevel.L: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; + elif errorCorrectLevel == QRErrorCorrectLevel.M: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; + elif errorCorrectLevel == QRErrorCorrectLevel.Q: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; + elif errorCorrectLevel == QRErrorCorrectLevel.H: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; + else: + return None; + +class QRBitBuffer: + def __init__(self): + self.buffer = [] + self.length = 0 + def __repr__(self): + return ".".join([str(n) for n in self.buffer]) + def get(self, index): + bufIndex = math.floor(index / 8) + val = ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1 + print "get ", val + return ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1 + def put(self, num, length): + for i in range(length): + self.putBit( ( (num >> (length - i - 1) ) & 1) == 1) + def getLengthInBits(self): + return self.length + def putBit(self, bit): + bufIndex = self.length // 8 + if len(self.buffer) <= bufIndex: + self.buffer.append(0) + if bit: + self.buffer[bufIndex] |= (0x80 >> (self.length % 8) ) + self.length+=1 + +class QRCodeInkscape(inkex.Effect): + def __init__(self): + inkex.Effect.__init__(self) + + #PARSE OPTIONS + self.OptionParser.add_option("--text", + action="store", type="string", + dest="TEXT", default='www.inkscape.org') + self.OptionParser.add_option("--typenumber", + action="store", type="string", + dest="TYPENUMBER", default="0") + self.OptionParser.add_option("--correctionlevel", + action="store", type="string", + dest="CORRECTIONLEVEL", default="0") + self.OptionParser.add_option("--modulesize", + action="store", type="float", + dest="MODULESIZE", default=10) + + def effect(self): + + so = self.options + + if so.TEXT == '': #abort if converting blank text + inkex.errormsg(_('Please enter an input text')) + else: + + #INKSCAPE GROUP TO CONTAIN EVERYTHING + + centre = self.view_center #Put in in the centre of the current view + grp_transform = 'translate' + str( centre ) + grp_name = 'QR Code: '+so.TEXT + grp_attribs = {inkex.addNS('label','inkscape'):grp_name, + 'transform':grp_transform } + grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs) #the group to put everything in + + #GENERATE THE QRCODE + qr = QRCode(int(so.TYPENUMBER), int(so.CORRECTIONLEVEL)) + qr.addData(so.TEXT) + qr.make() + qr.makeSVG(grp, so.MODULESIZE) + +if __name__ == '__main__': + e = QRCodeInkscape() + e.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/replace_font.inx b/share/extensions/replace_font.inx new file mode 100644 index 000000000..8ec90904b --- /dev/null +++ b/share/extensions/replace_font.inx @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Replace font</_name> + <id>org.inkscape.replace_font</id> + + <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> + <dependency type="executable" location="extensions">replace_font.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + + <param name="action" type="notebook"> + <page name="find_replace" _gui-text="Find and Replace font"> + <param name="fr_find" type="string" _gui-text="Find this font: "></param> + <param name="fr_replace" type="string" _gui-text="And replace with: "></param> + </page> + <page name="replace_all" _gui-text="Replace font"> + <param name="r_replace" type="string" _gui-text="Replace all fonts with: "></param> + </page> + <page name="list_only" _gui-text="List all fonts"> + <_param name="d" type="description">Choose this tab if you would like to see a list of the fonts used/found.</_param> + </page> + </param> + + <param name="scope" type="enum" _gui-text="Work on:"> + <_item value="entire_document">Entire drawing</_item> + <_item value="selection_only">Selected objects only</_item> + </param> + + <effect needs-live-preview="false"> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Text"/> + </effects-menu> + </effect> + + <script> + <command reldir="extensions" interpreter="python">replace_font.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/replace_font.py b/share/extensions/replace_font.py new file mode 100644 index 000000000..f0f25ab8e --- /dev/null +++ b/share/extensions/replace_font.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +''' +replace_font.py + +Copyright (C) 2010 Craig Marshall, craig9 [at] gmail.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +----------------------- + +This script finds all fonts in the current drawing that match the +specified find font, and replaces them with the specified replacement +font. + +It can also replace all fonts indiscriminately, and list all fonts +currently being used. +''' + +import os +import sys +import inkex +import simplestyle +import gettext +_ = gettext.gettext + +text_tags = ['{http://www.w3.org/2000/svg}tspan', + '{http://www.w3.org/2000/svg}text', + '{http://www.w3.org/2000/svg}flowRoot', + '{http://www.w3.org/2000/svg}flowPara', + '{http://www.w3.org/2000/svg}flowSpan'] +font_attributes = ['font-family', '-inkscape-font-specification'] + +def set_font(node, new_font, style=None): + ''' + Sets the font attribute in the style attribute of node, using the + font name stored in new_font. If the style dict is open already, + it can be passed in, otherwise it will be optned anyway. + + Returns a dirty boolean flag + ''' + dirty = False + if not style: + style = get_style(node) + if style: + for att in font_attributes: + if att in style: + style[att] = new_font + set_style(node, style) + dirty = True + return dirty + +def find_replace_font(node, find, replace): + ''' + Searches the relevant font attributes/styles of node for find, and + replaces them with replace. + + Returns a dirty boolean flag + ''' + dirty = False + style = get_style(node) + if style: + for att in font_attributes: + if att in style and style[att].strip().lower() == find: + set_font(node, replace, style) + dirty = True + return dirty + +def is_styled_text(node): + ''' + Returns true if the tag in question is a "styled" element that + can hold text. + ''' + return node.tag in text_tags and 'style' in node.attrib + +def is_text(node): + ''' + Returns true if the tag in question is an element that + can hold text. + ''' + return node.tag in text_tags + + +def get_style(node): + ''' + Sugar coated way to get style dict from a node + ''' + if 'style' in node.attrib: + return simplestyle.parseStyle(node.attrib['style']) + +def set_style(node, style): + ''' + Sugar coated way to set the style dict, for node + ''' + node.attrib['style'] = simplestyle.formatStyle(style) + +def get_fonts(node): + ''' + Given a node, returns a list containing all the fonts that + the node is using. + ''' + fonts = [] + s = get_style(node) + if not s: + return fonts + for a in font_attributes: + if a in s: + fonts.append(s[a]) + return fonts + +def die(msg = "Dying!"): + inkex.errormsg(msg) + sys.exit(0) + +def report_replacements(num): + ''' + Sends a message to the end user showing success of failure + of the font replacement + ''' + if num == 0: + die(_('Couldn\'t find anything using that font, please ensure the spelling and spacing is correct.')) + +def report_findings(findings): + ''' + Tells the user which fonts were found, if any + ''' + if len(findings) == 0: + inkex.errormsg(_("Didn't find any fonts in this document/selection.")) + else: + if len(findings) == 1: + inkex.errormsg(_("Found the following font only: %s") % findings[0]) + else: + inkex.errormsg(_("Found the following fonts:\n%s") % '\n'.join(findings)) + +class ReplaceFont(inkex.Effect): + ''' + Replaces all instances of one font with another + ''' + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("--fr_find", action="store", + type="string", dest="fr_find", + default=None, help="") + + self.OptionParser.add_option("--fr_replace", action="store", + type="string", dest="fr_replace", + default=None, help="") + + self.OptionParser.add_option("--r_replace", action="store", + type="string", dest="r_replace", + default=None, help="") + + self.OptionParser.add_option("--action", action="store", + type="string", dest="action", + default=None, help="") + + self.OptionParser.add_option("--scope", action="store", + type="string", dest="scope", + default=None, help="") + + def find_child_text_items(self, node): + ''' + Recursive method for appending all text-type elements + to self.selected_items + ''' + if is_text(node): + self.selected_items.append(node) + for child in node: + self.find_child_text_items(child) + + def relevant_items(self, scope): + ''' + Depending on the scope, returns all text elements, or all + selected text elements including nested children + ''' + items = [] + to_return = [] + if scope == "selection_only": + self.selected_items = [] + for item in self.selected.iteritems(): + self.find_child_text_items(item[1]) + items = self.selected_items + if len(items) == 0: + die(_("There was nothing selected")) + else: + items = self.document.getroot().getiterator() + to_return.extend(filter(is_text, items)) + return to_return + + def find_replace(self, nodes, find, replace): + ''' + Walks through nodes, replacing fonts as it goes according + to find and replace + ''' + replacements = 0 + for node in nodes: + if find_replace_font(node, find, replace): + replacements += 1 + report_replacements(replacements) + + def replace_all(self, nodes, replace): + ''' + Walks through nodes, setting fonts indiscriminately. + ''' + replacements = 0 + for node in nodes: + if set_font(node, replace): + replacements += 1 + report_replacements(replacements) + + def list_all(self, nodes): + ''' + Walks through nodes, building a list of all fonts found, then + reports to the user with that list + ''' + fonts_found = [] + for node in nodes: + for f in get_fonts(node): + if not f in fonts_found: + fonts_found.append(f) + report_findings(sorted(fonts_found)) + + def effect(self): + action = self.options.action.strip("\"") # TODO Is this a bug? (Extra " characters) + scope = self.options.scope + + relevant_items = self.relevant_items(scope) + + if action == "find_replace": + find = self.options.fr_find + if find is None or find == "": + die(_("Please enter a search string in the find box.")); + find = find.strip().lower() + replace = self.options.fr_replace + if replace is None or replace == "": + die(_("Please enter a replacement font in the replace with box.")); + self.find_replace(relevant_items, find, replace) + elif action == "replace_all": + replace = self.options.r_replace + if replace is None or replace == "": + die(_("Please enter a replacement font in the replace all box.")); + self.replace_all(relevant_items, replace) + elif action == "list_only": + self.list_all(relevant_items) + sys.exit(0) + +if __name__ == "__main__": + e = ReplaceFont() + e.affect() diff --git a/share/extensions/restack.inx b/share/extensions/restack.inx index 07d222a16..67f0f777a 100644 --- a/share/extensions/restack.inx +++ b/share/extensions/restack.inx @@ -4,25 +4,25 @@ <id>org.inkscape.filter.restack</id> <dependency type="executable" location="extensions">restack.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="direction" type="optiongroup" appearance="minimal" _gui-text="Restack Direction:"> - <_option value="lr">Left to Right (0)</_option> - <_option value="bt">Bottom to Top (90)</_option> - <_option value="rl">Right to Left (180)</_option> - <_option value="tb">Top to Bottom (270)</_option> - <_option value="ro">Radial Outward</_option> - <_option value="ri">Radial Inward</_option> - <_option value="aa">Arbitrary Angle:</_option> + <param name="direction" type="enum" _gui-text="Restack Direction:"> + <_item value="lr">Left to Right (0)</_item> + <_item value="bt">Bottom to Top (90)</_item> + <_item value="rl">Right to Left (180)</_item> + <_item value="tb">Top to Bottom (270)</_item> + <_item value="ro">Radial Outward</_item> + <_item value="ri">Radial Inward</_item> + <_item value="aa">Arbitrary Angle</_item> </param> - <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Angle">0.00</param> - <param name="xanchor" type="optiongroup" appearance="minimal" _gui-text="Horizontal Point:"> - <_option value="l">Left</_option> - <_option value="m">Middle</_option> - <_option value="r">Right</_option> + <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Angle:">0.00</param> + <param name="xanchor" type="enum" _gui-text="Horizontal Point:"> + <_item value="l">Left</_item> + <_item value="m">Middle</_item> + <_item value="r">Right</_item> </param> - <param name="yanchor" type="optiongroup" appearance="minimal" _gui-text="Vertical Point:"> - <_option value="t">Top</_option> - <_option value="m">Middle</_option> - <_option value="b">Bottom</_option> + <param name="yanchor" type="enum" _gui-text="Vertical Point:"> + <_item value="t">Top</_item> + <_item value="m">Middle</_item> + <_item value="b">Bottom</_item> </param> <effect> <object-type>path</object-type> diff --git a/share/extensions/restack.py b/share/extensions/restack.py index 139f783b2..518c1b10e 100644 --- a/share/extensions/restack.py +++ b/share/extensions/restack.py @@ -143,4 +143,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/rtree.inx b/share/extensions/rtree.inx index fec2a4bec..5fcac5560 100644 --- a/share/extensions/rtree.inx +++ b/share/extensions/rtree.inx @@ -4,8 +4,8 @@ <id>org.ekips.filter.turtle.rtree</id> <dependency type="executable" location="extensions">rtree.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="size" type="float" min="0.0" max="1000.0" _gui-text="Initial size">100.0</param> - <param name="minimum" type="float" min="0.0" max="500.0" _gui-text="Minimum size">40.0</param> + <param name="size" type="float" min="0.0" max="1000.0" _gui-text="Initial size:">100.0</param> + <param name="minimum" type="float" min="0.0" max="500.0" _gui-text="Minimum size:">40.0</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/rtree.py b/share/extensions/rtree.py index ddd0078d0..3231d284e 100755 --- a/share/extensions/rtree.py +++ b/share/extensions/rtree.py @@ -62,4 +62,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/rubberstretch.py b/share/extensions/rubberstretch.py index 5426ea3c9..95d1cffb5 100644 --- a/share/extensions/rubberstretch.py +++ b/share/extensions/rubberstretch.py @@ -78,4 +78,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/run_command.py b/share/extensions/run_command.py index f688444d6..7012c4274 100644 --- a/share/extensions/run_command.py +++ b/share/extensions/run_command.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import os import sys import tempfile @@ -92,4 +93,4 @@ def run(command_format, prog_name): sys.exit(0) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/scour.inkscape.py b/share/extensions/scour.inkscape.py index f21e223a0..69c2dda5d 100755 --- a/share/extensions/scour.inkscape.py +++ b/share/extensions/scour.inkscape.py @@ -43,7 +43,7 @@ class ScourInkscape (inkex.Effect): def effect(self): - input = file(sys.argv[12], "r") + input = file(self.args[0], "r") sys.stdout.write(scourString(input.read(), self.options).encode("UTF-8")) input.close() sys.stdout.close() diff --git a/share/extensions/simplepath.py b/share/extensions/simplepath.py index f62b1b4b3..94ab09242 100755 --- a/share/extensions/simplepath.py +++ b/share/extensions/simplepath.py @@ -209,4 +209,4 @@ def rotatePath(p, a, cx = 0, cy = 0): params[i + 1] = (r * math.sin(theta)) + cy -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/simplestyle.py b/share/extensions/simplestyle.py index e312d3cef..feb0b0bcd 100755 --- a/share/extensions/simplestyle.py +++ b/share/extensions/simplestyle.py @@ -231,4 +231,4 @@ def formatColor3f(r,g,b): return '#%02x%02x%02x' % (int(round(r*255)),int(round(g*255)),int(round(b*255))) -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/simpletransform.py b/share/extensions/simpletransform.py index 08aa4c55f..8f8a811dc 100644 --- a/share/extensions/simpletransform.py +++ b/share/extensions/simpletransform.py @@ -230,4 +230,4 @@ def computeBBox(aList,mat=[[1,0,0],[0,1,0]]): return bbox -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/sk1_output.py b/share/extensions/sk1_output.py index fd85f7740..5ad2eaccc 100644 --- a/share/extensions/sk1_output.py +++ b/share/extensions/sk1_output.py @@ -27,4 +27,4 @@ from uniconv_output import run, get_command cmd = get_command() run((cmd + ' "%s" ') % sys.argv[1], "UniConvertor", ".sk1") -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
\ No newline at end of file +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
\ No newline at end of file diff --git a/share/extensions/spirograph.inx b/share/extensions/spirograph.inx index 84e13c5d6..612643336 100644 --- a/share/extensions/spirograph.inx +++ b/share/extensions/spirograph.inx @@ -4,15 +4,15 @@ <id>org.ekips.filter.spirograph</id> <dependency type="executable" location="extensions">spirograph.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="primaryr" type="float" min="0.0" max="1000.0" _gui-text="R - Ring Radius (px)">100.0</param> - <param name="secondaryr" type="float" min="0.0" max="1000.0" _gui-text="r - Gear Radius (px)">60.0</param> - <param name="penr" type="float" min="0.0" max="1000.0" _gui-text="d - Pen Radius (px)">50.0</param> - <param name="gearplacement" type="optiongroup" _gui-text="Gear Placement"> - <_option value="inside">Inside (Hypotrochoid)</_option> - <_option value="outside">Outside (Epitrochoid)</_option> + <param name="primaryr" type="float" min="0.0" max="1000.0" _gui-text="R - Ring Radius (px):">100.0</param> + <param name="secondaryr" type="float" min="0.0" max="1000.0" _gui-text="r - Gear Radius (px):">60.0</param> + <param name="penr" type="float" min="0.0" max="1000.0" _gui-text="d - Pen Radius (px):">50.0</param> + <param name="gearplacement" type="enum" _gui-text="Gear Placement:"> + <_item value="inside">Inside (Hypotrochoid)</_item> + <_item value="outside">Outside (Epitrochoid)</_item> </param> - <param name="rotation" type="float" min="-360.0" max="360.0" _gui-text="Rotation (deg)">0.0</param> - <param name="quality" type="int" min="1" max="100" _gui-text="Quality (Default = 16)">16</param> + <param name="rotation" type="float" min="-360.0" max="360.0" _gui-text="Rotation (deg):">0.0</param> + <param name="quality" type="int" min="1" max="100" _gui-text="Quality (Default = 16):">16</param> <effect> <object-type>all</object-type> <effects-menu> diff --git a/share/extensions/spirograph.py b/share/extensions/spirograph.py index 9dbf0dcea..21249831f 100644 --- a/share/extensions/spirograph.py +++ b/share/extensions/spirograph.py @@ -113,4 +113,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/split.inx b/share/extensions/split.inx index ced0cf495..12e443011 100644 --- a/share/extensions/split.inx +++ b/share/extensions/split.inx @@ -4,13 +4,19 @@ <id>com.nerdson.split</id> <dependency type="executable" location="extensions">split.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="texthelp" type="description">This effect splits texts into different lines, words or letters. Select below how your text should be splitted.</_param> - <param name="splittype" type="enum" _gui-text="Split:"> - <_item value="line">Lines</_item> - <_item value="word">Words</_item> - <_item value="letter">Letters</_item> - </param> - <param name="preserve" type="boolean" _gui-text="Preserve original text?">true</param> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="splittype" type="enum" _gui-text="Split:"> + <_item msgctxt="split" value="line">Lines</_item> + <_item msgctxt="split" value="word">Words</_item> + <_item msgctxt="split" value="letter">Letters</_item> + </param> + <param name="preserve" type="boolean" _gui-text="Preserve original text">true</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="texthelp" type="description">This effect splits texts into different lines, words or letters.</_param> + </page> + </param> <effect> <object-type>text</object-type> <effects-menu> diff --git a/share/extensions/split.py b/share/extensions/split.py index 5e9de002b..0cbc7b05b 100644 --- a/share/extensions/split.py +++ b/share/extensions/split.py @@ -30,7 +30,10 @@ class Split(inkex.Effect): action="store", type="inkbool", dest="preserve", default="True", help="Preserve original") - + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def split_lines(self, node): """Returns a list of lines""" diff --git a/share/extensions/straightseg.inx b/share/extensions/straightseg.inx index 965b33086..45014c879 100644 --- a/share/extensions/straightseg.inx +++ b/share/extensions/straightseg.inx @@ -4,13 +4,13 @@ <id>org.ekips.filter.straightseg</id> <dependency type="executable" location="extensions">straightseg.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="percent" type="float" min="0.0" max="100.0" _gui-text="Percent">50.0</param> - <param name="behavior" type="int" min="1" max="2" _gui-text="Behavior">1</param> + <param name="percent" type="float" min="0.0" max="100.0" _gui-text="Percent:">50.0</param> + <param name="behavior" type="int" min="1" max="2" _gui-text="Behavior:">1</param> <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> + <object-type>path</object-type> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">straightseg.py</command> diff --git a/share/extensions/straightseg.py b/share/extensions/straightseg.py index 16db996fc..f18658012 100755 --- a/share/extensions/straightseg.py +++ b/share/extensions/straightseg.py @@ -70,4 +70,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/summersnight.py b/share/extensions/summersnight.py index f14b400cd..7f4ffb1b0 100755 --- a/share/extensions/summersnight.py +++ b/share/extensions/summersnight.py @@ -121,4 +121,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/svg2xaml.xsl b/share/extensions/svg2xaml.xsl index cda6c7a97..1c663c11c 100755 --- a/share/extensions/svg2xaml.xsl +++ b/share/extensions/svg2xaml.xsl @@ -1,1483 +1,1483 @@ -<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Copyright (c) 2005-2007 authors:
-Original version: Toine de Greef (a.degreef@chello.nl)
-Modified (2010) by Nicolas Dufour (nicoduf@yahoo.fr) (blur support, units
-convertion, comments, and some other fixes)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
--->
-
-<xsl:stylesheet version="1.0"
-xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-xmlns:xlink="http://www.w3.org/1999/xlink"
-xmlns:xs="http://www.w3.org/2001/XMLSchema"
-xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-xmlns:exsl="http://exslt.org/common"
-xmlns:libxslt="http://xmlsoft.org/XSLT/namespace"
-exclude-result-prefixes="rdf xlink xs exsl libxslt">
-
-<xsl:strip-space elements="*" />
-<xsl:output method="xml" encoding="UTF-8"/>
-
-<xsl:param name="silverlight_compatible" select="1" />
-
-<!-- Root template.
-Everything starts here! -->
-<xsl:template match="/">
- <xsl:choose>
- <xsl:when test="$silverlight_compatible = 1">
- <xsl:apply-templates mode="forward" />
- </xsl:when>
- <xsl:otherwise>
- <Viewbox Stretch="Uniform">
- <xsl:apply-templates mode="forward" />
- </Viewbox>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- SVG and groups
-(including layers) -->
-<xsl:template mode="forward" match="*[name(.) = 'svg' or name(.) = 'g']">
- <xsl:choose>
- <xsl:when test="name(.) = 'svg' or @transform or @viewBox or @id or @clip-path or (@style and contains(@style, 'clip-path:url(#')) or (@width and not(contains(@width, '%'))) or @x or @y or (@height and not(contains(@height, '%'))) or *[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']">
- <Canvas>
- <xsl:apply-templates mode="id" select="." />
- <!--
- <xsl:apply-templates mode="clip" select="." />
- -->
- <xsl:if test="@style and contains(@style, 'display:none')"><xsl:attribute name="Visibility">Collapsed</xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'opacity:')">
- <xsl:attribute name="Opacity">
- <xsl:choose>
- <xsl:when test="contains(substring-after(@style, 'opacity:'), ';')"><xsl:value-of select="substring-before(substring-after(@style, 'opacity:'), ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="substring-after(@style, 'opacity:')" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@width and not(contains(@width, '%'))">
- <xsl:attribute name="Width">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@width" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@height and not(contains(@height, '%'))">
- <xsl:attribute name="Height">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@height" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@x">
- <xsl:attribute name="Canvas.Left">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@x" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@y">
- <xsl:attribute name="Canvas.Top">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@y" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@viewBox">
- <xsl:variable name="viewBox"><xsl:value-of select="normalize-space(translate(@viewBox, ',', ' '))" /></xsl:variable>
- <xsl:attribute name="Width"><xsl:value-of select="substring-before(substring-after(substring-after($viewBox, ' '), ' '), ' ')" /></xsl:attribute>
- <xsl:attribute name="Height"><xsl:value-of select="substring-after(substring-after(substring-after($viewBox, ' '), ' '), ' ')" /></xsl:attribute>
- <Canvas.RenderTransform>
- <TranslateTransform>
- <xsl:attribute name="X"><xsl:value-of select="-number(substring-before($viewBox, ' '))" /></xsl:attribute>
- <xsl:attribute name="Y"><xsl:value-of select="-number(substring-before(substring-after($viewBox, ' '), ' '))" /></xsl:attribute>
- </TranslateTransform>
- </Canvas.RenderTransform>
- </xsl:if>
- <xsl:if test="@transform">
- <Canvas>
- <Canvas.RenderTransform>
- <TransformGroup><xsl:apply-templates mode="transform" select="." /></TransformGroup>
- </Canvas.RenderTransform>
- <xsl:apply-templates mode="forward" select="*" />
- </Canvas>
- </xsl:if>
-
- <xsl:if test="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']">
- <Canvas.Resources>
- <xsl:apply-templates mode="forward" select="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']" />
- </Canvas.Resources>
- </xsl:if>
- <xsl:if test="not(@transform)">
- <xsl:apply-templates mode="forward" select="*[name(.) != 'linearGradient' and name(.) != 'radialGradient' and name(.) != 'defs' and name(.) != 'clipPath']" />
- </xsl:if>
- </Canvas>
- </xsl:when>
- <xsl:when test="not(@transform)">
- <xsl:apply-templates mode="forward" select="*" />
- </xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!--
-// Resources (defs) //
-
-* Resources ids
-* Generic defs template
-* Generic filters template
-* Filter effects
-* Linked filter effects
-* Linear gradients
-* Radial gradients
-* Generic gradient stops
-* Clipping
--->
-
-<!-- Resources ids -->
-<xsl:template mode="resources" match="*">
- <!-- should be in-depth -->
- <xsl:if test="ancestor::*[name(.) = 'defs']"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if>
-</xsl:template>
-
-<!-- Generic defs template -->
-<xsl:template mode="forward" match="defs">
- <xsl:apply-templates mode="forward" />
-</xsl:template>
-
-<!-- Generic filters template
-Limited to one filter (can be improved) -->
-<xsl:template mode="forward" match="*[name(.) = 'filter']">
- <xsl:if test="count(*) = 1">
- <xsl:apply-templates mode="forward" />
- </xsl:if>
-</xsl:template>
-
-<!-- Filter effects -->
-<xsl:template mode="forward" match="*[name(.) = 'feGaussianBlur']">
- <BlurEffect>
- <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if>
- <xsl:if test="@stdDeviation"><xsl:attribute name="Radius"><xsl:value-of select="round(@stdDeviation * 3)" /></xsl:attribute></xsl:if>
- </BlurEffect>
-</xsl:template>
-
-<!-- Linked filter effect -->
-<xsl:template mode="filter_effect" match="*">
-<xsl:choose>
- <xsl:when test="@filter and starts-with(@filter, 'url(#')">
- <xsl:attribute name="Effect">
- <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@filter, 'url(#'), ')'), '}')" />
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="@style and contains(@style, 'filter:url(#')">
- <xsl:attribute name="Effect">
- <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'filter:url(#'), ')'), '}')" />
- </xsl:attribute>
- </xsl:when>
-</xsl:choose>
-</xsl:template>
-
-<!-- Linear gradient -->
-<xsl:template mode="forward" match="*[name(.) = 'linearGradient']">
- <LinearGradientBrush>
- <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if>
- <xsl:attribute name="MappingMode">
- <xsl:choose>
- <xsl:when test="@gradientUnits = 'userSpaceOnUse' ">Absolute</xsl:when>
- <xsl:otherwise>RelativeToBoundingBox</xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- <xsl:if test="@spreadMethod">
- <xsl:attribute name="SpreadMethod">
- <xsl:choose>
- <xsl:when test="@spreadMethod = 'pad'">Pad</xsl:when>
- <xsl:when test="@spreadMethod = 'reflect'">Reflect</xsl:when>
- <xsl:when test="@spreadMethod = 'repeat'">Repeat</xsl:when>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:choose>
- <xsl:when test="@x1 and @y1 and @x2 and @y2">
- <xsl:choose>
- <xsl:when test="contains(@x1, '%') and contains(@y1, '%')">
- <xsl:attribute name="StartPoint"><xsl:value-of select="concat(substring-before(@x1, '%') div 100, ',', substring-before(@y1,'%') div 100)" /></xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="StartPoint"><xsl:value-of select="concat(@x1, ',', @y1)" /></xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- <xsl:choose>
- <xsl:when test="contains(@x2, '%') and contains(@y2, '%')">
- <xsl:attribute name="EndPoint"><xsl:value-of select="concat(substring-before(@x2, '%') div 100, ',', substring-before(@y2,'%') div 100)" /></xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="EndPoint"><xsl:value-of select="concat(@x2, ',', @y2)" /></xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="StartPoint"><xsl:value-of select="'0,0'" /></xsl:attribute>
- <xsl:attribute name="EndPoint"><xsl:value-of select="'1,1'" /></xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- <LinearGradientBrush.GradientStops>
- <GradientStopCollection>
- <xsl:choose>
- <xsl:when test="@xlink:href">
- <xsl:variable name="reference_id" select="@xlink:href" />
- <xsl:apply-templates mode="forward" select="//*[name(.) = 'linearGradient' and $reference_id = concat('#', @id)]/*" />
- </xsl:when>
- <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise>
- </xsl:choose>
- </GradientStopCollection>
- </LinearGradientBrush.GradientStops>
- <xsl:if test="@gradientTransform">
- <LinearGradientBrush.Transform>
- <xsl:apply-templates mode="transform" select="." />
- </LinearGradientBrush.Transform>
- </xsl:if>
- </LinearGradientBrush>
-</xsl:template>
-
-<!-- Radial gradient -->
-<xsl:template mode="forward" match="*[name(.) = 'radialGradient']">
- <RadialGradientBrush>
- <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if>
- <xsl:attribute name="MappingMode">
- <xsl:choose>
- <xsl:when test="@gradientUnits = 'userSpaceOnUse' ">Absolute</xsl:when>
- <xsl:otherwise>RelativeToBoundingBox</xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- <xsl:if test="@spreadMethod">
- <xsl:attribute name="SpreadMethod">
- <xsl:choose>
- <xsl:when test="@spreadMethod = 'pad'">Pad</xsl:when>
- <xsl:when test="@spreadMethod = 'reflect'">Reflect</xsl:when>
- <xsl:when test="@spreadMethod = 'repeat'">Repeat</xsl:when>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@cx and @cy">
- <xsl:attribute name="Center">
- <xsl:choose>
- <xsl:when test="contains(@cx, '%') and contains(@cy, '%')">
- <xsl:value-of select="concat(number(substring-before(@cx, '%')) div 100, ',', number(substring-before(@cy, '%')) div 100)" />
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="concat(@cx, ',', @cy)" />
- </xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@fx and @fy">
- <xsl:attribute name="GradientOrigin">
- <xsl:choose>
- <xsl:when test="contains(@fx, '%') and contains(@fy, '%')">
- <xsl:value-of select="concat(number(substring-before(@fx, '%')) div 100, ',', number(substring-before(@fy, '%')) div 100)" />
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="concat(@fx, ',', @fy)" />
- </xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@r">
- <xsl:choose>
- <xsl:when test="contains(@r, '%')">
- <xsl:attribute name="RadiusX"><xsl:value-of select="number(substring-before(@r, '%')) div 100" /></xsl:attribute>
- <xsl:attribute name="RadiusY"><xsl:value-of select="number(substring-before(@r, '%')) div 100" /></xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="RadiusX"><xsl:value-of select="@r" /></xsl:attribute>
- <xsl:attribute name="RadiusY"><xsl:value-of select="@r" /></xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:if>
- <RadialGradientBrush.GradientStops>
- <GradientStopCollection>
- <xsl:choose>
- <xsl:when test="@xlink:href">
- <xsl:variable name="reference_id" select="@xlink:href" />
- <xsl:apply-templates mode="forward" select="//*[name(.) = 'linearGradient' and $reference_id = concat('#', @id)]/*" />
- </xsl:when>
- <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise>
- </xsl:choose>
- </GradientStopCollection>
- </RadialGradientBrush.GradientStops>
- <xsl:if test="@gradientTransform">
- <RadialGradientBrush.Transform>
- <xsl:apply-templates mode="transform" select="." />
- </RadialGradientBrush.Transform>
- </xsl:if>
- </RadialGradientBrush>
-</xsl:template>
-
-<!-- Generic gradient stops -->
-<xsl:template mode="forward" match="*[name(.) = 'stop']">
- <GradientStop>
- <!--xsl:apply-templates mode="stop_opacity" select="." /-->
- <xsl:apply-templates mode="stop_color" select="." />
- <xsl:apply-templates mode="offset" select="." />
- <xsl:apply-templates mode="forward" />
- </GradientStop>
-</xsl:template>
-
-<!-- Clipping -->
-<xsl:template mode="clip" match="*">
- <xsl:choose>
- <xsl:when test="@clip-path and defs/clipPath/path/@d"><xsl:attribute name="Clip"><xsl:value-of select="defs/clipPath/path/@d" /></xsl:attribute></xsl:when>
- <xsl:when test="@clip-path and starts-with(@clip-path, 'url(#')"><xsl:attribute name="Clip"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@clip-path, 'url(#'), ')'), '}')" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'clip-path:url(#')"><xsl:attribute name="Clip"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:attribute></xsl:when>
- <xsl:when test="clipPath"><xsl:apply-templates mode="forward" /></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!--
-// Misc templates //
-
-* Object description
-* Id converter
-* Decimal to hexadecimal converter
-* Unit to pixel converter
-* Title and description
-* Misc ignored stuff (markers, patterns, styles)
-* Symbols
-* Use
-* RDF and foreign objects
-* Unknows tags
--->
-
-<!-- Object description -->
-<xsl:template mode="desc" match="*">
- <xsl:if test="*[name(.) = 'desc']/text()"><xsl:attribute name="Tag"><xsl:value-of select="*[name(.) = 'desc']/text()" /></xsl:attribute></xsl:if>
-</xsl:template>
-
-<!-- Id converter. Removes "-" from the original id. -->
-<xsl:template mode="id" match="*">
-<xsl:if test="@id">
- <xsl:attribute name="Name"><xsl:value-of select="translate(@id, '- ', '')" /></xsl:attribute>
- <!--
- <xsl:attribute name="x:Key"><xsl:value-of select="translate(@id, '- ', '')" /></xsl:attribute>
- -->
-</xsl:if>
-</xsl:template>
-
-<!-- Decimal to hexadecimal converter -->
-<xsl:template name="to_hex">
- <xsl:param name="convert" />
- <xsl:value-of select="concat(substring('0123456789ABCDEF', 1 + floor(round($convert) div 16), 1), substring('0123456789ABCDEF', 1 + round($convert) mod 16, 1))" />
-</xsl:template>
-
-<!-- Unit to pixel converter
-Values with units (except %) are converted to pixels and rounded.
-Unknown units are kept. -->
-<xsl:template name="convert_unit">
- <xsl:param name="convert_value" />
- <xsl:choose>
- <xsl:when test="contains($convert_value, 'px')">
- <xsl:value-of select="round(translate($convert_value, 'px', ''))" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'pt')">
- <xsl:value-of select="round(translate($convert_value, 'pt', '') * 1.25)" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'pc')">
- <xsl:value-of select="round(translate($convert_value, 'pc', '') * 15)" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'mm')">
- <xsl:value-of select="round(translate($convert_value, 'mm', '') * 3.543307)" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'cm')">
- <xsl:value-of select="round(translate($convert_value, 'cm', '') * 35.43307)" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'in')">
- <xsl:value-of select="round(translate($convert_value, 'in', '') * 90)" />
- </xsl:when>
- <xsl:when test="contains($convert_value, 'ft')">
- <xsl:value-of select="round(translate($convert_value, 'ft', '') * 1080)" />
- </xsl:when>
- <xsl:when test="not(string(number($convert_value))='NaN')">
- <xsl:value-of select="round($convert_value)" />
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$convert_value" />
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- Title and description
-Blank template. Title is ignored and desc is converted to Tag in the mode="desc" template
--->
-<xsl:template mode="forward" match="*[name(.) = 'title' or name(.) = 'desc']">
- <!-- -->
-</xsl:template>
-
-<!-- Misc ignored stuff (markers, patterns, styles) -->
-<xsl:template mode="forward" match="*[name(.) = 'marker' or name(.) = 'pattern' or name(.) = 'style']">
- <!-- -->
-</xsl:template>
-
-<!-- Symbols -->
-<xsl:template mode="forward" match="*[name(.) = 'symbol']">
- <Style>
- <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if>
- <Canvas>
- <xsl:apply-templates mode="forward" />
- </Canvas>
- </Style>
-</xsl:template>
-
-<!-- Use -->
-<xsl:template mode="forward" match="*[name(.) = 'use']">
- <Canvas>
- <xsl:if test="@xlink:href"><xsl:attribute name="Style"><xsl:value-of select="@xlink:href" /></xsl:attribute></xsl:if>
- <!--xsl:apply-templates mode="transform" select="." /-->
- <xsl:apply-templates mode="forward" />
- </Canvas>
-</xsl:template>
-
-<!-- RDF and foreign objects -->
-<xsl:template mode="forward" match="rdf:RDF | *[name(.) = 'foreignObject']">
- <!-- -->
-</xsl:template>
-
-<!-- Unknown tags -->
-<xsl:template match="*">
-<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment>
-</xsl:template>
-
-
-<!--
-// Colors and patterns //
-
-* Generic color template
-* Fill
-* Fill opacity
-* Fill rule
-* Generic fill template
-* Stroke
-* Stroke opacity
-* Generic stroke template
-* Stroke width
-* Stroke mitterlimit
-* Stroke dasharray
-* Stroke dashoffset
-* Linejoin SVG to XAML converter
-* Stroke linejoin
-* Linecap SVG to XAML converter
-* Stroke linecap
-* Gradient stop
-* Gradient stop opacity
-* Gradient stop offset
--->
-
-<!-- Generic color template -->
-<xsl:template name="template_color">
- <xsl:param name="colorspec" />
- <xsl:param name="opacityspec" />
- <xsl:choose>
- <xsl:when test="starts-with($colorspec, 'rgb(') and not(contains($colorspec , '%'))">
- <xsl:value-of select="'#'" />
- <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after($colorspec, 'rgb('), ',')" /></xsl:with-param></xsl:call-template>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), ',')" /></xsl:with-param></xsl:call-template>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), ')')" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:when test="starts-with($colorspec, 'rgb(') and contains($colorspec , '%')">
- <xsl:value-of select="'#'" />
- <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after($colorspec, 'rgb('), '%,')) * 255 div 100" /></xsl:with-param></xsl:call-template>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), '%,')) * 255 div 100" /></xsl:with-param></xsl:call-template>
- <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), '%)')) * 255 div 100" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:when test="starts-with($colorspec, '#')">
- <xsl:value-of select="'#'" />
- <xsl:if test="$opacityspec != ''"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if>
- <xsl:choose>
- <xsl:when test="string-length(substring-after($colorspec, '#')) = 3">
- <xsl:variable name="colorspec3"><xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" /></xsl:variable>
- <xsl:value-of select="concat(substring($colorspec3, 1, 1), substring($colorspec3, 1, 1))" />
- <xsl:value-of select="concat(substring($colorspec3, 2, 1), substring($colorspec3, 2, 1))" />
- <xsl:value-of select="concat(substring($colorspec3, 3, 1), substring($colorspec3, 3, 1))" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" /></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="named_color_hex" select="document('colors.xml')/colors/color[@name = translate($colorspec, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]/@hex" />
- <xsl:choose>
- <xsl:when test="$named_color_hex and $named_color_hex != ''">
- <xsl:value-of select="'#'" />
- <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number($opacityspec) * 255" /></xsl:with-param></xsl:call-template></xsl:if>
- <xsl:value-of select="substring-after($named_color_hex, '#')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$colorspec" /></xsl:otherwise>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- Fill -->
-<xsl:template mode="fill" match="*">
- <xsl:choose>
- <xsl:when test="@fill and starts-with(@fill, 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@fill, 'url(#'), ')'), '}')" /></xsl:when>
- <xsl:when test="@fill"><xsl:value-of select="@fill" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'fill:') and starts-with(substring-after(@style, 'fill:'), 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'fill:')">
- <xsl:variable name="Fill" select="substring-after(@style, 'fill:')" />
- <xsl:choose>
- <xsl:when test="contains($Fill, ';')">
- <xsl:value-of select="substring-before($Fill, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$Fill" /></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Fill opacity -->
-<xsl:template mode="fill_opacity" match="*">
- <xsl:choose>
- <xsl:when test="@fill-opacity"><xsl:value-of select="@fill-opacity" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'fill-opacity:')">
- <xsl:variable name="Opacity" select="substring-after(@style, 'fill-opacity:')" />
- <xsl:choose>
- <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill_opacity" select="parent::*" /></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Fill rule -->
-<xsl:template mode="fill_rule" match="*">
- <xsl:choose>
- <xsl:when test="@fill-rule and (@fill-rule = 'nonzero' or @fill-rule = 'evenodd')"><xsl:attribute name="FillRule"><xsl:value-of select="@fill-rule" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'fill-rule:')">
- <xsl:variable name="FillRule" select="substring-after(@style, 'fill-rule:')" />
- <xsl:choose>
- <xsl:when test="contains($FillRule, ';')">
- <xsl:if test="substring-before($FillRule, ';') = 'nonzero' or substring-before($FillRule, ';') = 'evenodd'"><xsl:attribute name="FillRule"><xsl:value-of select="substring-before($FillRule, ';')" /></xsl:attribute></xsl:if>
- </xsl:when>
- <xsl:when test="$FillRule = 'nonzero' or $FillRule = 'evenodd'"><xsl:attribute name="FillRule"><xsl:value-of select="$FillRule" /></xsl:attribute></xsl:when>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill_rule" select="parent::*"/></xsl:when>
- <xsl:otherwise><xsl:attribute name="FillRule">NonZero</xsl:attribute></xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- Generic fill template -->
-<xsl:template mode="template_fill" match="*">
- <xsl:variable name="fill"><xsl:apply-templates mode="fill" select="." /></xsl:variable>
- <xsl:variable name="fill_opacity"><xsl:apply-templates mode="fill_opacity" select="." /></xsl:variable>
- <xsl:if test="not($fill = 'none')">
- <xsl:attribute name="Fill">
- <xsl:choose>
- <xsl:when test="$fill != ''">
- <xsl:call-template name="template_color">
- <xsl:with-param name="colorspec">
- <xsl:if test="$fill != 'none'"><xsl:value-of select="$fill" /></xsl:if>
- </xsl:with-param>
- <xsl:with-param name="opacityspec"><xsl:value-of select="$fill_opacity" /></xsl:with-param>
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>#000000</xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
-</xsl:template>
-
-<!-- Stroke -->
-<xsl:template mode="stroke" match="*">
- <xsl:choose>
- <xsl:when test="@stroke and starts-with(@stroke, 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@stroke, 'url(#'), ')'), '}')" /></xsl:when>
- <xsl:when test="@stroke and @stroke != 'none'"><xsl:value-of select="@stroke" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke:') and starts-with(substring-after(@style, 'stroke:'), 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke:')">
- <xsl:variable name="Stroke" select="substring-after(@style, 'stroke:')" />
- <xsl:choose>
- <xsl:when test="contains($Stroke, ';')">
- <xsl:if test="substring-before($Stroke, ';') != 'none'"><xsl:value-of select="substring-before($Stroke, ';')" /></xsl:if>
- </xsl:when>
- <xsl:when test="$Stroke != 'none'"><xsl:value-of select="$Stroke" /></xsl:when>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke opacity -->
-<xsl:template mode="stroke_opacity" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-opacity"><xsl:value-of select="@stroke-opacity" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-opacity:')">
- <xsl:variable name="Opacity" select="substring-after(@style, 'stroke-opacity:')" />
- <xsl:choose>
- <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_opacity" select="parent::*" /></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Generic stroke template -->
-<xsl:template mode="template_stroke" match="*">
- <xsl:variable name="stroke"><xsl:apply-templates mode="stroke" select="." /></xsl:variable>
- <xsl:variable name="stroke_opacity"><xsl:apply-templates mode="stroke_opacity" select="." /></xsl:variable>
- <xsl:if test="$stroke != ''">
- <xsl:attribute name="Stroke">
- <xsl:call-template name="template_color">
- <xsl:with-param name="colorspec"><xsl:value-of select="$stroke" /></xsl:with-param>
- <xsl:with-param name="opacityspec"><xsl:value-of select="$stroke_opacity" /></xsl:with-param>
- </xsl:call-template>
- </xsl:attribute>
- </xsl:if>
-</xsl:template>
-
-<!-- Stroke width -->
-<xsl:template mode="stroke_width" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-width">
- <xsl:attribute name="StrokeThickness"><xsl:value-of select="@stroke-width" /></xsl:attribute>
- </xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-width:')">
- <xsl:attribute name="StrokeThickness">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value">
- <xsl:choose>
- <xsl:when test="contains(substring-after(@style, 'stroke-width:'), ';')"><xsl:value-of select="substring-before(substring-after(@style, 'stroke-width:'), ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="substring-after(@style, 'stroke-width:')" /></xsl:otherwise>
- </xsl:choose>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_width" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke miterlimit -->
-<xsl:template mode="stroke_miterlimit" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-miterlimit"><xsl:attribute name="StrokeMiterLimit"><xsl:value-of select="@stroke-miterlimit" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-miterlimit:')">
- <xsl:variable name="StrokeMiterLimit" select="substring-after(@style, 'stroke-miterlimit:')" />
- <xsl:attribute name="StrokeMiterLimit">
- <xsl:choose>
- <xsl:when test="contains($StrokeMiterLimit, ';')"><xsl:value-of select="substring-before($StrokeMiterLimit, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$StrokeMiterLimit" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_miterlimit" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke dasharray -->
-<xsl:template mode="stroke_dasharray" match="*">
- <!-- stroke-dasharray="10,30,20,30" becomes StrokeDashArray="1 3 2 3" ?? -->
- <xsl:choose>
- <xsl:when test="@stroke-dasharray and @stroke-dasharray != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="@stroke-dasharray" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-dasharray:')">
- <xsl:variable name="StrokeDashArray" select="substring-after(@style, 'stroke-dasharray:')" />
- <xsl:choose>
- <xsl:when test="contains($StrokeDashArray, ';')">
- <xsl:if test="substring-before($StrokeDashArray, ';') != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="substring-before($StrokeDashArray, ';')" /></xsl:attribute></xsl:if>
- </xsl:when>
- <xsl:when test="$StrokeDashArray != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="$StrokeDashArray" /></xsl:attribute></xsl:when>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_dasharray" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke dashoffset -->
-<xsl:template mode="stroke_dashoffset" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-dashoffset"><xsl:attribute name="StrokeDashOffset"><xsl:value-of select="@stroke-dashoffset" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-dashoffset:')">
- <xsl:variable name="StrokeDashOffset" select="substring-after(@style, 'stroke-dashoffset:')" />
- <xsl:attribute name="StrokeDashOffset">
- <xsl:choose>
- <xsl:when test="contains($StrokeDashOffset, ';')"><xsl:value-of select="substring-before($StrokeDashOffset, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$StrokeDashOffset" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_dashoffset" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Linejoin SVG to XAML converter -->
-<xsl:template name="linejoin_svg_to_xaml">
- <xsl:param name="linejoin" />
- <xsl:choose>
- <xsl:when test="$linejoin = 'bevel'">Bevel</xsl:when>
- <xsl:when test="$linejoin = 'round'">Round</xsl:when>
- <xsl:otherwise>Miter</xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke linejoin -->
-<xsl:template mode="stroke_linejoin" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-miterlimit">
- <xsl:attribute name="StrokeLineJoin">
- <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="@stroke-linejoin" /></xsl:with-param></xsl:call-template>
- </xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-linejoin:')">
- <xsl:variable name="StrokeLineJoin" select="substring-after(@style, 'stroke-linejoin:')" />
- <xsl:attribute name="StrokeLineJoin">
- <xsl:choose>
- <xsl:when test="contains($StrokeLineJoin, ';')">
- <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="substring-before($StrokeLineJoin, ';')" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="$StrokeLineJoin" /></xsl:with-param></xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_linejoin" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Linecap SVG to XAML converter -->
-<xsl:template name="linecap_svg_to_xaml">
- <xsl:param name="linecap" />
- <xsl:choose>
- <xsl:when test="$linecap = 'round'">Round</xsl:when>
- <xsl:when test="$linecap = 'square'">Square</xsl:when>
- <xsl:otherwise>Flat</xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!-- Stroke linecap -->
-<xsl:template mode="stroke_linecap" match="*">
- <xsl:choose>
- <xsl:when test="@stroke-linecap">
- <xsl:attribute name="StrokeStartLineCap">
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="@stroke-linecap" /></xsl:with-param></xsl:call-template>
- </xsl:attribute>
- <xsl:attribute name="StrokeEndLineCap">
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="@stroke-linecap" /></xsl:with-param></xsl:call-template>
- </xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stroke-linecap:')">
- <xsl:variable name="StrokeStartLineCap" select="substring-after(@style, 'stroke-linecap:')" />
- <xsl:variable name="StrokeEndLineCap" select="substring-after(@style, 'stroke-linecap:')" />
- <xsl:attribute name="StrokeStartLineCap">
- <xsl:choose>
- <xsl:when test="contains($StrokeStartLineCap, ';')">
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="substring-before($StrokeStartLineCap, ';')" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="$StrokeStartLineCap" /></xsl:with-param></xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- <xsl:attribute name="StrokeEndLineCap">
- <xsl:choose>
- <xsl:when test="contains($StrokeEndLineCap, ';')">
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="substring-before($StrokeEndLineCap, ';')" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="$StrokeEndLineCap" /></xsl:with-param></xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_linecap" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Gradient stops -->
-<xsl:template mode="stop_color" match="*">
- <xsl:variable name="Opacity">
- <xsl:choose>
- <xsl:when test="@stop-opacity"><xsl:value-of select="@stop-opacity" /></xsl:when>
- <xsl:when test="@style and contains(@style, 'stop-opacity:')">
- <xsl:variable name="temp_opacity" select="substring-after(@style, 'stop-opacity:')" />
- <xsl:choose>
- <xsl:when test="contains($temp_opacity, ';')"><xsl:value-of select="substring-before($temp_opacity, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$temp_opacity" /></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="''" /></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="hex_opacity">
- <xsl:choose>
- <xsl:when test="$Opacity != ''"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number($Opacity) * 255" /></xsl:with-param></xsl:call-template> </xsl:when>
- <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="stopcolor">
- <xsl:choose>
- <xsl:when test="@stop-color">
- <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="@stop-color" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:when test="@style and contains(@style, 'stop-color:')">
- <xsl:variable name="Color" select="substring-after(@style, 'stop-color:')" />
- <xsl:choose>
- <xsl:when test="contains($Color, ';')">
- <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="substring-before($Color, ';')" /></xsl:with-param></xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="$Color" /></xsl:with-param></xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_color" select="parent::*"/></xsl:when>
- <xsl:otherwise>#000</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:attribute name="Color">
- <xsl:choose>
- <xsl:when test="$hex_opacity != '' and starts-with($stopcolor, '#')"><xsl:value-of select="concat('#', $hex_opacity, substring-after($stopcolor, '#'))" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$stopcolor" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
-</xsl:template>
-
-<!-- Gradient stop opacity -->
-<xsl:template mode="stop_opacity" match="*">
- <xsl:choose>
- <xsl:when test="@stop-opacity"><xsl:attribute name="Opacity"><xsl:value-of select="@stop-opacity" /></xsl:attribute></xsl:when>
- <xsl:when test="@style and contains(@style, 'stop-opacity:')">
- <xsl:variable name="Opacity" select="substring-after(@style, 'stop-opacity:')" />
- <xsl:attribute name="Opacity">
- <xsl:choose>
- <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_opacity" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Gradient stop offset -->
-<xsl:template mode="offset" match="*">
- <xsl:choose>
- <xsl:when test="@offset">
- <xsl:attribute name="Offset">
- <xsl:choose>
- <xsl:when test="contains(@offset, '%')"><xsl:value-of select="number(substring-before(@offset, '%')) div 100" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="@offset" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="@style and contains(@style, 'offset:')">
- <xsl:variable name="Offset" select="substring-after(@style, 'offset:')" />
- <xsl:attribute name="Offset">
- <xsl:choose>
- <xsl:when test="contains($Offset, '%')"><xsl:value-of select="number(substring-before($Offset, '%')) div 100" /></xsl:when>
- <xsl:when test="contains($Offset, ';')"><xsl:value-of select="substring-before($Offset, ';')" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$Offset" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:when>
- <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_offset" select="parent::*"/></xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!--
-// Transforms //
-All the matrix, translate, rotate... stuff.
-Fixme: XAML transforms don't show the same result as SVG ones with the same values.
-
-* Parse transform
-* Apply transform
-* Apply transform v2
--->
-
-<!-- Parse transform -->
-<xsl:template name="parse_transform">
- <xsl:param name="input" />
- <xsl:choose>
- <xsl:when test="starts-with($input, 'matrix(')">
- <MatrixTransform><xsl:attribute name="Matrix"><xsl:value-of select="substring-before(substring-after($input, 'matrix('), ')')" /></xsl:attribute></MatrixTransform>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </xsl:when>
- <xsl:when test="starts-with($input, 'scale(')">
- <ScaleTransform>
- <xsl:variable name="scale" select="substring-before(substring-after($input, 'scale('), ')')" />
- <xsl:choose>
- <xsl:when test="contains($scale, ',')">
- <xsl:attribute name="ScaleX"><xsl:value-of select="substring-before($scale, ',')" /></xsl:attribute>
- <xsl:attribute name="ScaleY"><xsl:value-of select="substring-after($scale, ',')" /></xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <xsl:attribute name="ScaleX"><xsl:value-of select="$scale" /></xsl:attribute>
- <xsl:attribute name="ScaleY"><xsl:value-of select="$scale" /></xsl:attribute>
- </xsl:otherwise>
- </xsl:choose>
- </ScaleTransform>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </xsl:when>
- <xsl:when test="starts-with($input, 'rotate(')">
- <RotateTransform>
- <xsl:attribute name="Angle"><xsl:value-of select="substring-before(substring-after($input, 'rotate('), ')')" /></xsl:attribute>
- <xsl:if test="@rx"><xsl:attribute name="CenterX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if>
- <xsl:if test="@ry"><xsl:attribute name="CenterY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if>
- </RotateTransform>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </xsl:when>
- <xsl:when test="starts-with($input, 'skewX(')">
- <SkewTransform>
- <xsl:attribute name="AngleX"><xsl:value-of select="substring-before(substring-after($input, 'skewX('), ')')" /></xsl:attribute>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </SkewTransform>
- </xsl:when>
- <xsl:when test="starts-with($input, 'skewY(')">
- <SkewTransform>
- <xsl:attribute name="AngleY"><xsl:value-of select="substring-before(substring-after($input, 'skewY('), ')')" /></xsl:attribute>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </SkewTransform>
- </xsl:when>
- <xsl:when test="starts-with($input, 'translate(')">
- <TranslateTransform>
- <xsl:variable name="translate" select="substring-before(substring-after($input, 'translate('), ')')" />
- <xsl:choose>
- <xsl:when test="contains($translate, ',')">
- <xsl:attribute name="X"><xsl:value-of select="substring-before($translate, ',')" /></xsl:attribute>
- <xsl:attribute name="Y"><xsl:value-of select="substring-after($translate, ',')" /></xsl:attribute>
- </xsl:when>
- <xsl:when test="contains($translate, ' ')">
- <xsl:attribute name="X"><xsl:value-of select="substring-before($translate, ' ')" /></xsl:attribute>
- <xsl:attribute name="Y"><xsl:value-of select="substring-after($translate, ' ')" /></xsl:attribute>
- </xsl:when>
- <xsl:otherwise><xsl:attribute name="X"><xsl:value-of select="$translate" /></xsl:attribute></xsl:otherwise>
- </xsl:choose>
- </TranslateTransform>
- <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template>
- </xsl:when>
- </xsl:choose>
-</xsl:template>
-
-<!-- Apply transform -->
-<xsl:template mode="transform" match="*">
- <xsl:param name="mapped_type" />
- <xsl:if test="@transform or @gradientTransform">
- <xsl:variable name="transform">
- <xsl:choose>
- <xsl:when test="@transform"><xsl:value-of select="@transform" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="@gradientTransform" /></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="transform_nodes">
- <xsl:call-template name="parse_transform">
- <xsl:with-param name="input" select="$transform" />
- </xsl:call-template>
- </xsl:variable>
-
- <xsl:comment>
- <xsl:value-of select="name(.)" />
- </xsl:comment>
-
- <xsl:choose>
- <xsl:when test="$mapped_type and $mapped_type != ''">
- <xsl:element name="{$mapped_type}.RenderTransform">
- <xsl:choose>
- <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></xsl:when>
- <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"><TransformGroup><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></TransformGroup></xsl:when>
- </xsl:choose>
- </xsl:element>
- </xsl:when>
- <xsl:otherwise>
- <!-- For instance LinearGradient.Transform -->
- <xsl:choose>
- <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></xsl:when>
- <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"><TransformGroup><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></TransformGroup></xsl:when>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:if>
-</xsl:template>
-
-<!-- Apply transform v2
-Fixme: is this template still in use? -->
-<xsl:template mode="transform2" match="*">
- <xsl:choose>
- <xsl:when test="@transform">
- <Canvas>
- <Canvas.RenderTransform>
- <TransformGroup><xsl:apply-templates mode="transform" select="." /></TransformGroup>
- </Canvas.RenderTransform>
- <xsl:apply-templates mode="forward" select="." />
- </Canvas>
- </xsl:when>
- <xsl:otherwise>
- <xsl:apply-templates mode="forward" select="." />
- </xsl:otherwise>
- </xsl:choose>
-</xsl:template>
-
-<!--
-// Objects //
-
-* Image
-* Text
-* Lines
-* Rectangle
-* Polygon
-* Polyline
-* Path
-* Ellipse
-* Circle
--->
-
-<!-- Image -->
-<xsl:template mode="forward" match="*[name(.) = 'image']">
- <Image>
- <xsl:apply-templates mode="id" select="." />
- <xsl:if test="@x"><xsl:attribute name="Canvas.Left">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@x" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@y"><xsl:attribute name="Canvas.Top">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@y" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:apply-templates mode="desc" select="." />
- <xsl:apply-templates mode="clip" select="." />
- <xsl:if test="@xlink:href"><xsl:attribute name="Source"><xsl:value-of select="@xlink:href" /></xsl:attribute></xsl:if>
- <xsl:if test="@width"><xsl:attribute name="Width">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@width" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@height"><xsl:attribute name="Height">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@height" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Image'" />
- </xsl:apply-templates>
- <!--xsl:apply-templates mode="transform" /-->
- <xsl:apply-templates mode="forward" />
- </Image>
-</xsl:template>
-
-<!-- Text -->
-<xsl:template mode="forward" match="*[name(.) = 'text']">
- <TextBlock>
- <xsl:if test="@font-size"><xsl:attribute name="FontSize"><xsl:value-of select="@font-size" /></xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'font-size:')">
- <xsl:variable name="font_size" select="substring-after(@style, 'font-size:')" />
- <xsl:attribute name="FontSize">
- <xsl:choose>
- <xsl:when test="contains($font_size, ';')">
- <xsl:value-of select="substring-before($font_size, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$font_size" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@font-weight"><xsl:attribute name="FontWeight"><xsl:value-of select="@font-weight" /></xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'font-weight:')">
- <xsl:variable name="font_weight" select="substring-after(@style, 'font-weight:')" />
- <xsl:attribute name="FontWeight">
- <xsl:choose>
- <xsl:when test="contains($font_weight, ';')">
- <xsl:value-of select="substring-before($font_weight, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$font_weight" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@font-family"><xsl:attribute name="FontFamily"><xsl:value-of select="@font-family" /></xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'font-family:')">
- <xsl:variable name="font_family" select="substring-after(@style, 'font-family:')" />
- <xsl:attribute name="FontFamily">
- <xsl:choose>
- <xsl:when test="contains($font_family, ';')">
- <xsl:value-of select="substring-before($font_family, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$font_family" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@font-style"><xsl:attribute name="FontStyle"><xsl:value-of select="@font-style" /></xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'font-style:')">
- <xsl:variable name="font_style" select="substring-after(@style, 'font-style:')" />
- <xsl:attribute name="FontStyle">
- <xsl:choose>
- <xsl:when test="contains($font_style, ';')">
- <xsl:value-of select="substring-before($font_style, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$font_style" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@fill"><xsl:attribute name="Foreground"><xsl:value-of select="@fill" /></xsl:attribute></xsl:if>
- <xsl:if test="@style and contains(@style, 'fill')">
- <xsl:variable name="fill" select="substring-after(@style, 'fill:')" />
- <xsl:attribute name="Foreground">
- <xsl:choose>
- <xsl:when test="contains($fill, ';')">
- <xsl:value-of select="substring-before($fill, ';')" />
- </xsl:when>
- <xsl:otherwise><xsl:value-of select="$fill" /></xsl:otherwise>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@text-anchor">
- <xsl:attribute name="HorizontalAlignment">
- <xsl:choose>
- <xsl:when test="@text-anchor = 'start'">Left</xsl:when>
- <xsl:when test="@text-anchor = 'middle'">Center</xsl:when>
- <xsl:when test="@text-anchor = 'end'">Right</xsl:when>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:if test="@width"><xsl:attribute name="Width">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@width" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@height"><xsl:attribute name="Height">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@height" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@x"><xsl:attribute name="Canvas.Left">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@x" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@y"><xsl:attribute name="Canvas.Top">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@y" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
- <xsl:apply-templates mode="clip" select="." />
- <!--xsl:apply-templates mode="transform" select="." /-->
- <!--xsl:apply-templates mode="forward" /-->
- <xsl:if test="text()"><xsl:value-of select="text()" /></xsl:if>
- <xsl:if test="*[name(.) = 'tspan']/text()"><xsl:value-of select="*[name(.) = 'tspan']/text()" /></xsl:if>
- </TextBlock>
-</xsl:template>
-
-<!-- Lines -->
-<xsl:template mode="forward" match="*[name(.) = 'line']">
- <Line>
- <xsl:if test="@x1"><xsl:attribute name="X1"><xsl:value-of select="@x1" /></xsl:attribute></xsl:if>
- <xsl:if test="@y1"><xsl:attribute name="Y1"><xsl:value-of select="@y1" /></xsl:attribute></xsl:if>
- <xsl:if test="@x2"><xsl:attribute name="X2"><xsl:value-of select="@x2" /></xsl:attribute></xsl:if>
- <xsl:if test="@y2"><xsl:attribute name="Y2"><xsl:value-of select="@y2" /></xsl:attribute></xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Line'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Line>
-</xsl:template>
-
-<!-- Rectangle -->
-<xsl:template mode="forward" match="*[name(.) = 'rect']">
- <Rectangle>
- <xsl:if test="@x"><xsl:attribute name="Canvas.Left">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@x" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@y"><xsl:attribute name="Canvas.Top">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@y" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@width"><xsl:attribute name="Width">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@width" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@height"><xsl:attribute name="Height">
- <xsl:call-template name="convert_unit">
- <xsl:with-param name="convert_value" select="@height" />
- </xsl:call-template>
- </xsl:attribute></xsl:if>
- <xsl:if test="@rx"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if>
- <xsl:if test="@ry"><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if>
- <xsl:if test="@rx and not(@ry)"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute><xsl:attribute name="RadiusY"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if>
- <xsl:if test="@ry and not(@rx)"><xsl:attribute name="RadiusX"><xsl:value-of select="@ry" /></xsl:attribute><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if>
-
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="resources" select="." />
- <xsl:apply-templates mode="desc" select="." />
- <xsl:apply-templates mode="clip" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Rectangle'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Rectangle>
-</xsl:template>
-
-<!-- Polygon -->
-<xsl:template mode="forward" match="*[name(.) = 'polygon']">
- <Polygon>
- <xsl:if test="@points"><xsl:attribute name="Points"><xsl:value-of select="@points" /></xsl:attribute></xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="fill_rule" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Polygon'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Polygon>
-</xsl:template>
-
-<!-- Polyline -->
-<xsl:template mode="forward" match="*[name(.) = 'polyline']">
- <Polyline>
- <xsl:if test="@points"><xsl:attribute name="Points"><xsl:value-of select="@points" /></xsl:attribute></xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="fill_rule" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Polyline'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Polyline>
-</xsl:template>
-
-<!-- Path -->
-<xsl:template mode="forward" match="*[name(.) = 'path']">
- <Path>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
-
- <xsl:if test="@d">
- <xsl:choose>
- <xsl:when test="$silverlight_compatible = 1">
- <xsl:attribute name="Data">
- <xsl:value-of select="translate(@d , ',', ' ')" />
- </xsl:attribute>
- </xsl:when>
- <xsl:otherwise>
- <Path.Data>
- <PathGeometry>
- <xsl:attribute name="Figures">
- <xsl:value-of select="translate(@d , ',', ' ')" />
- </xsl:attribute>
- <xsl:apply-templates mode="fill_rule" select="." />
- </PathGeometry>
- </Path.Data>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:if>
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Path'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Path>
-</xsl:template>
-
-<!-- Ellipse -->
-<xsl:template mode="forward" match="*[name(.) = 'ellipse']">
- <Ellipse>
- <xsl:variable name="cx">
- <xsl:choose>
- <xsl:when test="@cx"><xsl:value-of select="@cx" /></xsl:when>
- <xsl:otherwise>0</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="cy">
- <xsl:choose>
- <xsl:when test="@cy"><xsl:value-of select="@cy" /></xsl:when>
- <xsl:otherwise>0</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:if test="@rx">
- <xsl:attribute name="Canvas.Left"><xsl:value-of select='format-number($cx - @rx, "#.#")' /></xsl:attribute>
- <xsl:attribute name="Width"><xsl:value-of select='format-number(2 * @rx, "#.#")' /></xsl:attribute>
- </xsl:if>
- <xsl:if test="@ry">
- <xsl:attribute name="Canvas.Top"><xsl:value-of select='format-number($cy - @ry, "#.#")' /></xsl:attribute>
- <xsl:attribute name="Height"><xsl:value-of select='format-number(2 * @ry, "#.#")' /></xsl:attribute>
- </xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
- <xsl:apply-templates mode="clip" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Ellipse'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Ellipse>
-</xsl:template>
-
-<!-- Circle -->
-<xsl:template mode="forward" match="*[name(.) = 'circle']">
- <Ellipse>
- <xsl:variable name="cx">
- <xsl:choose>
- <xsl:when test="@cx"><xsl:value-of select="@cx" /></xsl:when>
- <xsl:otherwise>0</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="cy">
- <xsl:choose>
- <xsl:when test="@cy"><xsl:value-of select="@cy" /></xsl:when>
- <xsl:otherwise>0</xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:if test="@r">
- <xsl:attribute name="Canvas.Left"><xsl:value-of select='format-number($cx - @r, "#.#")' /></xsl:attribute>
- <xsl:attribute name="Canvas.Top"><xsl:value-of select='format-number($cy - @r, "#.#")' /></xsl:attribute>
- <xsl:attribute name="Width"><xsl:value-of select='format-number(2 * @r, "#.#")' /></xsl:attribute>
- <xsl:attribute name="Height"><xsl:value-of select='format-number(2 * @r, "#.#")' /></xsl:attribute>
- </xsl:if>
- <xsl:apply-templates mode="id" select="." />
- <xsl:apply-templates mode="template_fill" select="." />
- <xsl:apply-templates mode="template_stroke" select="." />
- <xsl:apply-templates mode="stroke_width" select="." />
- <xsl:apply-templates mode="stroke_miterlimit" select="." />
- <xsl:apply-templates mode="stroke_dasharray" select="." />
- <xsl:apply-templates mode="stroke_dashoffset" select="." />
- <xsl:apply-templates mode="stroke_linejoin" select="." />
- <xsl:apply-templates mode="stroke_linecap" select="." />
- <xsl:apply-templates mode="filter_effect" select="." />
- <xsl:apply-templates mode="desc" select="." />
- <xsl:apply-templates mode="clip" select="." />
-
- <xsl:apply-templates mode="transform" select=".">
- <xsl:with-param name="mapped_type" select="'Ellipse'" />
- </xsl:apply-templates>
-
- <xsl:apply-templates mode="forward" />
- </Ellipse>
-</xsl:template>
-
-<!--
-// Geometry //
-* Generic clip path template
-* Geometry for circle
-* Geometry for rectangle
--->
-
-<!-- Generic clip path template -->
-<xsl:template mode="forward" match="*[name(.) = 'clipPath']">
- <xsl:apply-templates mode="geometry" />
-</xsl:template>
-
-<!-- Geometry for circle -->
-<xsl:template mode="geometry" match="*[name(.) = 'circle']">
- <EllipseGeometry>
- <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if>
- <xsl:if test="@cx and @cy"><xsl:attribute name="Center"><xsl:value-of select="concat(@cx, ',', @cy)" /></xsl:attribute></xsl:if>
- <xsl:if test="@r">
- <xsl:attribute name="RadiusX"><xsl:value-of select="@r" /></xsl:attribute>
- <xsl:attribute name="RadiusY"><xsl:value-of select="@r" /></xsl:attribute>
- </xsl:if>
- </EllipseGeometry>
-</xsl:template>
-
-<!-- Geometry for rectangle -->
-<xsl:template mode="geometry" match="*[name(.) = 'rect']">
- <RectangleGeometry>
- <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if>
- <!--
- <xsl:if test="@x"><xsl:attribute name="Canvas.Left"><xsl:value-of select="@x" /></xsl:attribute></xsl:if>
- <xsl:if test="@y"><xsl:attribute name="Canvas.Top"><xsl:value-of select="@y" /></xsl:attribute></xsl:if>
- <xsl:if test="@width"><xsl:attribute name="Width"><xsl:value-of select="@width" /></xsl:attribute></xsl:if>
- <xsl:if test="@height"><xsl:attribute name="Height"><xsl:value-of select="@height" /></xsl:attribute></xsl:if>
- <xsl:if test="@rx"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if>
- <xsl:if test="@ry"><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if>
- -->
- <xsl:attribute name="Rect"><xsl:value-of select="concat('0, 0, ', @width, ', ', @height)" /></xsl:attribute>
- </RectangleGeometry>
-</xsl:template>
-
-</xsl:stylesheet>
+<?xml version="1.0" encoding="UTF-8"?> + +<!-- +Copyright (c) 2005-2007 authors: +Original version: Toine de Greef (a.degreef@chello.nl) +Modified (2010) by Nicolas Dufour (nicoduf@yahoo.fr) (blur support, units +convertion, comments, and some other fixes) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +--> + +<xsl:stylesheet version="1.0" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +xmlns:xlink="http://www.w3.org/1999/xlink" +xmlns:xs="http://www.w3.org/2001/XMLSchema" +xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" +xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" +xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" +xmlns:exsl="http://exslt.org/common" +xmlns:libxslt="http://xmlsoft.org/XSLT/namespace" +exclude-result-prefixes="rdf xlink xs exsl libxslt"> + +<xsl:strip-space elements="*" /> +<xsl:output method="xml" encoding="UTF-8"/> + +<xsl:param name="silverlight_compatible" select="1" /> + +<!-- Root template. +Everything starts here! --> +<xsl:template match="/"> + <xsl:choose> + <xsl:when test="$silverlight_compatible = 1"> + <xsl:apply-templates mode="forward" /> + </xsl:when> + <xsl:otherwise> + <Viewbox Stretch="Uniform"> + <xsl:apply-templates mode="forward" /> + </Viewbox> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- SVG and groups +(including layers) --> +<xsl:template mode="forward" match="*[name(.) = 'svg' or name(.) = 'g']"> + <xsl:choose> + <xsl:when test="name(.) = 'svg' or @transform or @viewBox or @id or @clip-path or (@style and contains(@style, 'clip-path:url(#')) or (@width and not(contains(@width, '%'))) or @x or @y or (@height and not(contains(@height, '%'))) or *[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']"> + <Canvas> + <xsl:apply-templates mode="id" select="." /> + <!-- + <xsl:apply-templates mode="clip" select="." /> + --> + <xsl:if test="@style and contains(@style, 'display:none')"><xsl:attribute name="Visibility">Collapsed</xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'opacity:')"> + <xsl:attribute name="Opacity"> + <xsl:choose> + <xsl:when test="contains(substring-after(@style, 'opacity:'), ';')"><xsl:value-of select="substring-before(substring-after(@style, 'opacity:'), ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="substring-after(@style, 'opacity:')" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@width and not(contains(@width, '%'))"> + <xsl:attribute name="Width"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@width" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@height and not(contains(@height, '%'))"> + <xsl:attribute name="Height"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@height" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@x"> + <xsl:attribute name="Canvas.Left"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@x" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@y"> + <xsl:attribute name="Canvas.Top"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@y" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@viewBox"> + <xsl:variable name="viewBox"><xsl:value-of select="normalize-space(translate(@viewBox, ',', ' '))" /></xsl:variable> + <xsl:attribute name="Width"><xsl:value-of select="substring-before(substring-after(substring-after($viewBox, ' '), ' '), ' ')" /></xsl:attribute> + <xsl:attribute name="Height"><xsl:value-of select="substring-after(substring-after(substring-after($viewBox, ' '), ' '), ' ')" /></xsl:attribute> + <Canvas.RenderTransform> + <TranslateTransform> + <xsl:attribute name="X"><xsl:value-of select="-number(substring-before($viewBox, ' '))" /></xsl:attribute> + <xsl:attribute name="Y"><xsl:value-of select="-number(substring-before(substring-after($viewBox, ' '), ' '))" /></xsl:attribute> + </TranslateTransform> + </Canvas.RenderTransform> + </xsl:if> + <xsl:if test="@transform"> + <Canvas> + <Canvas.RenderTransform> + <TransformGroup><xsl:apply-templates mode="transform" select="." /></TransformGroup> + </Canvas.RenderTransform> + <xsl:apply-templates mode="forward" select="*" /> + </Canvas> + </xsl:if> + + <xsl:if test="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']"> + <Canvas.Resources> + <xsl:apply-templates mode="forward" select="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath']" /> + </Canvas.Resources> + </xsl:if> + <xsl:if test="not(@transform)"> + <xsl:apply-templates mode="forward" select="*[name(.) != 'linearGradient' and name(.) != 'radialGradient' and name(.) != 'defs' and name(.) != 'clipPath']" /> + </xsl:if> + </Canvas> + </xsl:when> + <xsl:when test="not(@transform)"> + <xsl:apply-templates mode="forward" select="*" /> + </xsl:when> + </xsl:choose> +</xsl:template> + +<!-- +// Resources (defs) // + +* Resources ids +* Generic defs template +* Generic filters template +* Filter effects +* Linked filter effects +* Linear gradients +* Radial gradients +* Generic gradient stops +* Clipping +--> + +<!-- Resources ids --> +<xsl:template mode="resources" match="*"> + <!-- should be in-depth --> + <xsl:if test="ancestor::*[name(.) = 'defs']"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if> +</xsl:template> + +<!-- Generic defs template --> +<xsl:template mode="forward" match="defs"> + <xsl:apply-templates mode="forward" /> +</xsl:template> + +<!-- Generic filters template +Limited to one filter (can be improved) --> +<xsl:template mode="forward" match="*[name(.) = 'filter']"> + <xsl:if test="count(*) = 1"> + <xsl:apply-templates mode="forward" /> + </xsl:if> +</xsl:template> + +<!-- Filter effects --> +<xsl:template mode="forward" match="*[name(.) = 'feGaussianBlur']"> + <BlurEffect> + <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if> + <xsl:if test="@stdDeviation"><xsl:attribute name="Radius"><xsl:value-of select="round(@stdDeviation * 3)" /></xsl:attribute></xsl:if> + </BlurEffect> +</xsl:template> + +<!-- Linked filter effect --> +<xsl:template mode="filter_effect" match="*"> +<xsl:choose> + <xsl:when test="@filter and starts-with(@filter, 'url(#')"> + <xsl:attribute name="Effect"> + <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@filter, 'url(#'), ')'), '}')" /> + </xsl:attribute> + </xsl:when> + <xsl:when test="@style and contains(@style, 'filter:url(#')"> + <xsl:attribute name="Effect"> + <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'filter:url(#'), ')'), '}')" /> + </xsl:attribute> + </xsl:when> +</xsl:choose> +</xsl:template> + +<!-- Linear gradient --> +<xsl:template mode="forward" match="*[name(.) = 'linearGradient']"> + <LinearGradientBrush> + <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if> + <xsl:attribute name="MappingMode"> + <xsl:choose> + <xsl:when test="@gradientUnits = 'userSpaceOnUse' ">Absolute</xsl:when> + <xsl:otherwise>RelativeToBoundingBox</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:if test="@spreadMethod"> + <xsl:attribute name="SpreadMethod"> + <xsl:choose> + <xsl:when test="@spreadMethod = 'pad'">Pad</xsl:when> + <xsl:when test="@spreadMethod = 'reflect'">Reflect</xsl:when> + <xsl:when test="@spreadMethod = 'repeat'">Repeat</xsl:when> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:choose> + <xsl:when test="@x1 and @y1 and @x2 and @y2"> + <xsl:choose> + <xsl:when test="contains(@x1, '%') and contains(@y1, '%')"> + <xsl:attribute name="StartPoint"><xsl:value-of select="concat(substring-before(@x1, '%') div 100, ',', substring-before(@y1,'%') div 100)" /></xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="StartPoint"><xsl:value-of select="concat(@x1, ',', @y1)" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <xsl:choose> + <xsl:when test="contains(@x2, '%') and contains(@y2, '%')"> + <xsl:attribute name="EndPoint"><xsl:value-of select="concat(substring-before(@x2, '%') div 100, ',', substring-before(@y2,'%') div 100)" /></xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="EndPoint"><xsl:value-of select="concat(@x2, ',', @y2)" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="StartPoint"><xsl:value-of select="'0,0'" /></xsl:attribute> + <xsl:attribute name="EndPoint"><xsl:value-of select="'1,1'" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <LinearGradientBrush.GradientStops> + <GradientStopCollection> + <xsl:choose> + <xsl:when test="@xlink:href"> + <xsl:variable name="reference_id" select="@xlink:href" /> + <xsl:apply-templates mode="forward" select="//*[name(.) = 'linearGradient' and $reference_id = concat('#', @id)]/*" /> + </xsl:when> + <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise> + </xsl:choose> + </GradientStopCollection> + </LinearGradientBrush.GradientStops> + <xsl:if test="@gradientTransform"> + <LinearGradientBrush.Transform> + <xsl:apply-templates mode="transform" select="." /> + </LinearGradientBrush.Transform> + </xsl:if> + </LinearGradientBrush> +</xsl:template> + +<!-- Radial gradient --> +<xsl:template mode="forward" match="*[name(.) = 'radialGradient']"> + <RadialGradientBrush> + <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if> + <xsl:attribute name="MappingMode"> + <xsl:choose> + <xsl:when test="@gradientUnits = 'userSpaceOnUse' ">Absolute</xsl:when> + <xsl:otherwise>RelativeToBoundingBox</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:if test="@spreadMethod"> + <xsl:attribute name="SpreadMethod"> + <xsl:choose> + <xsl:when test="@spreadMethod = 'pad'">Pad</xsl:when> + <xsl:when test="@spreadMethod = 'reflect'">Reflect</xsl:when> + <xsl:when test="@spreadMethod = 'repeat'">Repeat</xsl:when> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@cx and @cy"> + <xsl:attribute name="Center"> + <xsl:choose> + <xsl:when test="contains(@cx, '%') and contains(@cy, '%')"> + <xsl:value-of select="concat(number(substring-before(@cx, '%')) div 100, ',', number(substring-before(@cy, '%')) div 100)" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@cx, ',', @cy)" /> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@fx and @fy"> + <xsl:attribute name="GradientOrigin"> + <xsl:choose> + <xsl:when test="contains(@fx, '%') and contains(@fy, '%')"> + <xsl:value-of select="concat(number(substring-before(@fx, '%')) div 100, ',', number(substring-before(@fy, '%')) div 100)" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@fx, ',', @fy)" /> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@r"> + <xsl:choose> + <xsl:when test="contains(@r, '%')"> + <xsl:attribute name="RadiusX"><xsl:value-of select="number(substring-before(@r, '%')) div 100" /></xsl:attribute> + <xsl:attribute name="RadiusY"><xsl:value-of select="number(substring-before(@r, '%')) div 100" /></xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="RadiusX"><xsl:value-of select="@r" /></xsl:attribute> + <xsl:attribute name="RadiusY"><xsl:value-of select="@r" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + <RadialGradientBrush.GradientStops> + <GradientStopCollection> + <xsl:choose> + <xsl:when test="@xlink:href"> + <xsl:variable name="reference_id" select="@xlink:href" /> + <xsl:apply-templates mode="forward" select="//*[name(.) = 'linearGradient' and $reference_id = concat('#', @id)]/*" /> + </xsl:when> + <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise> + </xsl:choose> + </GradientStopCollection> + </RadialGradientBrush.GradientStops> + <xsl:if test="@gradientTransform"> + <RadialGradientBrush.Transform> + <xsl:apply-templates mode="transform" select="." /> + </RadialGradientBrush.Transform> + </xsl:if> + </RadialGradientBrush> +</xsl:template> + +<!-- Generic gradient stops --> +<xsl:template mode="forward" match="*[name(.) = 'stop']"> + <GradientStop> + <!--xsl:apply-templates mode="stop_opacity" select="." /--> + <xsl:apply-templates mode="stop_color" select="." /> + <xsl:apply-templates mode="offset" select="." /> + <xsl:apply-templates mode="forward" /> + </GradientStop> +</xsl:template> + +<!-- Clipping --> +<xsl:template mode="clip" match="*"> + <xsl:choose> + <xsl:when test="@clip-path and defs/clipPath/path/@d"><xsl:attribute name="Clip"><xsl:value-of select="defs/clipPath/path/@d" /></xsl:attribute></xsl:when> + <xsl:when test="@clip-path and starts-with(@clip-path, 'url(#')"><xsl:attribute name="Clip"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@clip-path, 'url(#'), ')'), '}')" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'clip-path:url(#')"><xsl:attribute name="Clip"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:attribute></xsl:when> + <xsl:when test="clipPath"><xsl:apply-templates mode="forward" /></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- +// Misc templates // + +* Object description +* Id converter +* Decimal to hexadecimal converter +* Unit to pixel converter +* Title and description +* Misc ignored stuff (markers, patterns, styles) +* Symbols +* Use +* RDF and foreign objects +* Unknows tags +--> + +<!-- Object description --> +<xsl:template mode="desc" match="*"> + <xsl:if test="*[name(.) = 'desc']/text()"><xsl:attribute name="Tag"><xsl:value-of select="*[name(.) = 'desc']/text()" /></xsl:attribute></xsl:if> +</xsl:template> + +<!-- Id converter. Removes "-" from the original id. --> +<xsl:template mode="id" match="*"> +<xsl:if test="@id"> + <xsl:attribute name="Name"><xsl:value-of select="translate(@id, '- ', '')" /></xsl:attribute> + <!-- + <xsl:attribute name="x:Key"><xsl:value-of select="translate(@id, '- ', '')" /></xsl:attribute> + --> +</xsl:if> +</xsl:template> + +<!-- Decimal to hexadecimal converter --> +<xsl:template name="to_hex"> + <xsl:param name="convert" /> + <xsl:value-of select="concat(substring('0123456789ABCDEF', 1 + floor(round($convert) div 16), 1), substring('0123456789ABCDEF', 1 + round($convert) mod 16, 1))" /> +</xsl:template> + +<!-- Unit to pixel converter +Values with units (except %) are converted to pixels and rounded. +Unknown units are kept. --> +<xsl:template name="convert_unit"> + <xsl:param name="convert_value" /> + <xsl:choose> + <xsl:when test="contains($convert_value, 'px')"> + <xsl:value-of select="round(translate($convert_value, 'px', ''))" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'pt')"> + <xsl:value-of select="round(translate($convert_value, 'pt', '') * 1.25)" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'pc')"> + <xsl:value-of select="round(translate($convert_value, 'pc', '') * 15)" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'mm')"> + <xsl:value-of select="round(translate($convert_value, 'mm', '') * 3.543307)" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'cm')"> + <xsl:value-of select="round(translate($convert_value, 'cm', '') * 35.43307)" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'in')"> + <xsl:value-of select="round(translate($convert_value, 'in', '') * 90)" /> + </xsl:when> + <xsl:when test="contains($convert_value, 'ft')"> + <xsl:value-of select="round(translate($convert_value, 'ft', '') * 1080)" /> + </xsl:when> + <xsl:when test="not(string(number($convert_value))='NaN')"> + <xsl:value-of select="round($convert_value)" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$convert_value" /> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- Title and description +Blank template. Title is ignored and desc is converted to Tag in the mode="desc" template +--> +<xsl:template mode="forward" match="*[name(.) = 'title' or name(.) = 'desc']"> + <!-- --> +</xsl:template> + +<!-- Misc ignored stuff (markers, patterns, styles) --> +<xsl:template mode="forward" match="*[name(.) = 'marker' or name(.) = 'pattern' or name(.) = 'style']"> + <!-- --> +</xsl:template> + +<!-- Symbols --> +<xsl:template mode="forward" match="*[name(.) = 'symbol']"> + <Style> + <xsl:if test="@id"><xsl:attribute name="x:Key"><xsl:value-of select="@id" /></xsl:attribute></xsl:if> + <Canvas> + <xsl:apply-templates mode="forward" /> + </Canvas> + </Style> +</xsl:template> + +<!-- Use --> +<xsl:template mode="forward" match="*[name(.) = 'use']"> + <Canvas> + <xsl:if test="@xlink:href"><xsl:attribute name="Style"><xsl:value-of select="@xlink:href" /></xsl:attribute></xsl:if> + <!--xsl:apply-templates mode="transform" select="." /--> + <xsl:apply-templates mode="forward" /> + </Canvas> +</xsl:template> + +<!-- RDF and foreign objects --> +<xsl:template mode="forward" match="rdf:RDF | *[name(.) = 'foreignObject']"> + <!-- --> +</xsl:template> + +<!-- Unknown tags --> +<xsl:template match="*"> +<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment> +</xsl:template> + + +<!-- +// Colors and patterns // + +* Generic color template +* Fill +* Fill opacity +* Fill rule +* Generic fill template +* Stroke +* Stroke opacity +* Generic stroke template +* Stroke width +* Stroke mitterlimit +* Stroke dasharray +* Stroke dashoffset +* Linejoin SVG to XAML converter +* Stroke linejoin +* Linecap SVG to XAML converter +* Stroke linecap +* Gradient stop +* Gradient stop opacity +* Gradient stop offset +--> + +<!-- Generic color template --> +<xsl:template name="template_color"> + <xsl:param name="colorspec" /> + <xsl:param name="opacityspec" /> + <xsl:choose> + <xsl:when test="starts-with($colorspec, 'rgb(') and not(contains($colorspec , '%'))"> + <xsl:value-of select="'#'" /> + <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after($colorspec, 'rgb('), ',')" /></xsl:with-param></xsl:call-template> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), ',')" /></xsl:with-param></xsl:call-template> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), ')')" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:when test="starts-with($colorspec, 'rgb(') and contains($colorspec , '%')"> + <xsl:value-of select="'#'" /> + <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after($colorspec, 'rgb('), '%,')) * 255 div 100" /></xsl:with-param></xsl:call-template> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), '%,')) * 255 div 100" /></xsl:with-param></xsl:call-template> + <xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number(substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), '%)')) * 255 div 100" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:when test="starts-with($colorspec, '#')"> + <xsl:value-of select="'#'" /> + <xsl:if test="$opacityspec != ''"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="round(number($opacityspec) * 255)" /></xsl:with-param></xsl:call-template></xsl:if> + <xsl:choose> + <xsl:when test="string-length(substring-after($colorspec, '#')) = 3"> + <xsl:variable name="colorspec3"><xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" /></xsl:variable> + <xsl:value-of select="concat(substring($colorspec3, 1, 1), substring($colorspec3, 1, 1))" /> + <xsl:value-of select="concat(substring($colorspec3, 2, 1), substring($colorspec3, 2, 1))" /> + <xsl:value-of select="concat(substring($colorspec3, 3, 1), substring($colorspec3, 3, 1))" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" /></xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="named_color_hex" select="document('colors.xml')/colors/color[@name = translate($colorspec, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]/@hex" /> + <xsl:choose> + <xsl:when test="$named_color_hex and $named_color_hex != ''"> + <xsl:value-of select="'#'" /> + <xsl:if test="$opacityspec != '' and number($opacityspec) != 1"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number($opacityspec) * 255" /></xsl:with-param></xsl:call-template></xsl:if> + <xsl:value-of select="substring-after($named_color_hex, '#')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$colorspec" /></xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- Fill --> +<xsl:template mode="fill" match="*"> + <xsl:choose> + <xsl:when test="@fill and starts-with(@fill, 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@fill, 'url(#'), ')'), '}')" /></xsl:when> + <xsl:when test="@fill"><xsl:value-of select="@fill" /></xsl:when> + <xsl:when test="@style and contains(@style, 'fill:') and starts-with(substring-after(@style, 'fill:'), 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:when> + <xsl:when test="@style and contains(@style, 'fill:')"> + <xsl:variable name="Fill" select="substring-after(@style, 'fill:')" /> + <xsl:choose> + <xsl:when test="contains($Fill, ';')"> + <xsl:value-of select="substring-before($Fill, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$Fill" /></xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Fill opacity --> +<xsl:template mode="fill_opacity" match="*"> + <xsl:choose> + <xsl:when test="@fill-opacity"><xsl:value-of select="@fill-opacity" /></xsl:when> + <xsl:when test="@style and contains(@style, 'fill-opacity:')"> + <xsl:variable name="Opacity" select="substring-after(@style, 'fill-opacity:')" /> + <xsl:choose> + <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill_opacity" select="parent::*" /></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Fill rule --> +<xsl:template mode="fill_rule" match="*"> + <xsl:choose> + <xsl:when test="@fill-rule and (@fill-rule = 'nonzero' or @fill-rule = 'evenodd')"><xsl:attribute name="FillRule"><xsl:value-of select="@fill-rule" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'fill-rule:')"> + <xsl:variable name="FillRule" select="substring-after(@style, 'fill-rule:')" /> + <xsl:choose> + <xsl:when test="contains($FillRule, ';')"> + <xsl:if test="substring-before($FillRule, ';') = 'nonzero' or substring-before($FillRule, ';') = 'evenodd'"><xsl:attribute name="FillRule"><xsl:value-of select="substring-before($FillRule, ';')" /></xsl:attribute></xsl:if> + </xsl:when> + <xsl:when test="$FillRule = 'nonzero' or $FillRule = 'evenodd'"><xsl:attribute name="FillRule"><xsl:value-of select="$FillRule" /></xsl:attribute></xsl:when> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="fill_rule" select="parent::*"/></xsl:when> + <xsl:otherwise><xsl:attribute name="FillRule">NonZero</xsl:attribute></xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- Generic fill template --> +<xsl:template mode="template_fill" match="*"> + <xsl:variable name="fill"><xsl:apply-templates mode="fill" select="." /></xsl:variable> + <xsl:variable name="fill_opacity"><xsl:apply-templates mode="fill_opacity" select="." /></xsl:variable> + <xsl:if test="not($fill = 'none')"> + <xsl:attribute name="Fill"> + <xsl:choose> + <xsl:when test="$fill != ''"> + <xsl:call-template name="template_color"> + <xsl:with-param name="colorspec"> + <xsl:if test="$fill != 'none'"><xsl:value-of select="$fill" /></xsl:if> + </xsl:with-param> + <xsl:with-param name="opacityspec"><xsl:value-of select="$fill_opacity" /></xsl:with-param> + </xsl:call-template> + </xsl:when> + <xsl:otherwise>#000000</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> +</xsl:template> + +<!-- Stroke --> +<xsl:template mode="stroke" match="*"> + <xsl:choose> + <xsl:when test="@stroke and starts-with(@stroke, 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@stroke, 'url(#'), ')'), '}')" /></xsl:when> + <xsl:when test="@stroke and @stroke != 'none'"><xsl:value-of select="@stroke" /></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke:') and starts-with(substring-after(@style, 'stroke:'), 'url(#')"><xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(@style, 'url(#'), ')'), '}')" /></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke:')"> + <xsl:variable name="Stroke" select="substring-after(@style, 'stroke:')" /> + <xsl:choose> + <xsl:when test="contains($Stroke, ';')"> + <xsl:if test="substring-before($Stroke, ';') != 'none'"><xsl:value-of select="substring-before($Stroke, ';')" /></xsl:if> + </xsl:when> + <xsl:when test="$Stroke != 'none'"><xsl:value-of select="$Stroke" /></xsl:when> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Stroke opacity --> +<xsl:template mode="stroke_opacity" match="*"> + <xsl:choose> + <xsl:when test="@stroke-opacity"><xsl:value-of select="@stroke-opacity" /></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-opacity:')"> + <xsl:variable name="Opacity" select="substring-after(@style, 'stroke-opacity:')" /> + <xsl:choose> + <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_opacity" select="parent::*" /></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Generic stroke template --> +<xsl:template mode="template_stroke" match="*"> + <xsl:variable name="stroke"><xsl:apply-templates mode="stroke" select="." /></xsl:variable> + <xsl:variable name="stroke_opacity"><xsl:apply-templates mode="stroke_opacity" select="." /></xsl:variable> + <xsl:if test="$stroke != ''"> + <xsl:attribute name="Stroke"> + <xsl:call-template name="template_color"> + <xsl:with-param name="colorspec"><xsl:value-of select="$stroke" /></xsl:with-param> + <xsl:with-param name="opacityspec"><xsl:value-of select="$stroke_opacity" /></xsl:with-param> + </xsl:call-template> + </xsl:attribute> + </xsl:if> +</xsl:template> + +<!-- Stroke width --> +<xsl:template mode="stroke_width" match="*"> + <xsl:choose> + <xsl:when test="@stroke-width"> + <xsl:attribute name="StrokeThickness"><xsl:value-of select="@stroke-width" /></xsl:attribute> + </xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-width:')"> + <xsl:attribute name="StrokeThickness"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value"> + <xsl:choose> + <xsl:when test="contains(substring-after(@style, 'stroke-width:'), ';')"><xsl:value-of select="substring-before(substring-after(@style, 'stroke-width:'), ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="substring-after(@style, 'stroke-width:')" /></xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:call-template> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_width" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Stroke miterlimit --> +<xsl:template mode="stroke_miterlimit" match="*"> + <xsl:choose> + <xsl:when test="@stroke-miterlimit"><xsl:attribute name="StrokeMiterLimit"><xsl:value-of select="@stroke-miterlimit" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-miterlimit:')"> + <xsl:variable name="StrokeMiterLimit" select="substring-after(@style, 'stroke-miterlimit:')" /> + <xsl:attribute name="StrokeMiterLimit"> + <xsl:choose> + <xsl:when test="contains($StrokeMiterLimit, ';')"><xsl:value-of select="substring-before($StrokeMiterLimit, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$StrokeMiterLimit" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_miterlimit" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Stroke dasharray --> +<xsl:template mode="stroke_dasharray" match="*"> + <!-- stroke-dasharray="10,30,20,30" becomes StrokeDashArray="1 3 2 3" ?? --> + <xsl:choose> + <xsl:when test="@stroke-dasharray and @stroke-dasharray != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="@stroke-dasharray" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-dasharray:')"> + <xsl:variable name="StrokeDashArray" select="substring-after(@style, 'stroke-dasharray:')" /> + <xsl:choose> + <xsl:when test="contains($StrokeDashArray, ';')"> + <xsl:if test="substring-before($StrokeDashArray, ';') != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="substring-before($StrokeDashArray, ';')" /></xsl:attribute></xsl:if> + </xsl:when> + <xsl:when test="$StrokeDashArray != 'none'"><xsl:attribute name="StrokeDashArray"><xsl:value-of select="$StrokeDashArray" /></xsl:attribute></xsl:when> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_dasharray" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Stroke dashoffset --> +<xsl:template mode="stroke_dashoffset" match="*"> + <xsl:choose> + <xsl:when test="@stroke-dashoffset"><xsl:attribute name="StrokeDashOffset"><xsl:value-of select="@stroke-dashoffset" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-dashoffset:')"> + <xsl:variable name="StrokeDashOffset" select="substring-after(@style, 'stroke-dashoffset:')" /> + <xsl:attribute name="StrokeDashOffset"> + <xsl:choose> + <xsl:when test="contains($StrokeDashOffset, ';')"><xsl:value-of select="substring-before($StrokeDashOffset, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$StrokeDashOffset" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_dashoffset" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Linejoin SVG to XAML converter --> +<xsl:template name="linejoin_svg_to_xaml"> + <xsl:param name="linejoin" /> + <xsl:choose> + <xsl:when test="$linejoin = 'bevel'">Bevel</xsl:when> + <xsl:when test="$linejoin = 'round'">Round</xsl:when> + <xsl:otherwise>Miter</xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- Stroke linejoin --> +<xsl:template mode="stroke_linejoin" match="*"> + <xsl:choose> + <xsl:when test="@stroke-miterlimit"> + <xsl:attribute name="StrokeLineJoin"> + <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="@stroke-linejoin" /></xsl:with-param></xsl:call-template> + </xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-linejoin:')"> + <xsl:variable name="StrokeLineJoin" select="substring-after(@style, 'stroke-linejoin:')" /> + <xsl:attribute name="StrokeLineJoin"> + <xsl:choose> + <xsl:when test="contains($StrokeLineJoin, ';')"> + <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="substring-before($StrokeLineJoin, ';')" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="linejoin_svg_to_xaml"><xsl:with-param name="linejoin"><xsl:value-of select="$StrokeLineJoin" /></xsl:with-param></xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_linejoin" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Linecap SVG to XAML converter --> +<xsl:template name="linecap_svg_to_xaml"> + <xsl:param name="linecap" /> + <xsl:choose> + <xsl:when test="$linecap = 'round'">Round</xsl:when> + <xsl:when test="$linecap = 'square'">Square</xsl:when> + <xsl:otherwise>Flat</xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- Stroke linecap --> +<xsl:template mode="stroke_linecap" match="*"> + <xsl:choose> + <xsl:when test="@stroke-linecap"> + <xsl:attribute name="StrokeStartLineCap"> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="@stroke-linecap" /></xsl:with-param></xsl:call-template> + </xsl:attribute> + <xsl:attribute name="StrokeEndLineCap"> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="@stroke-linecap" /></xsl:with-param></xsl:call-template> + </xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stroke-linecap:')"> + <xsl:variable name="StrokeStartLineCap" select="substring-after(@style, 'stroke-linecap:')" /> + <xsl:variable name="StrokeEndLineCap" select="substring-after(@style, 'stroke-linecap:')" /> + <xsl:attribute name="StrokeStartLineCap"> + <xsl:choose> + <xsl:when test="contains($StrokeStartLineCap, ';')"> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="substring-before($StrokeStartLineCap, ';')" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="$StrokeStartLineCap" /></xsl:with-param></xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:attribute name="StrokeEndLineCap"> + <xsl:choose> + <xsl:when test="contains($StrokeEndLineCap, ';')"> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="substring-before($StrokeEndLineCap, ';')" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="linecap_svg_to_xaml"><xsl:with-param name="linecap"><xsl:value-of select="$StrokeEndLineCap" /></xsl:with-param></xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stroke_linecap" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Gradient stops --> +<xsl:template mode="stop_color" match="*"> + <xsl:variable name="Opacity"> + <xsl:choose> + <xsl:when test="@stop-opacity"><xsl:value-of select="@stop-opacity" /></xsl:when> + <xsl:when test="@style and contains(@style, 'stop-opacity:')"> + <xsl:variable name="temp_opacity" select="substring-after(@style, 'stop-opacity:')" /> + <xsl:choose> + <xsl:when test="contains($temp_opacity, ';')"><xsl:value-of select="substring-before($temp_opacity, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$temp_opacity" /></xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise><xsl:value-of select="''" /></xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="hex_opacity"> + <xsl:choose> + <xsl:when test="$Opacity != ''"><xsl:call-template name="to_hex"><xsl:with-param name="convert"><xsl:value-of select="number($Opacity) * 255" /></xsl:with-param></xsl:call-template> </xsl:when> + <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="stopcolor"> + <xsl:choose> + <xsl:when test="@stop-color"> + <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="@stop-color" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:when test="@style and contains(@style, 'stop-color:')"> + <xsl:variable name="Color" select="substring-after(@style, 'stop-color:')" /> + <xsl:choose> + <xsl:when test="contains($Color, ';')"> + <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="substring-before($Color, ';')" /></xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="template_color"><xsl:with-param name="colorspec"><xsl:value-of select="$Color" /></xsl:with-param></xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_color" select="parent::*"/></xsl:when> + <xsl:otherwise>#000</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:attribute name="Color"> + <xsl:choose> + <xsl:when test="$hex_opacity != '' and starts-with($stopcolor, '#')"><xsl:value-of select="concat('#', $hex_opacity, substring-after($stopcolor, '#'))" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$stopcolor" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> +</xsl:template> + +<!-- Gradient stop opacity --> +<xsl:template mode="stop_opacity" match="*"> + <xsl:choose> + <xsl:when test="@stop-opacity"><xsl:attribute name="Opacity"><xsl:value-of select="@stop-opacity" /></xsl:attribute></xsl:when> + <xsl:when test="@style and contains(@style, 'stop-opacity:')"> + <xsl:variable name="Opacity" select="substring-after(@style, 'stop-opacity:')" /> + <xsl:attribute name="Opacity"> + <xsl:choose> + <xsl:when test="contains($Opacity, ';')"><xsl:value-of select="substring-before($Opacity, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$Opacity" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_opacity" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Gradient stop offset --> +<xsl:template mode="offset" match="*"> + <xsl:choose> + <xsl:when test="@offset"> + <xsl:attribute name="Offset"> + <xsl:choose> + <xsl:when test="contains(@offset, '%')"><xsl:value-of select="number(substring-before(@offset, '%')) div 100" /></xsl:when> + <xsl:otherwise><xsl:value-of select="@offset" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="@style and contains(@style, 'offset:')"> + <xsl:variable name="Offset" select="substring-after(@style, 'offset:')" /> + <xsl:attribute name="Offset"> + <xsl:choose> + <xsl:when test="contains($Offset, '%')"><xsl:value-of select="number(substring-before($Offset, '%')) div 100" /></xsl:when> + <xsl:when test="contains($Offset, ';')"><xsl:value-of select="substring-before($Offset, ';')" /></xsl:when> + <xsl:otherwise><xsl:value-of select="$Offset" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:when> + <xsl:when test="name(..) = 'g' or name(..) = 'svg'"><xsl:apply-templates mode="stop_offset" select="parent::*"/></xsl:when> + </xsl:choose> +</xsl:template> + +<!-- +// Transforms // +All the matrix, translate, rotate... stuff. +Fixme: XAML transforms don't show the same result as SVG ones with the same values. + +* Parse transform +* Apply transform +* Apply transform v2 +--> + +<!-- Parse transform --> +<xsl:template name="parse_transform"> + <xsl:param name="input" /> + <xsl:choose> + <xsl:when test="starts-with($input, 'matrix(')"> + <MatrixTransform><xsl:attribute name="Matrix"><xsl:value-of select="substring-before(substring-after($input, 'matrix('), ')')" /></xsl:attribute></MatrixTransform> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </xsl:when> + <xsl:when test="starts-with($input, 'scale(')"> + <ScaleTransform> + <xsl:variable name="scale" select="substring-before(substring-after($input, 'scale('), ')')" /> + <xsl:choose> + <xsl:when test="contains($scale, ',')"> + <xsl:attribute name="ScaleX"><xsl:value-of select="substring-before($scale, ',')" /></xsl:attribute> + <xsl:attribute name="ScaleY"><xsl:value-of select="substring-after($scale, ',')" /></xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="ScaleX"><xsl:value-of select="$scale" /></xsl:attribute> + <xsl:attribute name="ScaleY"><xsl:value-of select="$scale" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + </ScaleTransform> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </xsl:when> + <xsl:when test="starts-with($input, 'rotate(')"> + <RotateTransform> + <xsl:attribute name="Angle"><xsl:value-of select="substring-before(substring-after($input, 'rotate('), ')')" /></xsl:attribute> + <xsl:if test="@rx"><xsl:attribute name="CenterX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if> + <xsl:if test="@ry"><xsl:attribute name="CenterY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if> + </RotateTransform> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </xsl:when> + <xsl:when test="starts-with($input, 'skewX(')"> + <SkewTransform> + <xsl:attribute name="AngleX"><xsl:value-of select="substring-before(substring-after($input, 'skewX('), ')')" /></xsl:attribute> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </SkewTransform> + </xsl:when> + <xsl:when test="starts-with($input, 'skewY(')"> + <SkewTransform> + <xsl:attribute name="AngleY"><xsl:value-of select="substring-before(substring-after($input, 'skewY('), ')')" /></xsl:attribute> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </SkewTransform> + </xsl:when> + <xsl:when test="starts-with($input, 'translate(')"> + <TranslateTransform> + <xsl:variable name="translate" select="substring-before(substring-after($input, 'translate('), ')')" /> + <xsl:choose> + <xsl:when test="contains($translate, ',')"> + <xsl:attribute name="X"><xsl:value-of select="substring-before($translate, ',')" /></xsl:attribute> + <xsl:attribute name="Y"><xsl:value-of select="substring-after($translate, ',')" /></xsl:attribute> + </xsl:when> + <xsl:when test="contains($translate, ' ')"> + <xsl:attribute name="X"><xsl:value-of select="substring-before($translate, ' ')" /></xsl:attribute> + <xsl:attribute name="Y"><xsl:value-of select="substring-after($translate, ' ')" /></xsl:attribute> + </xsl:when> + <xsl:otherwise><xsl:attribute name="X"><xsl:value-of select="$translate" /></xsl:attribute></xsl:otherwise> + </xsl:choose> + </TranslateTransform> + <xsl:call-template name="parse_transform"><xsl:with-param name="input" select="substring-after($input, ') ')" /></xsl:call-template> + </xsl:when> + </xsl:choose> +</xsl:template> + +<!-- Apply transform --> +<xsl:template mode="transform" match="*"> + <xsl:param name="mapped_type" /> + <xsl:if test="@transform or @gradientTransform"> + <xsl:variable name="transform"> + <xsl:choose> + <xsl:when test="@transform"><xsl:value-of select="@transform" /></xsl:when> + <xsl:otherwise><xsl:value-of select="@gradientTransform" /></xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="transform_nodes"> + <xsl:call-template name="parse_transform"> + <xsl:with-param name="input" select="$transform" /> + </xsl:call-template> + </xsl:variable> + + <xsl:comment> + <xsl:value-of select="name(.)" /> + </xsl:comment> + + <xsl:choose> + <xsl:when test="$mapped_type and $mapped_type != ''"> + <xsl:element name="{$mapped_type}.RenderTransform"> + <xsl:choose> + <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></xsl:when> + <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"><TransformGroup><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></TransformGroup></xsl:when> + </xsl:choose> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <!-- For instance LinearGradient.Transform --> + <xsl:choose> + <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></xsl:when> + <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"><TransformGroup><xsl:copy-of select="libxslt:node-set($transform_nodes)" /></TransformGroup></xsl:when> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:if> +</xsl:template> + +<!-- Apply transform v2 +Fixme: is this template still in use? --> +<xsl:template mode="transform2" match="*"> + <xsl:choose> + <xsl:when test="@transform"> + <Canvas> + <Canvas.RenderTransform> + <TransformGroup><xsl:apply-templates mode="transform" select="." /></TransformGroup> + </Canvas.RenderTransform> + <xsl:apply-templates mode="forward" select="." /> + </Canvas> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates mode="forward" select="." /> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +<!-- +// Objects // + +* Image +* Text +* Lines +* Rectangle +* Polygon +* Polyline +* Path +* Ellipse +* Circle +--> + +<!-- Image --> +<xsl:template mode="forward" match="*[name(.) = 'image']"> + <Image> + <xsl:apply-templates mode="id" select="." /> + <xsl:if test="@x"><xsl:attribute name="Canvas.Left"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@x" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@y"><xsl:attribute name="Canvas.Top"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@y" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:apply-templates mode="desc" select="." /> + <xsl:apply-templates mode="clip" select="." /> + <xsl:if test="@xlink:href"><xsl:attribute name="Source"><xsl:value-of select="@xlink:href" /></xsl:attribute></xsl:if> + <xsl:if test="@width"><xsl:attribute name="Width"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@width" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@height"><xsl:attribute name="Height"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@height" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Image'" /> + </xsl:apply-templates> + <!--xsl:apply-templates mode="transform" /--> + <xsl:apply-templates mode="forward" /> + </Image> +</xsl:template> + +<!-- Text --> +<xsl:template mode="forward" match="*[name(.) = 'text']"> + <TextBlock> + <xsl:if test="@font-size"><xsl:attribute name="FontSize"><xsl:value-of select="@font-size" /></xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'font-size:')"> + <xsl:variable name="font_size" select="substring-after(@style, 'font-size:')" /> + <xsl:attribute name="FontSize"> + <xsl:choose> + <xsl:when test="contains($font_size, ';')"> + <xsl:value-of select="substring-before($font_size, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$font_size" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@font-weight"><xsl:attribute name="FontWeight"><xsl:value-of select="@font-weight" /></xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'font-weight:')"> + <xsl:variable name="font_weight" select="substring-after(@style, 'font-weight:')" /> + <xsl:attribute name="FontWeight"> + <xsl:choose> + <xsl:when test="contains($font_weight, ';')"> + <xsl:value-of select="substring-before($font_weight, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$font_weight" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@font-family"><xsl:attribute name="FontFamily"><xsl:value-of select="@font-family" /></xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'font-family:')"> + <xsl:variable name="font_family" select="substring-after(@style, 'font-family:')" /> + <xsl:attribute name="FontFamily"> + <xsl:choose> + <xsl:when test="contains($font_family, ';')"> + <xsl:value-of select="substring-before($font_family, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$font_family" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@font-style"><xsl:attribute name="FontStyle"><xsl:value-of select="@font-style" /></xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'font-style:')"> + <xsl:variable name="font_style" select="substring-after(@style, 'font-style:')" /> + <xsl:attribute name="FontStyle"> + <xsl:choose> + <xsl:when test="contains($font_style, ';')"> + <xsl:value-of select="substring-before($font_style, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$font_style" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@fill"><xsl:attribute name="Foreground"><xsl:value-of select="@fill" /></xsl:attribute></xsl:if> + <xsl:if test="@style and contains(@style, 'fill')"> + <xsl:variable name="fill" select="substring-after(@style, 'fill:')" /> + <xsl:attribute name="Foreground"> + <xsl:choose> + <xsl:when test="contains($fill, ';')"> + <xsl:value-of select="substring-before($fill, ';')" /> + </xsl:when> + <xsl:otherwise><xsl:value-of select="$fill" /></xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@text-anchor"> + <xsl:attribute name="HorizontalAlignment"> + <xsl:choose> + <xsl:when test="@text-anchor = 'start'">Left</xsl:when> + <xsl:when test="@text-anchor = 'middle'">Center</xsl:when> + <xsl:when test="@text-anchor = 'end'">Right</xsl:when> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="@width"><xsl:attribute name="Width"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@width" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@height"><xsl:attribute name="Height"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@height" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@x"><xsl:attribute name="Canvas.Left"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@x" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@y"><xsl:attribute name="Canvas.Top"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@y" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + <xsl:apply-templates mode="clip" select="." /> + <!--xsl:apply-templates mode="transform" select="." /--> + <!--xsl:apply-templates mode="forward" /--> + <xsl:if test="text()"><xsl:value-of select="text()" /></xsl:if> + <xsl:if test="*[name(.) = 'tspan']/text()"><xsl:value-of select="*[name(.) = 'tspan']/text()" /></xsl:if> + </TextBlock> +</xsl:template> + +<!-- Lines --> +<xsl:template mode="forward" match="*[name(.) = 'line']"> + <Line> + <xsl:if test="@x1"><xsl:attribute name="X1"><xsl:value-of select="@x1" /></xsl:attribute></xsl:if> + <xsl:if test="@y1"><xsl:attribute name="Y1"><xsl:value-of select="@y1" /></xsl:attribute></xsl:if> + <xsl:if test="@x2"><xsl:attribute name="X2"><xsl:value-of select="@x2" /></xsl:attribute></xsl:if> + <xsl:if test="@y2"><xsl:attribute name="Y2"><xsl:value-of select="@y2" /></xsl:attribute></xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Line'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Line> +</xsl:template> + +<!-- Rectangle --> +<xsl:template mode="forward" match="*[name(.) = 'rect']"> + <Rectangle> + <xsl:if test="@x"><xsl:attribute name="Canvas.Left"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@x" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@y"><xsl:attribute name="Canvas.Top"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@y" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@width"><xsl:attribute name="Width"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@width" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@height"><xsl:attribute name="Height"> + <xsl:call-template name="convert_unit"> + <xsl:with-param name="convert_value" select="@height" /> + </xsl:call-template> + </xsl:attribute></xsl:if> + <xsl:if test="@rx"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if> + <xsl:if test="@ry"><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if> + <xsl:if test="@rx and not(@ry)"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute><xsl:attribute name="RadiusY"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if> + <xsl:if test="@ry and not(@rx)"><xsl:attribute name="RadiusX"><xsl:value-of select="@ry" /></xsl:attribute><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if> + + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="resources" select="." /> + <xsl:apply-templates mode="desc" select="." /> + <xsl:apply-templates mode="clip" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Rectangle'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Rectangle> +</xsl:template> + +<!-- Polygon --> +<xsl:template mode="forward" match="*[name(.) = 'polygon']"> + <Polygon> + <xsl:if test="@points"><xsl:attribute name="Points"><xsl:value-of select="@points" /></xsl:attribute></xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="fill_rule" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Polygon'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Polygon> +</xsl:template> + +<!-- Polyline --> +<xsl:template mode="forward" match="*[name(.) = 'polyline']"> + <Polyline> + <xsl:if test="@points"><xsl:attribute name="Points"><xsl:value-of select="@points" /></xsl:attribute></xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="fill_rule" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Polyline'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Polyline> +</xsl:template> + +<!-- Path --> +<xsl:template mode="forward" match="*[name(.) = 'path']"> + <Path> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + + <xsl:if test="@d"> + <xsl:choose> + <xsl:when test="$silverlight_compatible = 1"> + <xsl:attribute name="Data"> + <xsl:value-of select="translate(@d , ',', ' ')" /> + </xsl:attribute> + </xsl:when> + <xsl:otherwise> + <Path.Data> + <PathGeometry> + <xsl:attribute name="Figures"> + <xsl:value-of select="translate(@d , ',', ' ')" /> + </xsl:attribute> + <xsl:apply-templates mode="fill_rule" select="." /> + </PathGeometry> + </Path.Data> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Path'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Path> +</xsl:template> + +<!-- Ellipse --> +<xsl:template mode="forward" match="*[name(.) = 'ellipse']"> + <Ellipse> + <xsl:variable name="cx"> + <xsl:choose> + <xsl:when test="@cx"><xsl:value-of select="@cx" /></xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="cy"> + <xsl:choose> + <xsl:when test="@cy"><xsl:value-of select="@cy" /></xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="@rx"> + <xsl:attribute name="Canvas.Left"><xsl:value-of select='format-number($cx - @rx, "#.#")' /></xsl:attribute> + <xsl:attribute name="Width"><xsl:value-of select='format-number(2 * @rx, "#.#")' /></xsl:attribute> + </xsl:if> + <xsl:if test="@ry"> + <xsl:attribute name="Canvas.Top"><xsl:value-of select='format-number($cy - @ry, "#.#")' /></xsl:attribute> + <xsl:attribute name="Height"><xsl:value-of select='format-number(2 * @ry, "#.#")' /></xsl:attribute> + </xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + <xsl:apply-templates mode="clip" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Ellipse'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Ellipse> +</xsl:template> + +<!-- Circle --> +<xsl:template mode="forward" match="*[name(.) = 'circle']"> + <Ellipse> + <xsl:variable name="cx"> + <xsl:choose> + <xsl:when test="@cx"><xsl:value-of select="@cx" /></xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="cy"> + <xsl:choose> + <xsl:when test="@cy"><xsl:value-of select="@cy" /></xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="@r"> + <xsl:attribute name="Canvas.Left"><xsl:value-of select='format-number($cx - @r, "#.#")' /></xsl:attribute> + <xsl:attribute name="Canvas.Top"><xsl:value-of select='format-number($cy - @r, "#.#")' /></xsl:attribute> + <xsl:attribute name="Width"><xsl:value-of select='format-number(2 * @r, "#.#")' /></xsl:attribute> + <xsl:attribute name="Height"><xsl:value-of select='format-number(2 * @r, "#.#")' /></xsl:attribute> + </xsl:if> + <xsl:apply-templates mode="id" select="." /> + <xsl:apply-templates mode="template_fill" select="." /> + <xsl:apply-templates mode="template_stroke" select="." /> + <xsl:apply-templates mode="stroke_width" select="." /> + <xsl:apply-templates mode="stroke_miterlimit" select="." /> + <xsl:apply-templates mode="stroke_dasharray" select="." /> + <xsl:apply-templates mode="stroke_dashoffset" select="." /> + <xsl:apply-templates mode="stroke_linejoin" select="." /> + <xsl:apply-templates mode="stroke_linecap" select="." /> + <xsl:apply-templates mode="filter_effect" select="." /> + <xsl:apply-templates mode="desc" select="." /> + <xsl:apply-templates mode="clip" select="." /> + + <xsl:apply-templates mode="transform" select="."> + <xsl:with-param name="mapped_type" select="'Ellipse'" /> + </xsl:apply-templates> + + <xsl:apply-templates mode="forward" /> + </Ellipse> +</xsl:template> + +<!-- +// Geometry // +* Generic clip path template +* Geometry for circle +* Geometry for rectangle +--> + +<!-- Generic clip path template --> +<xsl:template mode="forward" match="*[name(.) = 'clipPath']"> + <xsl:apply-templates mode="geometry" /> +</xsl:template> + +<!-- Geometry for circle --> +<xsl:template mode="geometry" match="*[name(.) = 'circle']"> + <EllipseGeometry> + <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if> + <xsl:if test="@cx and @cy"><xsl:attribute name="Center"><xsl:value-of select="concat(@cx, ',', @cy)" /></xsl:attribute></xsl:if> + <xsl:if test="@r"> + <xsl:attribute name="RadiusX"><xsl:value-of select="@r" /></xsl:attribute> + <xsl:attribute name="RadiusY"><xsl:value-of select="@r" /></xsl:attribute> + </xsl:if> + </EllipseGeometry> +</xsl:template> + +<!-- Geometry for rectangle --> +<xsl:template mode="geometry" match="*[name(.) = 'rect']"> + <RectangleGeometry> + <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if> + <!-- + <xsl:if test="@x"><xsl:attribute name="Canvas.Left"><xsl:value-of select="@x" /></xsl:attribute></xsl:if> + <xsl:if test="@y"><xsl:attribute name="Canvas.Top"><xsl:value-of select="@y" /></xsl:attribute></xsl:if> + <xsl:if test="@width"><xsl:attribute name="Width"><xsl:value-of select="@width" /></xsl:attribute></xsl:if> + <xsl:if test="@height"><xsl:attribute name="Height"><xsl:value-of select="@height" /></xsl:attribute></xsl:if> + <xsl:if test="@rx"><xsl:attribute name="RadiusX"><xsl:value-of select="@rx" /></xsl:attribute></xsl:if> + <xsl:if test="@ry"><xsl:attribute name="RadiusY"><xsl:value-of select="@ry" /></xsl:attribute></xsl:if> + --> + <xsl:attribute name="Rect"><xsl:value-of select="concat('0, 0, ', @width, ', ', @height)" /></xsl:attribute> + </RectangleGeometry> +</xsl:template> + +</xsl:stylesheet> diff --git a/share/extensions/svg_and_media_zip_output.py b/share/extensions/svg_and_media_zip_output.py index 8308d6062..640c9ede4 100644 --- a/share/extensions/svg_and_media_zip_output.py +++ b/share/extensions/svg_and_media_zip_output.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python """ svg_and_media_zip_output.py An extention which collects all images to the documents directory and @@ -136,4 +136,4 @@ if __name__ == '__main__': #pragma: no cover e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/svg_regex.py b/share/extensions/svg_regex.py index 10fd9c385..3d0a21520 100644 --- a/share/extensions/svg_regex.py +++ b/share/extensions/svg_regex.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # This software is OSI Certified Open Source Software. # OSI Certified is a certification mark of the Open Source Initiative. # diff --git a/share/extensions/svgcalendar.inx b/share/extensions/svgcalendar.inx index fd1af0544..56f5f62ab 100644 --- a/share/extensions/svgcalendar.inx +++ b/share/extensions/svgcalendar.inx @@ -1,139 +1,137 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Calendar</_name> - <id>org.inkscape.render.calendar</id> - - <dependency type="executable" location="extensions">svgcalendar.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="tab" type="notebook"> - <page name="tab" _gui-text="Configuration"> - <param name="month" type="int" min="0" max="12" _gui-text="Month (0 for all)">0</param> - <param name="year" type="int" min="0" max="3000" _gui-text="Year (0 for current)">0</param> - <param name="fill-empty-day-boxes" type="boolean" _gui-text="Fill empty day boxes with next month's days">true</param> - <param name="start-day" type="enum" _gui-text="Week start day"> - <_item value="sun">Sunday</_item> - <_item value="mon">Monday</_item> - </param> - <param name="weekend" type="enum" _gui-text="Weekend"> - <_item value="sat+sun">Saturday and Sunday</_item> - <_item value="sat">Saturday</_item> - <_item value="sun">Sunday</_item> - </param> - </page> - <page name="tab" _gui-text="Layout"> - <param name="auto-organize" type="boolean" _gui-text="Automatically set size and position">true</param> - <_param name="organize-help" type="description">The options below have no influence when the above is checked.</_param> - <param name="months-per-line" type="int" min="1" max="12" _gui-text="Months per line">3</param> - <param name="month-width" type="string" _gui-text="Month Width">6cm</param> - <param name="month-margin" type="string" _gui-text="Month Margin">1cm</param> - </page> - <page name="tab" _gui-text="Colors"> - <param name="color-year" type="string" _gui-text="Year color">#808080</param> - <param name="color-month" type="string" _gui-text="Month color">#686868</param> - <param name="color-day-name" type="string" _gui-text="Weekday name color ">#909090</param> - <param name="color-day" type="string" _gui-text="Day color">#000000</param> - <param name="color-weekend" type="string" _gui-text="Weekend day color">#787878</param> - <param name="color-nmd" type="string" _gui-text="Next month day color">#B0B0B0</param> - </page> - <page name="tab" _gui-text="Localization"> - <_param name="l10n-help" type="description">You may change the names for other languages:</_param> - <_param name="month-names" type="string" _gui-text="Month names" xml:space="preserve">January February March April May June July August September October November December</_param> - <_param name="day-names" type="string" _gui-text="Day names" xml:space="preserve">Sun Mon Tue Wed Thu Fri Sat</_param> - <_param name="day-names-help" type="description">(The day names list must start from Sunday)</_param> - <param name="encoding" _gui-text="Char Encoding" type="optiongroup" appearance="minimal"> - <option value="arabic">arabic</option> - <option value="big5-tw">big5-tw</option> - <option value="big5-hkscs">big5-hkscs</option> - <option value="chinese">chinese</option> - <option value="cp737">cp737</option> - <option value="cp856">cp856</option> - <option value="cp874">cp874</option> - <option value="cp875">cp875</option> - <option value="cp1006">cp1006</option> - <option value="cyrillic">cyrillic</option> - <option value="cyrillic-asian">cyrillic-asian</option> - <option value="eucjis2004">eucjis2004</option> - <option value="eucjisx0213">eucjisx0213</option> - <option value="gbk">gbk</option> - <option value="gb18030-2000">gb18030-2000</option> - <option value="greek">greek</option> - <option value="hebrew">hebrew</option> - <option value="hz-gb">hz-gb</option> - <option value="IBM037">IBM037</option> - <option value="IBM424">IBM424</option> - <option value="IBM437">IBM437</option> - <option value="IBM500">IBM500</option> - <option value="IBM775">IBM775</option> - <option value="IBM850">IBM850</option> - <option value="IBM852">IBM852</option> - <option value="IBM855">IBM855</option> - <option value="IBM857">IBM857</option> - <option value="IBM860">IBM860</option> - <option value="IBM861">IBM861</option> - <option value="IBM862">IBM862</option> - <option value="IBM863">IBM863</option> - <option value="IBM864">IBM864</option> - <option value="IBM865">IBM865</option> - <option value="IBM866">IBM866</option> - <option value="IBM869">IBM869</option> - <option value="IBM1026">IBM1026</option> - <option value="IBM1140">IBM1140</option> - <option value="iso-2022-jp">iso-2022-jp</option> - <option value="iso-2022-jp-1">iso-2022-jp-1</option> - <option value="iso-2022-jp-2">iso-2022-jp-2</option> - <option value="iso-2022-jp-2004">iso-2022-jp-2004</option> - <option value="iso-2022-jp-3">iso-2022-jp-3</option> - <option value="iso-2022-jp-ext">iso-2022-jp-ext</option> - <option value="iso-2022-kr">iso-2022-kr</option> - <option value="johab">johab</option> - <option value="korean">korean</option> - <option value="koi8_r">koi8_r</option> - <option value="koi8_u">koi8_u</option> - <option value="latin1">latin1</option> - <option value="latin2">latin2</option> - <option value="latin3">latin3</option> - <option value="latin4">latin4</option> - <option value="latin5">latin5</option> - <option value="latin6">latin6</option> - <option value="latin8">latin8</option> - <option value="iso-8859-15">Latin - iso-8859-15 - Western Europe</option> - <option value="macgreek">macgreek</option> - <option value="maciceland">maciceland</option> - <option value="maccentraleurope">maccentraleurope</option> - <option value="macroman">macroman</option> - <option value="macturkish">macturkish</option> - <option value="ms932">ms932</option> - <option value="ms949">ms949</option> - <option value="ms950">ms950</option> - <option value="sjis">sjis</option> - <option value="sjis2004">sjis2004</option> - <option value="sjisx0213">sjisx0213</option> - <option value="u-jis">u-jis</option> - <option value="us-ascii">us-ascii</option> - <option value="windows-1250">Windows - Central and Eastern Europe</option> - <option value="windows-1251">Windows - Russian and more</option> - <option value="windows-1252">Windows - Western Europe</option> - <option value="windows-1253">Windows - Greek</option> - <option value="windows-1254">Windows - Turkish</option> - <option value="windows-1255">Windows - Hebrew</option> - <option value="windows-1256">Windows - Arabic</option> - <option value="windows-1257">Windows - Baltic languages</option> - <option value="windows-1258">Windows - Vietnamese</option> - <option value="utf_32">UTF-32 - All languages</option> - <option value="utf_16">UTF-16 - All languages</option> - <option value="utf_8">UTF-8 - All languages</option> - </param> - <_param name="encoding-help" type="description">(Select your system encoding. More information at http://docs.python.org/library/codecs.html#standard-encodings)</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">svgcalendar.py</command> - </script> + <_name>Calendar</_name> + <id>org.inkscape.render.calendar</id> + <dependency type="executable" location="extensions">svgcalendar.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="config" _gui-text="Configuration"> + <param name="year" type="int" min="0" max="3000" _gui-text="Year (4 digits):">2011</param> + <param name="month" type="int" min="0" max="12" _gui-text="Month (0 for all):">0</param> + <param name="fill-empty-day-boxes" type="boolean" _gui-text="Fill empty day boxes with next month's days">true</param> + <param name="start-day" type="enum" _gui-text="Week start day"> + <_item value="sun">Sunday</_item> + <_item value="mon">Monday</_item> + </param> + <param name="weekend" type="enum" _gui-text="Weekend:"> + <_item value="sat+sun">Saturday and Sunday</_item> + <_item value="sat">Saturday</_item> + <_item value="sun">Sunday</_item> + </param> + </page> + <page name="layout" _gui-text="Layout"> + <param name="auto-organize" type="boolean" _gui-text="Automatically set size and position">true</param> + <_param name="organize-help" type="description">The options below have no influence when the above is checked.</_param> + <param name="months-per-line" type="int" min="1" max="12" _gui-text="Months per line:">3</param> + <param name="month-width" type="string" _gui-text="Month Width:">6cm</param> + <param name="month-margin" type="string" _gui-text="Month Margin:">1cm</param> + </page> + <page name="colors" _gui-text="Colors"> + <param name="color-year" type="string" _gui-text="Year color:">#808080</param> + <param name="color-month" type="string" _gui-text="Month color:">#686868</param> + <param name="color-day-name" type="string" _gui-text="Weekday name color:">#909090</param> + <param name="color-day" type="string" _gui-text="Day color:">#000000</param> + <param name="color-weekend" type="string" _gui-text="Weekend day color:">#787878</param> + <param name="color-nmd" type="string" _gui-text="Next month day color:">#B0B0B0</param> + </page> + <page name="localization" _gui-text="Localization"> + <_param name="l10n-help" type="description">You may change the names for other languages:</_param> + <_param name="month-names" type="string" _gui-text="Month names:" xml:space="preserve">January February March April May June July August September October November December</_param> + <_param name="day-names" type="string" _gui-text="Day names:" xml:space="preserve">Sun Mon Tue Wed Thu Fri Sat</_param> + <_param name="day-names-help" type="description">The day names list must start from Sunday.</_param> + <param name="encoding" _gui-text="Char Encoding:" type="enum"> + <item value="arabic">arabic</item> + <item value="big5-tw">big5-tw</item> + <item value="big5-hkscs">big5-hkscs</item> + <item value="chinese">chinese</item> + <item value="cp737">cp737</item> + <item value="cp856">cp856</item> + <item value="cp874">cp874</item> + <item value="cp875">cp875</item> + <item value="cp1006">cp1006</item> + <item value="cyrillic">cyrillic</item> + <item value="cyrillic-asian">cyrillic-asian</item> + <item value="eucjis2004">eucjis2004</item> + <item value="eucjisx0213">eucjisx0213</item> + <item value="gbk">gbk</item> + <item value="gb18030-2000">gb18030-2000</item> + <item value="greek">greek</item> + <item value="hebrew">hebrew</item> + <item value="hz-gb">hz-gb</item> + <item value="IBM037">IBM037</item> + <item value="IBM424">IBM424</item> + <item value="IBM437">IBM437</item> + <item value="IBM500">IBM500</item> + <item value="IBM775">IBM775</item> + <item value="IBM850">IBM850</item> + <item value="IBM852">IBM852</item> + <item value="IBM855">IBM855</item> + <item value="IBM857">IBM857</item> + <item value="IBM860">IBM860</item> + <item value="IBM861">IBM861</item> + <item value="IBM862">IBM862</item> + <item value="IBM863">IBM863</item> + <item value="IBM864">IBM864</item> + <item value="IBM865">IBM865</item> + <item value="IBM866">IBM866</item> + <item value="IBM869">IBM869</item> + <item value="IBM1026">IBM1026</item> + <item value="IBM1140">IBM1140</item> + <item value="iso-2022-jp">iso-2022-jp</item> + <item value="iso-2022-jp-1">iso-2022-jp-1</item> + <item value="iso-2022-jp-2">iso-2022-jp-2</item> + <item value="iso-2022-jp-2004">iso-2022-jp-2004</item> + <item value="iso-2022-jp-3">iso-2022-jp-3</item> + <item value="iso-2022-jp-ext">iso-2022-jp-ext</item> + <item value="iso-2022-kr">iso-2022-kr</item> + <item value="johab">johab</item> + <item value="korean">korean</item> + <item value="koi8_r">koi8_r</item> + <item value="koi8_u">koi8_u</item> + <item value="latin1">latin1</item> + <item value="latin2">latin2</item> + <item value="latin3">latin3</item> + <item value="latin4">latin4</item> + <item value="latin5">latin5</item> + <item value="latin6">latin6</item> + <item value="latin8">latin8</item> + <item value="iso-8859-15">Latin - iso-8859-15 - Western Europe</item> + <item value="macgreek">macgreek</item> + <item value="maciceland">maciceland</item> + <item value="maccentraleurope">maccentraleurope</item> + <item value="macroman">macroman</item> + <item value="macturkish">macturkish</item> + <item value="ms932">ms932</item> + <item value="ms949">ms949</item> + <item value="ms950">ms950</item> + <item value="sjis">sjis</item> + <item value="sjis2004">sjis2004</item> + <item value="sjisx0213">sjisx0213</item> + <item value="u-jis">u-jis</item> + <item value="us-ascii">us-ascii</item> + <item value="windows-1250">Windows - Central and Eastern Europe</item> + <item value="windows-1251">Windows - Russian and more</item> + <item value="windows-1252">Windows - Western Europe</item> + <item value="windows-1253">Windows - Greek</item> + <item value="windows-1254">Windows - Turkish</item> + <item value="windows-1255">Windows - Hebrew</item> + <item value="windows-1256">Windows - Arabic</item> + <item value="windows-1257">Windows - Baltic languages</item> + <item value="windows-1258">Windows - Vietnamese</item> + <item value="utf_32">UTF-32 - All languages</item> + <item value="utf_16">UTF-16 - All languages</item> + <item value="utf_8">UTF-8 - All languages</item> + </param> + <_param name="encoding-help" type="description">Select your system encoding. More information at http://docs.python.org/library/codecs.html#standard-encodings.</_param> + </page> + </param> + <effect needs-live-preview="false"> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">svgcalendar.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/svgcalendar.py b/share/extensions/svgcalendar.py index b62863927..8390c33f7 100755 --- a/share/extensions/svgcalendar.py +++ b/share/extensions/svgcalendar.py @@ -131,6 +131,8 @@ class SVGCalendar (inkex.Effect): self.options.day_names = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] # Convert year 0 to current year: if self.options.year == 0: self.options.year = datetime.today().year + # Year 1 starts it's week at monday, obligatorily + if self.options.year == 1: self.options.start_day = 'mon' # Set the calendar start day: if self.options.start_day=='sun': calendar.setfirstweekday(6) @@ -266,8 +268,9 @@ class SVGCalendar (inkex.Effect): gdays = inkex.etree.SubElement(g, 'g') cal = calendar.monthcalendar(self.options.year,m) if m == 1: - before_month = \ - self.in_line_month( calendar.monthcalendar(self.options.year-1, 12) ) + if self.options.year > 1: + before_month = \ + self.in_line_month( calendar.monthcalendar(self.options.year-1, 12) ) else: before_month = \ self.in_line_month( calendar.monthcalendar(self.options.year, m-1) ) @@ -297,8 +300,8 @@ class SVGCalendar (inkex.Effect): 'x': str( self.day_w * week_x ), 'y': str( self.day_h * (week_y+2) ) } if day==0 and not self.options.fill_edb: - pass # draw nothing - elif day==0: + pass # draw nothing + elif day==0: if before: inkex.etree.SubElement(gdays, 'text', txt_atts).text = str( before_month[-bmd] ) bmd -= 1 diff --git a/share/extensions/text_braille.py b/share/extensions/text_braille.py index 3dcbbc6ac..09300f891 100644 --- a/share/extensions/text_braille.py +++ b/share/extensions/text_braille.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python #encoding: utf-8 import chardataeffect, inkex, string diff --git a/share/extensions/text_flipcase.py b/share/extensions/text_flipcase.py index 167f7f89c..6ddb9d5ea 100644 --- a/share/extensions/text_flipcase.py +++ b/share/extensions/text_flipcase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/text_lowercase.py b/share/extensions/text_lowercase.py index 96dcef3fc..c5e9e6279 100644 --- a/share/extensions/text_lowercase.py +++ b/share/extensions/text_lowercase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/text_randomcase.py b/share/extensions/text_randomcase.py index 0200aef3d..74c061a7c 100644 --- a/share/extensions/text_randomcase.py +++ b/share/extensions/text_randomcase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string import random diff --git a/share/extensions/text_replace.py b/share/extensions/text_replace.py index 6fb08cd27..b5d960430 100644 --- a/share/extensions/text_replace.py +++ b/share/extensions/text_replace.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/text_sentencecase.py b/share/extensions/text_sentencecase.py index c5929ceb0..43460efc5 100644 --- a/share/extensions/text_sentencecase.py +++ b/share/extensions/text_sentencecase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/text_titlecase.py b/share/extensions/text_titlecase.py index 2fd3c49c3..1af0db26b 100644 --- a/share/extensions/text_titlecase.py +++ b/share/extensions/text_titlecase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/text_uppercase.py b/share/extensions/text_uppercase.py index f5a51945d..772c1fd88 100644 --- a/share/extensions/text_uppercase.py +++ b/share/extensions/text_uppercase.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import chardataeffect, inkex, string class C(chardataeffect.CharDataEffect): diff --git a/share/extensions/triangle.inx b/share/extensions/triangle.inx index 3c79ca42c..0c66ed907 100644 --- a/share/extensions/triangle.inx +++ b/share/extensions/triangle.inx @@ -4,23 +4,24 @@ <id>math.triangle</id> <dependency type="executable" location="extensions">triangle.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="s_a" type="float" min="0.01" max="10000" _gui-text="Side Length a / px">100.0</param> - <param name="s_b" type="float" min="0.01" max="10000" _gui-text="Side Length b / px">100.0</param> - <param name="s_c" type="float" min="0.01" max="10000" _gui-text="Side Length c / px">100.0</param> - <param name="a_a" type="float" min="0" max="180" _gui-text="Angle a / deg">60</param> - <param name="a_b" type="float" min="0" max="180" _gui-text="Angle b / deg">30</param> - <param name="a_c" type="float" min="0" max="180" _gui-text="Angle c / deg">90</param> - <param name="mode" type="optiongroup" _gui-text="Mode" appearance="minimal"> - <_option value="3_sides">From Three Sides</_option> - <_option value="s_ab_a_c">From Sides a, b and Angle c</_option> - <_option value="s_ab_a_a">From Sides a, b and Angle a</_option> - <_option value="s_a_a_ab">From Side a and Angles a, b</_option> - <_option value="s_c_a_ab">From Side c and Angles a, b</_option></param> + <param name="s_a" type="float" min="0.01" max="10000" _gui-text="Side Length a (px):">100.0</param> + <param name="s_b" type="float" min="0.01" max="10000" _gui-text="Side Length b (px):">100.0</param> + <param name="s_c" type="float" min="0.01" max="10000" _gui-text="Side Length c (px):">100.0</param> + <param name="a_a" type="float" min="0" max="180" _gui-text="Angle a (deg):">60</param> + <param name="a_b" type="float" min="0" max="180" _gui-text="Angle b (deg):">30</param> + <param name="a_c" type="float" min="0" max="180" _gui-text="Angle c (deg):">90</param> + <param name="mode" type="enum" _gui-text="Mode:"> + <_item value="3_sides">From Three Sides</_item> + <_item value="s_ab_a_c">From Sides a, b and Angle c</_item> + <_item value="s_ab_a_a">From Sides a, b and Angle a</_item> + <_item value="s_a_a_ab">From Side a and Angles a, b</_item> + <_item value="s_c_a_ab">From Side c and Angles a, b</_item> + </param> <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> + <effects-menu> + <submenu _name="Render"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">triangle.py</command> diff --git a/share/extensions/triangle.py b/share/extensions/triangle.py index 965de243e..81945f370 100644 --- a/share/extensions/triangle.py +++ b/share/extensions/triangle.py @@ -194,4 +194,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/uniconv-ext.py b/share/extensions/uniconv-ext.py index d3d69546c..246340e89 100644 --- a/share/extensions/uniconv-ext.py +++ b/share/extensions/uniconv-ext.py @@ -57,8 +57,8 @@ if cmd == None: 'http://sk1project.org/modules.php?name=Products&product=uniconvertor\n'+\ 'and install into your Inkscape\'s Python location\n')) sys.exit(1) - cmd = 'python -c "import uniconvertor"' + cmd = 'python -c "import uniconvertor; uniconvertor.uniconv_run()"' run((cmd+' "%s" "%%s"') % sys.argv[1].replace("%","%%"), "UniConvertor") -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/uniconv_output.py b/share/extensions/uniconv_output.py index f7746c2f4..30d1c2fe0 100644 --- a/share/extensions/uniconv_output.py +++ b/share/extensions/uniconv_output.py @@ -123,8 +123,8 @@ def get_command(): 'http://sk1project.org/modules.php?name=Products&product=uniconvertor\n'+\ 'and install into your Inkscape\'s Python location\n')) sys.exit(1) - cmd = 'python -c "from uniconvertor import uniconv; uniconv();"' + cmd = 'python -c "import uniconvertor; uniconvertor.uniconv_run();"' return cmd -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/web-set-att.inx b/share/extensions/web-set-att.inx index 5bb14d285..65b35bada 100644 --- a/share/extensions/web-set-att.inx +++ b/share/extensions/web-set-att.inx @@ -1,48 +1,52 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Set Attributes</_name> - <id>org.inkscape.web.set-att</id> - <dependency type="executable" location="extensions">web-set-att.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="intro" type="description">This effect adds a feature visible (or usable) only on a SVG enabled web browser (like Firefox).</_param> - <_param name="sep1" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> - <_param name="help" type="description">This effect sets one or more attributes in the second selected element, when a defined event occurs on the first selected element.</_param> - <_param name="sep2" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> - <_param name="help" type="description">If you want to set more than one attribute, you must separate this with a space, and only with a space.</_param> - <param name="att" type="string" _gui-text="Attribute to set">fill stroke stroke-width</param> - <param name="when" type="enum" _gui-text="When should the set be done?"> - <_item value="onclick">on click</_item> - <_item value="onfocusin">on focus</_item> - <_item value="onfocusout">on blur</_item> - <_item value="onactivate">on activate</_item> - <_item value="onmousedown">on mouse down</_item> - <_item value="onmouseup">on mouse up</_item> - <_item value="onmouseover">on mouse over</_item> - <_item value="onmousemove">on mouse move</_item> - <_item value="onmouseout">on mouse out</_item> - <_item value="onload">on element loaded</_item> - </param> - <_param name="help" type="description">The list of values must have the same size as the attributes list.</_param> - <param name="val" type="string" _gui-text="Value to set">red black 5px</param> - <param name="compatibility" type="enum" _gui-text="Compatibility with previews code to this event"> - <_item value="append">Run it after</_item> - <_item value="prepend">Run it before</_item> - <_item value="replace">Replace</_item> - </param> - <_param name="help" type="description">The next parameter is useful when you select more than two elements</_param> - <param name="from-and-to" type="enum" _gui-text="Source and destination of setting"> - <_item value="g-to-one">All selected ones set an attribute in the last one</_item> - <_item value="one-to-g">The first selected sets an attribute in all others</_item> - </param> - <effect> + <_name>Set Attributes</_name> + <id>org.inkscape.web.set-att</id> + <dependency type="executable" location="extensions">web-set-att.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="att" type="string" _gui-text="Attribute to set:">fill stroke stroke-width</param> + <param name="when" type="enum" _gui-text="When should the set be done:"> + <_item value="onclick">on click</_item> + <_item value="onfocusin">on focus</_item> + <_item value="onfocusout">on blur</_item> + <_item value="onactivate">on activate</_item> + <_item value="onmousedown">on mouse down</_item> + <_item value="onmouseup">on mouse up</_item> + <_item value="onmouseover">on mouse over</_item> + <_item value="onmousemove">on mouse move</_item> + <_item value="onmouseout">on mouse out</_item> + <_item value="onload">on element loaded</_item> + </param> + <_param name="help" type="description">The list of values must have the same size as the attributes list.</_param> + <param name="val" type="string" _gui-text="Value to set:">red black 5px</param> + <param name="compatibility" type="enum" _gui-text="Compatibility with previews code to this event:"> + <_item value="append">Run it after</_item> + <_item value="prepend">Run it before</_item> + <_item value="replace">Replace</_item> + </param> + <_param name="help" type="description">The next parameter is useful when you select more than two elements</_param> + <param name="from-and-to" type="enum" _gui-text="Source and destination of setting:"> + <_item value="g-to-one">All selected ones set an attribute in the last one</_item> + <_item value="one-to-g">The first selected sets an attribute in all others</_item> + </param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="intro" type="description">This effect adds a feature visible (or usable) only on a SVG enabled web browser (like Firefox).</_param> + <_param name="desc1" type="description">This effect sets one or more attributes in the second selected element, when a defined event occurs on the first selected element.</_param> + <_param name="desc2" type="description">If you want to set more than one attribute, you must separate this with a space, and only with a space.</_param> + </page> + </param> + <effect> <object-type>all</object-type> - <effects-menu> - <submenu _name="Web"> - <submenu name="JavaScript"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">web-set-att.py</command> - </script> + <effects-menu> + <submenu _name="Web"> + <submenu name="JavaScript"/> + </submenu> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">web-set-att.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/web-set-att.py b/share/extensions/web-set-att.py index 7878cd208..65dd5a5b4 100755 --- a/share/extensions/web-set-att.py +++ b/share/extensions/web-set-att.py @@ -44,6 +44,10 @@ class InkWebTransmitAtt(inkwebeffect.InkWebEffect): action="store", type="string", dest="from_and_to", default="g-to-one", help='Who transmit to Who? "g-to-one" All set the last. "one-to-g" The first set all.') + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def effect(self): self.ensureInkWebSupport() diff --git a/share/extensions/web-transmit-att.inx b/share/extensions/web-transmit-att.inx index caf284b93..343f65f61 100644 --- a/share/extensions/web-transmit-att.inx +++ b/share/extensions/web-transmit-att.inx @@ -4,43 +4,47 @@ <id>org.inkscape.web.transmit-att</id> <dependency type="executable" location="extensions">web-transmit-att.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="intro" type="description">This effect adds a feature visible (or usable) only on a SVG enabled web browser (like Firefox).</_param> - <_param name="sep1" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> - <_param name="help" type="description">This effect transmits one or more attributes from the first selected element to the second when an event occurs.</_param> - <_param name="sep2" type="description">••••••••••••••••••••••••••••••••••••••••••••••••</_param> - <_param name="help" type="description">If you want to transmit more than one attribute, you should separate this with a space, and only with a space.</_param> - <param name="att" type="string" _gui-text="Attribute to transmit">fill</param> - <param name="when" type="enum" _gui-text="When to transmit"> - <_item value="onclick">on click</_item> - <_item value="onfocusin">on focus</_item> - <_item value="onfocusout">on blur</_item> - <_item value="onactivate">on activate</_item> - <_item value="onmousedown">on mouse down</_item> - <_item value="onmouseup">on mouse up</_item> - <_item value="onmouseover">on mouse over</_item> - <_item value="onmousemove">on mouse move</_item> - <_item value="onmouseout">on mouse out</_item> - <_item value="onload">on element loaded</_item> - </param> - <param name="compatibility" type="enum" _gui-text="Compatibility with previews code to this event"> - <_item value="append">Run it after</_item> - <_item value="prepend">Run it before</_item> - <_item value="replace">Replace</_item> - </param> - <_param name="help" type="description">The next parameter is useful when you select more than two elements</_param> - <param name="from-and-to" type="enum" _gui-text="Source and destination of transmitting"> - <_item value="g-to-one">All selected ones transmit to the last one</_item> - <_item value="one-to-g">The first selected transmits to all others</_item> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Web"> - <submenu name="JavaScript"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">web-transmit-att.py</command> - </script> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="att" type="string" _gui-text="Attribute to transmit:">fill</param> + <param name="when" type="enum" _gui-text="When to transmit:"> + <_item value="onclick">on click</_item> + <_item value="onfocusin">on focus</_item> + <_item value="onfocusout">on blur</_item> + <_item value="onactivate">on activate</_item> + <_item value="onmousedown">on mouse down</_item> + <_item value="onmouseup">on mouse up</_item> + <_item value="onmouseover">on mouse over</_item> + <_item value="onmousemove">on mouse move</_item> + <_item value="onmouseout">on mouse out</_item> + <_item value="onload">on element loaded</_item> + </param> + <param name="compatibility" type="enum" _gui-text="Compatibility with previews code to this event:"> + <_item value="append">Run it after</_item> + <_item value="prepend">Run it before</_item> + <_item value="replace">Replace</_item> + </param> + <_param name="help" type="description">The next parameter is useful when you select more than two elements</_param> + <param name="from-and-to" type="enum" _gui-text="Source and destination of transmitting:"> + <_item value="g-to-one">All selected ones transmit to the last one</_item> + <_item value="one-to-g">The first selected transmits to all others</_item> + </param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="intro" type="description">This effect adds a feature visible (or usable) only on a SVG enabled web browser (like Firefox).</_param> + <_param name="desc1" type="description">This effect transmits one or more attributes from the first selected element to the second when an event occurs.</_param> + <_param name="desc2" type="description">If you want to transmit more than one attribute, you should separate this with a space, and only with a space.</_param> + </page> + </param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Web"> + <submenu name="JavaScript"/> + </submenu> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">web-transmit-att.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/web-transmit-att.py b/share/extensions/web-transmit-att.py index c597a41f0..35f16e145 100644 --- a/share/extensions/web-transmit-att.py +++ b/share/extensions/web-transmit-att.py @@ -40,6 +40,10 @@ class InkWebTransmitAtt(inkwebeffect.InkWebEffect): action="store", type="string", dest="from_and_to", default="g-to-one", help='Who transmit to Who? "g-to-one" All tramsmit to the last. "one-to-g" The first transmit to all.') + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def effect(self): self.ensureInkWebSupport() diff --git a/share/extensions/webslicer_create_group.inx b/share/extensions/webslicer_create_group.inx index 2238a0901..aaa327ea7 100644 --- a/share/extensions/webslicer_create_group.inx +++ b/share/extensions/webslicer_create_group.inx @@ -1,33 +1,39 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Set a layout group</_name> - <id>org.inkscape.web.slicer.create-group</id> - <dependency type="executable" location="extensions">webslicer_effect.py</dependency> - <dependency type="executable" location="extensions">webslicer_create_group.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="about" type="description">Layout Group is only about to help a better code generation (if you need it). To use this, you must to select some "Slicer rectangles" first.</_param> - <param name="html-id" type="string" _gui-text="HTML id attribute:"></param> - <param name="html-class" type="string" _gui-text="HTML class attribute:"></param> - <param name="width-unity" type="enum" _gui-text="Width unit:"> - <_item value="px">Pixel (fixed)</_item> - <_item value="percent">Percent (relative to parent size)</_item> - <_item value="undefined">Undefined (relative to non-floating content size)</_item> - </param> - <param name="height-unity" type="enum" _gui-text="Height unit:"> - <_item value="px">Pixel (fixed)</_item> - <_item value="percent">Percent (relative to parent size)</_item> - <_item value="undefined">Undefined (relative to non-floating content size)</_item> - </param> - <param name="bg-color" type="string" _gui-text="Background color:"></param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Web"> - <submenu _name="Slicer"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">webslicer_create_group.py</command> - </script> + <_name>Set a layout group</_name> + <id>org.inkscape.web.slicer.create-group</id> + <dependency type="executable" location="extensions">webslicer_effect.py</dependency> + <dependency type="executable" location="extensions">webslicer_create_group.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="html-id" type="string" _gui-text="HTML id attribute:"></param> + <param name="html-class" type="string" _gui-text="HTML class attribute:"></param> + <param name="width-unity" type="enum" _gui-text="Width unit:"> + <_item value="px">Pixel (fixed)</_item> + <_item value="percent">Percent (relative to parent size)</_item> + <_item value="undefined">Undefined (relative to non-floating content size)</_item> + </param> + <param name="height-unity" type="enum" _gui-text="Height unit:"> + <_item value="px">Pixel (fixed)</_item> + <_item value="percent">Percent (relative to parent size)</_item> + <_item value="undefined">Undefined (relative to non-floating content size)</_item> + </param> + <param name="bg-color" type="string" _gui-text="Background color:"></param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="about" type="description">Layout Group is only about to help a better code generation (if you need it). To use this, you must to select some "Slicer rectangles" first.</_param> + </page> + </param> + <effect needs-live-preview="false"> + <object-type>all</object-type> + <effects-menu> + <submenu _name="Web"> + <submenu _name="Slicer"/> + </submenu> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">webslicer_create_group.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/webslicer_create_group.py b/share/extensions/webslicer_create_group.py index c6f9e653e..c2de0594b 100644 --- a/share/extensions/webslicer_create_group.py +++ b/share/extensions/webslicer_create_group.py @@ -28,26 +28,29 @@ class WebSlicer_CreateGroup(WebSlicer_Effect): def __init__(self): WebSlicer_Effect.__init__(self) self.OptionParser.add_option("--html-id", - action="store", type="string", - dest="html_id", - help="") + action="store", type="string", + dest="html_id", + help="") self.OptionParser.add_option("--html-class", - action="store", type="string", - dest="html_class", - help="") + action="store", type="string", + dest="html_class", + help="") self.OptionParser.add_option("--width-unity", - action="store", type="string", - dest="width_unity", - help="") + action="store", type="string", + dest="width_unity", + help="") self.OptionParser.add_option("--height-unity", - action="store", type="string", - dest="height_unity", - help="") + action="store", type="string", + dest="height_unity", + help="") self.OptionParser.add_option("--bg-color", - action="store", type="string", - dest="bg_color", - help="") - + action="store", type="string", + dest="bg_color", + help="") + self.OptionParser.add_option("--tab", + action="store", type="string", + dest="tab", + help="The selected UI-tab when OK was pressed") def get_base_elements(self): self.layer = self.get_slicer_layer() diff --git a/share/extensions/webslicer_create_rect.inx b/share/extensions/webslicer_create_rect.inx index acf440cca..8a56c7892 100644 --- a/share/extensions/webslicer_create_rect.inx +++ b/share/extensions/webslicer_create_rect.inx @@ -19,12 +19,12 @@ <param name="bg-color" type="string" _gui-text="Background color:"></param> <param name="tab" type="notebook"> <page name="tabJPG" gui-text="JPG"> - <_param name="help-jpg" type="description">JPG specific options</_param> + <_param name="help-jpg" type="groupheader">JPG specific options</_param> <param name="quality" type="int" min="0" max="100" _gui-text="Quality:">85</param> <_param name="help-quality" type="description">0 is the lowest image quality and highest compression, and 100 is the best quality but least effective compression</_param> </page> <page name="tabGIF" gui-text="GIF"> - <_param name="help-gif" type="description">GIF specific options</_param> + <_param name="help-gif" type="groupheader">GIF specific options</_param> <param name="gif-type" type="enum" _gui-text="Type:"> <_item value="grayscale">Grayscale</_item> <_item value="palette">Palette</_item> @@ -34,7 +34,7 @@ <page name="tabHTML" gui-text="HTML"> <param name="html-id" type="string" _gui-text="HTML id attribute:"></param> <param name="html-class" type="string" _gui-text="HTML class attribute:"></param> - <_param name="help-gif" type="description">Options for HTML export</_param> + <_param name="help-gif" type="groupheader">Options for HTML export</_param> <param name="layout-disposition" type="enum" _gui-text="Layout disposition:"> <_item value="bg-el-norepeat">Positioned html block element with the image as Background</_item> <_item value="bg-parent-repeat">Tiled Background (on parent group)</_item> diff --git a/share/extensions/webslicer_export.inx b/share/extensions/webslicer_export.inx index 3a7324370..f82e42f33 100644 --- a/share/extensions/webslicer_export.inx +++ b/share/extensions/webslicer_export.inx @@ -1,23 +1,29 @@ <?xml version="1.0" encoding="UTF-8"?> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Export layout pieces and HTML+CSS code</_name> - <id>org.inkscape.web.slicer.export</id> - <dependency type="executable" location="extensions">webslicer_effect.py</dependency> - <dependency type="executable" location="extensions">webslicer_export.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="about" type="description">All sliced images, and optionaly code, will be generated as you had configured and saved to one directory.</_param> - <param name="dir" type="string" _gui-text="Directory path to export"></param> - <param name="create-dir" type="boolean" _gui-text="Create directory, if it does not exists">false</param> - <param name="with-code" type="boolean" _gui-text="With HTML and CSS">true</param> - <effect needs-live-preview="false"> + <_name>Export layout pieces and HTML+CSS code</_name> + <id>org.inkscape.web.slicer.export</id> + <dependency type="executable" location="extensions">webslicer_effect.py</dependency> + <dependency type="executable" location="extensions">webslicer_export.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <param name="tab" type="notebook"> + <page name="Options" _gui-text="Options"> + <param name="dir" type="string" _gui-text="Directory path to export:"></param> + <param name="create-dir" type="boolean" _gui-text="Create directory, if it does not exists">false</param> + <param name="with-code" type="boolean" _gui-text="With HTML and CSS">true</param> + </page> + <page name="Help" _gui-text="Help"> + <_param name="about" type="description">All sliced images, and optionaly code, will be generated as you had configured and saved to one directory.</_param> + </page> + </param> + <effect needs-live-preview="false"> <object-type>all</object-type> <effects-menu> - <submenu _name="Web"> - <submenu name="Slicer"/> - </submenu> + <submenu _name="Web"> + <submenu name="Slicer"/> + </submenu> </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">webslicer_export.py</command> - </script> + </effect> + <script> + <command reldir="extensions" interpreter="python">webslicer_export.py</command> + </script> </inkscape-extension> diff --git a/share/extensions/webslicer_export.py b/share/extensions/webslicer_export.py index 78de70a37..5b16ea2f5 100755 --- a/share/extensions/webslicer_export.py +++ b/share/extensions/webslicer_export.py @@ -20,17 +20,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from webslicer_effect import * import inkex import gettext -import os.path -import subprocess +import os +import sys import tempfile -import commands _ = gettext.gettext + class WebSlicer_Export(WebSlicer_Effect): def __init__(self): WebSlicer_Effect.__init__(self) + self.OptionParser.add_option("--tab") self.OptionParser.add_option("--dir", action="store", type="string", dest="dir", @@ -64,7 +65,7 @@ class WebSlicer_Export(WebSlicer_Effect): # Try to create it: try: os.makedirs( self.options.dir ) - except Exception as e: + except Exception, e: inkex.errormsg( _('Can\'t create "%s".') % self.options.dir ) inkex.errormsg( _('Error: %s') % e ) return {'error':'Can\'t create the directory to export.'} @@ -75,6 +76,21 @@ class WebSlicer_Export(WebSlicer_Effect): return None + def get_cmd_output(self, cmd): + # This solution comes from Andrew Reedick <jr9445 at ATT.COM> + # http://mail.python.org/pipermail/python-win32/2008-January/006606.html + # This method replaces the commands.getstatusoutput() usage, with the + # hope to correct the windows exporting bug: + # https://bugs.launchpad.net/inkscape/+bug/563722 + if sys.platform != "win32": cmd = '{ '+ cmd +'; }' + pipe = os.popen(cmd +' 2>&1', 'r') + text = pipe.read() + sts = pipe.close() + if sts is None: sts = 0 + if text[-1:] == '\n': text = text[:-1] + return sts, text + + _html_ids = [] def unique_html_id(self, el): for child in el.getchildren(): @@ -94,7 +110,7 @@ class WebSlicer_Export(WebSlicer_Effect): def test_if_has_imagemagick(self): - (status, output) = commands.getstatusoutput('convert --version') + (status, output) = self.get_cmd_output('convert --version') self.has_magick = ( status == 0 and 'ImageMagick' in output ) @@ -279,7 +295,7 @@ class WebSlicer_Export(WebSlicer_Effect): el_geo = { } def register_all_els_geometry(self): ink_cmm = 'inkscape --query-all '+self.tmp_svg - (status, output) = commands.getstatusoutput( ink_cmm ) + (status, output) = self.get_cmd_output( ink_cmm ) self.el_geo = { } if status == 0: for el in output.split('\n'): @@ -325,7 +341,7 @@ class WebSlicer_Export(WebSlicer_Effect): if 'dimension' in conf: dim = conf['dimension'].split('x') opts += ' -w '+dim[0]+' -h '+dim[1] - (status, output) = commands.getstatusoutput( + (status, output) = self.get_cmd_output( 'inkscape %s -i "%s" -e "%s" "%s"' % ( opts, el.attrib['id'], img_name_png, self.tmp_svg ) @@ -341,7 +357,7 @@ class WebSlicer_Export(WebSlicer_Effect): opts += ' -type Palette' if conf['palette-size'] < 256: opts += ' -colors '+str(conf['palette-size']) - (status, output) = commands.getstatusoutput( + (status, output) = self.get_cmd_output( 'convert "%s" %s "%s"' % ( img_name_png, opts, img_name ) ) if status != 0: diff --git a/share/extensions/whirl.inx b/share/extensions/whirl.inx index f68d99d35..a7de60f2b 100644 --- a/share/extensions/whirl.inx +++ b/share/extensions/whirl.inx @@ -4,13 +4,13 @@ <id>org.ekips.filter.whirl</id> <dependency type="executable" location="extensions">whirl.py</dependency> <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="whirl" type="float" min="0.00" max="1000.00" _gui-text="Amount of whirl">5.0</param> + <param name="whirl" type="float" min="0.00" max="1000.00" _gui-text="Amount of whirl:">5.0</param> <param name="rotation" type="boolean" _gui-text="Rotation is clockwise">true</param> <effect> <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> + <effects-menu> + <submenu _name="Modify Path"/> + </effects-menu> </effect> <script> <command reldir="extensions" interpreter="python">whirl.py</command> diff --git a/share/extensions/whirl.py b/share/extensions/whirl.py index 4c5db2262..cea9da8df 100644 --- a/share/extensions/whirl.py +++ b/share/extensions/whirl.py @@ -58,4 +58,4 @@ if __name__ == '__main__': e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/wireframe_sphere.inx b/share/extensions/wireframe_sphere.inx index 733ba8e11..6702657e3 100644 --- a/share/extensions/wireframe_sphere.inx +++ b/share/extensions/wireframe_sphere.inx @@ -6,11 +6,11 @@ <dependency type="executable" location="extensions">inkex.py</dependency> <dependency type="executable" location="extensions">simplestyle.py</dependency> <dependency type="executable" location="extensions">simpletransform.py</dependency> - <param name="num_lat" type="int" min="0" max="1000" _gui-text="Lines of latitude">19</param> - <param name="num_long" type="int" min="0" max="1000" _gui-text="Lines of longitude">24</param> - <param name="tilt" type="float" min="-90" max="90" _gui-text="Tilt [deg]">35</param> - <param name="rotation" type="float" min="0" max="360" _gui-text="Rotation [deg]">4</param> - <param name="radius" type="float" min="1" max="1000" _gui-text="Radius [px]">100.0</param> + <param name="num_lat" type="int" min="0" max="1000" _gui-text="Lines of latitude:">19</param> + <param name="num_long" type="int" min="0" max="1000" _gui-text="Lines of longitude:">24</param> + <param name="tilt" type="float" min="-90" max="90" _gui-text="Tilt (deg):">35</param> + <param name="rotation" type="float" min="0" max="360" _gui-text="Rotation (deg):">4</param> + <param name="radius" type="float" min="1" max="1000" _gui-text="Radius (px):">100.0</param> <param name="hide_back" type="boolean" _gui-text="Hide lines behind the sphere">false</param> <effect> <object-type>all</object-type> diff --git a/share/extensions/wireframe_sphere.py b/share/extensions/wireframe_sphere.py index 5391af3e6..467aa609e 100644 --- a/share/extensions/wireframe_sphere.py +++ b/share/extensions/wireframe_sphere.py @@ -218,4 +218,4 @@ if __name__ == '__main__': e = Wireframe_Sphere() e.affect() -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99 +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/wmf_output.py b/share/extensions/wmf_output.py index 3ea4c0acf..8d92b0518 100644 --- a/share/extensions/wmf_output.py +++ b/share/extensions/wmf_output.py @@ -27,4 +27,4 @@ from uniconv_output import run, get_command cmd = get_command() run((cmd + ' "%s" ') % sys.argv[1], "UniConvertor", ".wmf") -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
\ No newline at end of file +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
\ No newline at end of file diff --git a/share/extensions/xaml2svg.xsl b/share/extensions/xaml2svg.xsl index c5f1cfd75..8c0e4a5c9 100644 --- a/share/extensions/xaml2svg.xsl +++ b/share/extensions/xaml2svg.xsl @@ -1,107 +1,107 @@ -<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Copyright (c) 2005-2007 Toine de Greef (a.degreef@chello.nl)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-Version history:
-
-20070907 Initial release
-20070912 Removed NaN as viewBox values
-
--->
-
-<xsl:stylesheet version="1.0"
-xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-xmlns:xlink="http://www.w3.org/1999/xlink"
-xmlns:svg="http://www.w3.org/2000/svg"
-xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-xmlns:msxsl="urn:schemas-microsoft-com:xslt">
-<xsl:strip-space elements="*" />
-<xsl:output method="xml" encoding="UTF-8"/>
-<xsl:include href="xaml2svg/animation.xsl" />
-<xsl:include href="xaml2svg/brushes.xsl" />
-<xsl:include href="xaml2svg/canvas.xsl" />
-<xsl:include href="xaml2svg/geometry.xsl" />
-<xsl:include href="xaml2svg/properties.xsl" />
-<xsl:include href="xaml2svg/shapes.xsl" />
-<xsl:include href="xaml2svg/transform.xsl" />
-
-<xsl:template match="/">
- <svg>
- <xsl:attribute name="overflow">visible</xsl:attribute>
- <xsl:variable name="viewBox"><xsl:apply-templates mode="boundingbox" /></xsl:variable>
- <xsl:if test="system-property('xsl:vendor') = 'Microsoft' and (msxsl:node-set($viewBox)/boundingbox/@x1 != '') and (msxsl:node-set($viewBox)/boundingbox/@x2 != '') and (msxsl:node-set($viewBox)/boundingbox/@y1 != '') and (msxsl:node-set($viewBox)/boundingbox/@y2 != '')">
- <xsl:attribute name="viewBox">
- <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" />
- <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@y1, ' ')" />
- <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x2 - msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" />
- <xsl:value-of select="msxsl:node-set($viewBox)/boundingbox/@y2 - msxsl:node-set($viewBox)/boundingbox/@y1" />
- </xsl:attribute>
- </xsl:if>
- <xsl:apply-templates mode="svg" />
- </svg>
-</xsl:template>
-
-<xsl:template mode="forward" match="*[name(.) = 'Image']">
- <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if>
- <image>
- <xsl:if test="@Source"><xsl:attribute name="xlink:href"><xsl:value-of select="@Source" /></xsl:attribute></xsl:if>
- <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if>
- <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if>
- <xsl:call-template name="template_properties" />
- <xsl:call-template name="template_transform" />
- <xsl:apply-templates mode="forward" />
- </image>
- <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if>
-</xsl:template>
-
-<xsl:template mode="forward" match="*[name(.) = 'TextBlock']">
- <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if>
- <text>
- <xsl:if test="@FontSize"><xsl:attribute name="font-size"><xsl:value-of select="@FontSize" /></xsl:attribute></xsl:if>
- <xsl:if test="@FontWeight"><xsl:attribute name="font-weight"><xsl:value-of select="@FontWeight" /></xsl:attribute></xsl:if>
- <xsl:if test="@FontFamily"><xsl:attribute name="font-family"><xsl:value-of select="@FontFamily" /></xsl:attribute></xsl:if>
- <xsl:if test="@FontStyle"><xsl:attribute name="font-style"><xsl:value-of select="@FontStyle" /></xsl:attribute></xsl:if>
- <xsl:if test="@Foreground"><xsl:attribute name="fill"><xsl:value-of select="@Foreground" /></xsl:attribute></xsl:if>
- <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if>
- <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if>
- <xsl:if test="@HorizontalAlignment">
- <xsl:attribute name="text-anchor">
- <xsl:choose>
- <xsl:when test="@HorizontalAlignment = 'Left'">start</xsl:when>
- <xsl:when test="@HorizontalAlignment = 'Center'">middle</xsl:when>
- <xsl:when test="@HorizontalAlignment = 'Right'">end</xsl:when>
- </xsl:choose>
- </xsl:attribute>
- </xsl:if>
- <xsl:attribute name="dominant-baseline">hanging</xsl:attribute>
- <xsl:call-template name="template_properties" />
- <xsl:call-template name="template_transform" />
- <xsl:apply-templates />
- </text>
- <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if>
-</xsl:template>
-
-<xsl:template match="*">
-<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment>
-</xsl:template>
-
-</xsl:stylesheet>
+<?xml version="1.0" encoding="UTF-8"?> + +<!-- +Copyright (c) 2005-2007 Toine de Greef (a.degreef@chello.nl) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Version history: + +20070907 Initial release +20070912 Removed NaN as viewBox values + +--> + +<xsl:stylesheet version="1.0" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +xmlns:xlink="http://www.w3.org/1999/xlink" +xmlns:svg="http://www.w3.org/2000/svg" +xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" +xmlns:msxsl="urn:schemas-microsoft-com:xslt"> +<xsl:strip-space elements="*" /> +<xsl:output method="xml" encoding="UTF-8"/> +<xsl:include href="xaml2svg/animation.xsl" /> +<xsl:include href="xaml2svg/brushes.xsl" /> +<xsl:include href="xaml2svg/canvas.xsl" /> +<xsl:include href="xaml2svg/geometry.xsl" /> +<xsl:include href="xaml2svg/properties.xsl" /> +<xsl:include href="xaml2svg/shapes.xsl" /> +<xsl:include href="xaml2svg/transform.xsl" /> + +<xsl:template match="/"> + <svg> + <xsl:attribute name="overflow">visible</xsl:attribute> + <xsl:variable name="viewBox"><xsl:apply-templates mode="boundingbox" /></xsl:variable> + <xsl:if test="system-property('xsl:vendor') = 'Microsoft' and (msxsl:node-set($viewBox)/boundingbox/@x1 != '') and (msxsl:node-set($viewBox)/boundingbox/@x2 != '') and (msxsl:node-set($viewBox)/boundingbox/@y1 != '') and (msxsl:node-set($viewBox)/boundingbox/@y2 != '')"> + <xsl:attribute name="viewBox"> + <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" /> + <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@y1, ' ')" /> + <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x2 - msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" /> + <xsl:value-of select="msxsl:node-set($viewBox)/boundingbox/@y2 - msxsl:node-set($viewBox)/boundingbox/@y1" /> + </xsl:attribute> + </xsl:if> + <xsl:apply-templates mode="svg" /> + </svg> +</xsl:template> + +<xsl:template mode="forward" match="*[name(.) = 'Image']"> + <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if> + <image> + <xsl:if test="@Source"><xsl:attribute name="xlink:href"><xsl:value-of select="@Source" /></xsl:attribute></xsl:if> + <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if> + <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if> + <xsl:call-template name="template_properties" /> + <xsl:call-template name="template_transform" /> + <xsl:apply-templates mode="forward" /> + </image> + <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if> +</xsl:template> + +<xsl:template mode="forward" match="*[name(.) = 'TextBlock']"> + <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if> + <text> + <xsl:if test="@FontSize"><xsl:attribute name="font-size"><xsl:value-of select="@FontSize" /></xsl:attribute></xsl:if> + <xsl:if test="@FontWeight"><xsl:attribute name="font-weight"><xsl:value-of select="@FontWeight" /></xsl:attribute></xsl:if> + <xsl:if test="@FontFamily"><xsl:attribute name="font-family"><xsl:value-of select="@FontFamily" /></xsl:attribute></xsl:if> + <xsl:if test="@FontStyle"><xsl:attribute name="font-style"><xsl:value-of select="@FontStyle" /></xsl:attribute></xsl:if> + <xsl:if test="@Foreground"><xsl:attribute name="fill"><xsl:value-of select="@Foreground" /></xsl:attribute></xsl:if> + <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if> + <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if> + <xsl:if test="@HorizontalAlignment"> + <xsl:attribute name="text-anchor"> + <xsl:choose> + <xsl:when test="@HorizontalAlignment = 'Left'">start</xsl:when> + <xsl:when test="@HorizontalAlignment = 'Center'">middle</xsl:when> + <xsl:when test="@HorizontalAlignment = 'Right'">end</xsl:when> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:attribute name="dominant-baseline">hanging</xsl:attribute> + <xsl:call-template name="template_properties" /> + <xsl:call-template name="template_transform" /> + <xsl:apply-templates /> + </text> + <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if> +</xsl:template> + +<xsl:template match="*"> +<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment> +</xsl:template> + +</xsl:stylesheet> |
