summaryrefslogtreecommitdiffstats
path: root/share/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions')
-rw-r--r--share/extensions/Barcode/Base.py1
-rw-r--r--share/extensions/Barcode/Code128.py1
-rw-r--r--share/extensions/Barcode/Code39.py1
-rw-r--r--share/extensions/Barcode/Code39Ext.py1
-rw-r--r--share/extensions/Barcode/Code93.py1
-rw-r--r--share/extensions/Barcode/EAN13.py1
-rw-r--r--share/extensions/Barcode/EAN5.py1
-rw-r--r--share/extensions/Barcode/EAN8.py1
-rw-r--r--share/extensions/Barcode/RM4CC.py1
-rw-r--r--share/extensions/Barcode/UPCA.py1
-rw-r--r--share/extensions/Barcode/UPCE.py1
-rw-r--r--share/extensions/Barcode/__init__.py2
-rw-r--r--share/extensions/Makefile.am16
-rw-r--r--share/extensions/SpSVG.pm2
-rw-r--r--share/extensions/addnodes.inx10
-rw-r--r--share/extensions/addnodes.py2
-rw-r--r--share/extensions/aisvg.xslt72
-rwxr-xr-xshare/extensions/bezmisc.py2
-rw-r--r--share/extensions/color_blackandwhite.py1
-rw-r--r--share/extensions/color_brighter.py1
-rw-r--r--share/extensions/color_custom.inx23
-rw-r--r--share/extensions/color_custom.py71
-rw-r--r--share/extensions/color_darker.py1
-rw-r--r--share/extensions/color_desaturate.py3
-rw-r--r--share/extensions/color_grayscale.py3
-rw-r--r--share/extensions/color_lesshue.py1
-rw-r--r--share/extensions/color_lesslight.py1
-rw-r--r--share/extensions/color_lesssaturation.py1
-rw-r--r--share/extensions/color_morehue.py1
-rw-r--r--share/extensions/color_morelight.py1
-rw-r--r--share/extensions/color_moresaturation.py1
-rw-r--r--share/extensions/color_negative.py3
-rw-r--r--share/extensions/color_randomize.inx15
-rw-r--r--share/extensions/color_randomize.py7
-rw-r--r--share/extensions/color_removeblue.py3
-rw-r--r--share/extensions/color_removegreen.py3
-rw-r--r--share/extensions/color_removered.py3
-rw-r--r--share/extensions/color_replace.inx4
-rw-r--r--share/extensions/color_replace.py1
-rw-r--r--share/extensions/color_rgbbarrel.py3
-rw-r--r--share/extensions/colors.xml300
-rw-r--r--share/extensions/convert2dashes.inx32
-rw-r--r--share/extensions/convert2dashes.py2
-rw-r--r--share/extensions/cspsubdiv.py2
-rwxr-xr-xshare/extensions/cubicsuperpath.py2
-rw-r--r--share/extensions/dimension.inx10
-rw-r--r--share/extensions/dimension.py2
-rw-r--r--share/extensions/dots.inx18
-rwxr-xr-xshare/extensions/dots.py100
-rw-r--r--share/extensions/draw_from_triangle.inx16
-rw-r--r--share/extensions/draw_from_triangle.py16
-rw-r--r--share/extensions/dxf_input.py11
-rwxr-xr-xshare/extensions/dxf_outlines.py2
-rw-r--r--share/extensions/dxf_templates.py1
-rw-r--r--share/extensions/edge3d.inx45
-rw-r--r--share/extensions/edge3d.py2
-rw-r--r--share/extensions/embedimage.py2
-rw-r--r--share/extensions/eps_input.inx1
-rw-r--r--share/extensions/eqtexsvg.py2
-rw-r--r--share/extensions/export_gimp_palette.py2
-rw-r--r--share/extensions/extractimage.py2
-rw-r--r--share/extensions/extrude.inx14
-rw-r--r--share/extensions/ffgeom.py2
-rw-r--r--share/extensions/fig2dev-ext.py2
-rw-r--r--share/extensions/flatten.inx2
-rwxr-xr-xshare/extensions/flatten.py2
-rw-r--r--share/extensions/foldablebox.inx52
-rwxr-xr-xshare/extensions/foldablebox.py2
-rwxr-xr-xshare/extensions/fractalize.inx8
-rwxr-xr-xshare/extensions/fractalize.py2
-rw-r--r--share/extensions/funcplot.inx76
-rw-r--r--share/extensions/funcplot.py21
-rw-r--r--share/extensions/gcodetools.py4603
-rw-r--r--share/extensions/gcodetools_all_in_one.inx194
-rw-r--r--share/extensions/gcodetools_area.inx109
-rw-r--r--share/extensions/gcodetools_check_for_updates.inx43
-rw-r--r--share/extensions/gcodetools_dxf_points.inx79
-rw-r--r--share/extensions/gcodetools_engraving.inx87
-rw-r--r--share/extensions/gcodetools_lathe.inx94
-rw-r--r--share/extensions/gcodetools_orientation_points.inx70
-rw-r--r--share/extensions/gcodetools_path_to_gcode.inx80
-rw-r--r--share/extensions/gcodetools_tools_library.inx62
-rw-r--r--share/extensions/gears.inx6
-rw-r--r--share/extensions/gears.py2
-rw-r--r--share/extensions/generate_voronoi.inx15
-rw-r--r--share/extensions/generate_voronoi.py6
-rw-r--r--share/extensions/gimp_xcf.inx18
-rwxr-xr-xshare/extensions/gimp_xcf.py205
-rw-r--r--share/extensions/grid_cartesian.inx36
-rw-r--r--share/extensions/grid_cartesian.py2
-rw-r--r--share/extensions/grid_polar.inx38
-rw-r--r--share/extensions/grid_polar.py2
-rw-r--r--share/extensions/guides_creator.inx56
-rw-r--r--share/extensions/guillotine.inx26
-rw-r--r--share/extensions/guillotine.py258
-rwxr-xr-xshare/extensions/handles.py2
-rw-r--r--share/extensions/hpgl_output.py6
-rwxr-xr-xshare/extensions/inkex.py22
-rw-r--r--share/extensions/inkscape_help_keys.inx2
-rw-r--r--share/extensions/interp.inx6
-rwxr-xr-xshare/extensions/interp.py2
-rw-r--r--share/extensions/interp_att_g.inx102
-rwxr-xr-xshare/extensions/interp_att_g.py4
-rwxr-xr-xshare/extensions/jessyInk.js154
-rwxr-xr-xshare/extensions/jessyInk_autoTexts.py10
-rw-r--r--share/extensions/jessyInk_core_mouseHandler_zoomControl.js13
-rwxr-xr-xshare/extensions/jessyInk_effects.py8
-rwxr-xr-xshare/extensions/jessyInk_export.py6
-rwxr-xr-xshare/extensions/jessyInk_install.py2
-rw-r--r--share/extensions/jessyInk_keyBindings.inx3
-rwxr-xr-xshare/extensions/jessyInk_keyBindings.py10
-rwxr-xr-xshare/extensions/jessyInk_masterSlide.py10
-rwxr-xr-xshare/extensions/jessyInk_mouseHandler.py6
-rw-r--r--share/extensions/jessyInk_summary.inx3
-rwxr-xr-xshare/extensions/jessyInk_summary.py59
-rwxr-xr-xshare/extensions/jessyInk_transitions.py14
-rwxr-xr-xshare/extensions/jessyInk_video.py10
-rwxr-xr-xshare/extensions/jessyInk_view.py10
-rw-r--r--share/extensions/launch_webbrowser.py2
-rw-r--r--share/extensions/lindenmayer.inx46
-rwxr-xr-xshare/extensions/lindenmayer.py2
-rw-r--r--share/extensions/lorem_ipsum.inx14
-rw-r--r--share/extensions/lorem_ipsum.py5
-rw-r--r--share/extensions/markers_strokepaint.py2
-rw-r--r--share/extensions/measure.inx8
-rw-r--r--share/extensions/measure.py2
-rw-r--r--share/extensions/motion.inx4
-rwxr-xr-xshare/extensions/motion.py2
-rw-r--r--share/extensions/param_curves.inx85
-rw-r--r--share/extensions/param_curves.py504
-rw-r--r--share/extensions/pathalongpath.inx64
-rw-r--r--share/extensions/pathalongpath.py10
-rw-r--r--share/extensions/pathmodifier.py2
-rw-r--r--share/extensions/pathscatter.inx65
-rw-r--r--share/extensions/pathscatter.py39
-rw-r--r--share/extensions/perfectboundcover.inx74
-rw-r--r--share/extensions/perfectboundcover.py2
-rwxr-xr-xshare/extensions/perspective.py2
-rw-r--r--share/extensions/pixelsnap.inx2
-rw-r--r--share/extensions/plt_output.py2
-rw-r--r--share/extensions/polyhedron_3d.inx101
-rw-r--r--share/extensions/polyhedron_3d.py2
-rw-r--r--share/extensions/printing-marks.inx84
-rw-r--r--share/extensions/printing-marks.py8
-rw-r--r--share/extensions/ps2pdf-ext.py7
-rwxr-xr-xshare/extensions/pturtle.py2
-rw-r--r--share/extensions/radiusrand.inx44
-rwxr-xr-xshare/extensions/radiusrand.py7
-rw-r--r--share/extensions/render_alphabetsoup.inx6
-rw-r--r--share/extensions/render_alphabetsoup.py926
-rw-r--r--share/extensions/render_alphabetsoup_config.py3
-rw-r--r--share/extensions/render_barcode.py1
-rw-r--r--share/extensions/render_barcode_datamatrix.inx8
-rw-r--r--share/extensions/render_barcode_datamatrix.py2
-rw-r--r--share/extensions/render_barcode_qrcode.inx69
-rw-r--r--share/extensions/render_barcode_qrcode.py1068
-rw-r--r--share/extensions/replace_font.inx38
-rw-r--r--share/extensions/replace_font.py260
-rw-r--r--share/extensions/restack.inx34
-rw-r--r--share/extensions/restack.py2
-rw-r--r--share/extensions/rtree.inx4
-rwxr-xr-xshare/extensions/rtree.py2
-rw-r--r--share/extensions/rubberstretch.py2
-rw-r--r--share/extensions/run_command.py3
-rwxr-xr-xshare/extensions/scour.inkscape.py2
-rwxr-xr-xshare/extensions/simplepath.py2
-rwxr-xr-xshare/extensions/simplestyle.py2
-rw-r--r--share/extensions/simpletransform.py2
-rw-r--r--share/extensions/sk1_output.py2
-rw-r--r--share/extensions/spirograph.inx16
-rw-r--r--share/extensions/spirograph.py2
-rw-r--r--share/extensions/split.inx20
-rw-r--r--share/extensions/split.py5
-rw-r--r--share/extensions/straightseg.inx12
-rwxr-xr-xshare/extensions/straightseg.py2
-rwxr-xr-xshare/extensions/summersnight.py2
-rwxr-xr-xshare/extensions/svg2xaml.xsl2966
-rw-r--r--share/extensions/svg_and_media_zip_output.py4
-rw-r--r--share/extensions/svg_regex.py1
-rw-r--r--share/extensions/svgcalendar.inx270
-rwxr-xr-xshare/extensions/svgcalendar.py11
-rw-r--r--share/extensions/text_braille.py1
-rw-r--r--share/extensions/text_flipcase.py1
-rw-r--r--share/extensions/text_lowercase.py1
-rw-r--r--share/extensions/text_randomcase.py1
-rw-r--r--share/extensions/text_replace.py1
-rw-r--r--share/extensions/text_sentencecase.py1
-rw-r--r--share/extensions/text_titlecase.py1
-rw-r--r--share/extensions/text_uppercase.py1
-rw-r--r--share/extensions/triangle.inx31
-rw-r--r--share/extensions/triangle.py2
-rw-r--r--share/extensions/uniconv-ext.py4
-rw-r--r--share/extensions/uniconv_output.py4
-rw-r--r--share/extensions/web-set-att.inx92
-rwxr-xr-xshare/extensions/web-set-att.py4
-rw-r--r--share/extensions/web-transmit-att.inx82
-rw-r--r--share/extensions/web-transmit-att.py4
-rw-r--r--share/extensions/webslicer_create_group.inx66
-rw-r--r--share/extensions/webslicer_create_group.py35
-rw-r--r--share/extensions/webslicer_create_rect.inx6
-rw-r--r--share/extensions/webslicer_export.inx40
-rwxr-xr-xshare/extensions/webslicer_export.py32
-rw-r--r--share/extensions/whirl.inx8
-rw-r--r--share/extensions/whirl.py2
-rw-r--r--share/extensions/wireframe_sphere.inx10
-rw-r--r--share/extensions/wireframe_sphere.py2
-rw-r--r--share/extensions/wmf_output.py2
-rw-r--r--share/extensions/xaml2svg.xsl214
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)/*) &gt; 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)/*) &gt; 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)/*) &gt; 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)/*) &gt; 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('&lt;svg x=&quot;', @Canvas.Left, '&quot; y=&quot;', @Canvas.Top, '&quot;&gt;')" /></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="'&lt;/svg&gt;&#13;'" /></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('&lt;svg x=&quot;', @Canvas.Left, '&quot; y=&quot;', @Canvas.Top, '&quot;&gt;')" /></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="'&lt;/svg&gt;&#13;'" /></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('&lt;svg x=&quot;', @Canvas.Left, '&quot; y=&quot;', @Canvas.Top, '&quot;&gt;')" /></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="'&lt;/svg&gt;&#13;'" /></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('&lt;svg x=&quot;', @Canvas.Left, '&quot; y=&quot;', @Canvas.Top, '&quot;&gt;')" /></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="'&lt;/svg&gt;&#13;'" /></xsl:if>
+</xsl:template>
+
+<xsl:template match="*">
+<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment>
+</xsl:template>
+
+</xsl:stylesheet>