diff options
572 files changed, 7 insertions, 64275 deletions
diff --git a/INSTALL.md b/INSTALL.md index 3ceab9470..549e3d055 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -54,23 +54,14 @@ Please see [the wiki page on compiling Inkscape](http://wiki.inkscape.org/wiki/i most current dependencies, including links to the source tarballs. -Extension Dependencies -====================== -Inkscape also has a number of extensions for implementing various -features such as support for non-SVG file formats. In theory, all -extensions are optional, however in practice you will want to have these -installed and working. Unfortunately, there is a great deal of -variability in how you can get these functioning properly. Here are -some recommendations: - -First, make sure you have Python. If you are on Windows you -should also install [Cygwin](https://www.cygwin.com/). - -Second, if an extension does not work, check the file -`extensions-errors.log` located on Linux at `~/.config/inkscape` and on -Windows at `%userprofile%\Application Data\Inkscape\`. Any missing -programs will be listed. +Extensions +========== +All inkscape extensions have been moved into their own reporsitory, they +can be installed from there and should be packaged into builds directly. +Report all bugs and ideas to that sub project. + +[Inkscape Extensions](https://gitlab.com/inkscape/extensions/) Build Options ============= diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index ab1a16e40..3edddd847 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -1,7 +1,6 @@ add_subdirectory(attributes) add_subdirectory(branding) add_subdirectory(examples) -add_subdirectory(extensions) add_subdirectory(filters) add_subdirectory(fonts) add_subdirectory(gradients) diff --git a/share/extensions/Barcode/Base.py b/share/extensions/Barcode/Base.py deleted file mode 100644 index bfa0a774f..000000000 --- a/share/extensions/Barcode/Base.py +++ /dev/null @@ -1,162 +0,0 @@ -# -# Copyright (C) 2010 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Base module for rendering barcodes for Inkscape. -""" - -import itertools -import sys -from lxml import etree - -(TEXT_POS_BOTTOM, TEXT_POS_TOP) = range(2) -(WHITE_BAR, BLACK_BAR, TALL_BAR) = range(3) -TEXT_TEMPLATE = 'font-size:%dpx;text-align:center;text-anchor:middle;' -SVG_URI = u'http://www.w3.org/2000/svg' - -# pylint: disable=abstract-class-not-used -class Barcode(object): - """Provide a base class for all barcode renderers""" - default_height = 30 - font_size = 9 - name = None - - def error(self, text, msg): - """Cause an error to be reported""" - sys.stderr.write( - "Error encoding '%s' as %s barcode: %s\n" % (text, self.name, msg)) - return "ERROR" - - def encode(self, text): - """ - Replace this with the encoding function, it should return - a string of ones and zeros - """ - raise NotImplementedError("You need to write an encode() function.") - - def __init__(self, param): - param = param or {} - self.document = param.get('document', None) - self.known_ids = [] - self._extra = [] - - self.pos_x = int(param.get('x', 0)) - self.pos_y = int(param.get('y', 0)) - self.text = param.get('text', None) - self.scale = param.get('scale', 1) - self.height = param.get('height', self.default_height) - self.pos_text = param.get('text_pos', TEXT_POS_BOTTOM) - - if self.document: - self.known_ids = list(self.document.xpath('//@id')) - - if not self.text: - raise ValueError("No string specified for barcode.") - - def get_id(self, name='element'): - """Get the next useful id (and claim it)""" - index = 0 - while name in self.known_ids: - index += 1 - name = 'barcode%d' % index - self.known_ids.append(name) - return name - - def add_extra_barcode(self, barcode, **kw): - """Add an extra barcode along side this one, used for ean13 extras""" - from . import getBarcode - kw['height'] = self.height - kw['document'] = self.document - kw['scale'] = None - self._extra.append(getBarcode(barcode, **kw).generate()) - - def generate(self): - """Generate the actual svg from the coding""" - string = self.encode(self.text) - - if string == 'ERROR': - return - - name = self.get_id('barcode') - - # use an svg group element to contain the barcode - barcode = etree.Element('{%s}g' % SVG_URI) - barcode.set('id', name) - barcode.set('style', 'fill: black;') - if self.scale: - barcode.set('transform', 'translate(%d,%d) scale(%f)' % ( - self.pos_x, self.pos_y, self.scale)) - else: - barcode.set('transform', 'translate(%d,%d)' % ( - self.pos_x, self.pos_y)) - - bar_id = 1 - bar_offset = 0 - tops = set() - - for datum in self.graphical_array(string): - # Datum 0 tells us what style of bar is to come next - style = self.get_style(int(datum[0])) - # Datum 1 tells us what width in units, - # style tells us how wide a unit is - width = int(datum[1]) * int(style['width']) - - if style['write']: - tops.add(style['top']) - rect = etree.SubElement(barcode, '{%s}rect' % SVG_URI) - rect.set('x', str(bar_offset)) - rect.set('y', str(style['top'])) - if self.pos_text == TEXT_POS_TOP: - rect.set('y', str(style['top'] + self.font_size)) - rect.set('id', "%s_bar%d" % (name, bar_id)) - rect.set('width', str(width)) - rect.set('height', str(style['height'])) - bar_offset += width - bar_id += 1 - - for extra in self._extra: - if extra is not None: - barcode.append(extra) - - bar_width = bar_offset - # Add text at the bottom of the barcode - text = etree.SubElement(barcode, '{%s}text' % SVG_URI) - text.set('x', str(int(bar_width / 2))) - text.set('y', str(min(tops) + self.font_size - 1)) - if self.pos_text == TEXT_POS_BOTTOM: - text.set('y', str(self.height + max(tops) + self.font_size)) - text.set('style', TEXT_TEMPLATE % self.font_size) - text.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve') - text.set('id', '%s_text' % name) - text.text = str(self.text) - return barcode - - def graphical_array(self, code): - """Converts black and white markets into a space array""" - return [(x, len(list(y))) for x, y in itertools.groupby(code)] - - def get_style(self, index): - """Returns the styles that should be applied to each bar""" - result = {'width' : 1, 'top' : 0, 'write' : True} - if index == BLACK_BAR: - result['height'] = int(self.height) - if index == TALL_BAR: - result['height'] = int(self.height) + int(self.font_size / 2) - if index == WHITE_BAR: - result['write'] = False - return result - diff --git a/share/extensions/Barcode/BaseEan.py b/share/extensions/Barcode/BaseEan.py deleted file mode 100644 index 84f780ae3..000000000 --- a/share/extensions/Barcode/BaseEan.py +++ /dev/null @@ -1,153 +0,0 @@ -# -# Copyright (C) 2010 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Some basic common code shared between EAN and UCP generators. -""" - -from .Base import Barcode, TEXT_POS_TOP - -MAPPING = [ - # Left side of barcode Family '0' - ["0001101", "0011001", "0010011", "0111101", "0100011", - "0110001", "0101111", "0111011", "0110111", "0001011"], - # Left side of barcode Family '1' and flipped to right side. - ["0100111", "0110011", "0011011", "0100001", "0011101", - "0111001", "0000101", "0010001", "0001001", "0010111"], -] -# This chooses which of the two encodings above to use. -FAMILIES = ('000000', '001011', '001101', '001110', '010011', - '011001', '011100', '010101', '010110', '011010') - -class EanBarcode(Barcode): - """Simple base class for all EAN type barcodes""" - lengths = None - length = None - checks = [] - extras = {} - magic = 10 - guard_bar = '202' - center_bar = '02020' - - def intarray(self, number): - """Convert a string of digits into an array of ints""" - return [int(i) for i in number] - - def encode_interleaved(self, family, number, fams=FAMILIES): - """Encode any side of the barcode, interleaved""" - result = [] - encset = self.intarray(fams[family]) - for i in range(len(number)): - thismap = MAPPING[encset[i]] - result.append(thismap[number[i]]) - return result - - def encode_right(self, number): - """Encode the right side of the barcode, non-interleaved""" - result = [] - for num in number: - # The right side is always the reverse of the left's family '1' - result.append(MAPPING[1][num][::-1]) - return result - - def encode_left(self, number): - """Encode the left side of the barcode, non-interleaved""" - result = [] - for num in number: - result.append(MAPPING[0][num]) - return result - - def space(self, *spacing): - """Space out an array of numbers""" - result = '' - for space in spacing: - if isinstance(space, list): - for i in space: - result += str(i) - elif isinstance(space, int): - result += ' ' * space - return result - - def get_lengths(self): - """Return a list of acceptable lengths""" - if self.length: - return [self.length] - return self.lengths[:] - - def encode(self, code): - """Encode any EAN barcode""" - code = code.replace(' ', '').strip() - guide = code.endswith('>') - code = code.strip('>') - - if not code.isdigit(): - return self.error(code, 'Not a Number, must be digits 0-9 only') - lengths = self.get_lengths() + self.checks - - # Allow extra barcodes after the first one - if len(code) not in lengths: - for extra in self.extras: - sep = len(code) - extra - if sep in lengths: - # Generate a barcode along side this one. - self.add_extra_barcode(self.extras[extra], text=code[sep:], - x=self.pos_x + 400 * self.scale, text_pos=TEXT_POS_TOP) - code = code[:sep] - - if len(code) not in lengths: - return self.error(code, 'Wrong size %d, must be %s digits' % - (len(code), ', '.join([str(length) for length in lengths]))) - - if self.checks: - if len(code) not in self.checks: - code = self.append_checksum(code) - elif not self.verify_checksum(code): - return self.error(code, 'Checksum failed, omit for new sum') - return self._encode(self.intarray(code), guide=guide) - - def _encode(self, num, guide=False): - """ - Write your EAN encoding function, it's passed in an array of int and - it should return a string on 1 and 0 for black and white parts - """ - raise NotImplementedError("_encode should be provided by parent EAN") - - def enclose(self, left, right=()): - """Standard Enclosure""" - parts = [self.guard_bar] + left - parts.append(self.center_bar) - parts += list(right) + [self.guard_bar] - return ''.join(parts) - - def get_checksum(self, num): - """Generate a UPCA/EAN13/EAN8 Checksum""" - # Left to right,checksum based on first digits. - total = sum([int(n) * (3, 1)[x % 2] for x, n in enumerate(num[::-1])]) - # Modulous result to a single digit checksum - checksum = self.magic - (total % self.magic) - if checksum < 0 or checksum >= self.magic: - return '0' - return str(checksum) - - def append_checksum(self, number): - """Apply the checksum to a short number""" - return number + self.get_checksum(number) - - def verify_checksum(self, number): - """Verify any checksum""" - return self.get_checksum(number[:-1]) == number[-1] - diff --git a/share/extensions/Barcode/Code128.py b/share/extensions/Barcode/Code128.py deleted file mode 100644 index 4af788bbe..000000000 --- a/share/extensions/Barcode/Code128.py +++ /dev/null @@ -1,153 +0,0 @@ -# -# Authored by Martin Owens <doctormo@gmail.com> -# Debugged by Ralf Heinecke & Martin Siepmann 2007-09-07 -# Horst Schottky 2010-02-27 -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Renderer for Code128/EAN128 codes. Designed for use with Inkscape. -""" - -from .Base import Barcode -import re - -CODE_MAP = [ - '11011001100', '11001101100', '11001100110', '10010011000', '10010001100', - '10001001100', '10011001000', '10011000100', '10001100100', '11001001000', - '11001000100', '11000100100', '10110011100', '10011011100', '10011001110', - '10111001100', '10011101100', '10011100110', '11001110010', '11001011100', - '11001001110', '11011100100', '11001110100', '11101101110', '11101001100', - '11100101100', '11100100110', '11101100100', '11100110100', '11100110010', - '11011011000', '11011000110', '11000110110', '10100011000', '10001011000', - '10001000110', '10110001000', '10001101000', '10001100010', '11010001000', - '11000101000', '11000100010', '10110111000', '10110001110', '10001101110', - '10111011000', '10111000110', '10001110110', '11101110110', '11010001110', - '11000101110', '11011101000', '11011100010', '11011101110', '11101011000', - '11101000110', '11100010110', '11101101000', '11101100010', '11100011010', - '11101111010', '11001000010', '11110001010', '10100110000', '10100001100', - '10010110000', '10010000110', '10000101100', '10000100110', '10110010000', - '10110000100', '10011010000', '10011000010', '10000110100', '10000110010', - '11000010010', '11001010000', '11110111010', '11000010100', '10001111010', - '10100111100', '10010111100', '10010011110', '10111100100', '10011110100', - '10011110010', '11110100100', '11110010100', '11110010010', '11011011110', - '11011110110', '11110110110', '10101111000', '10100011110', '10001011110', - '10111101000', '10111100010', '11110101000', '11110100010', '10111011110', - '10111101110', '11101011110', '11110101110', '11010000100', '11010010000', - '11010011100', '11000111010', '11'] - -def map_extra(data, chars): - """Maps the data into the chars""" - result = list(data) - for char in chars: - result.append(chr(char)) - result.append('FNC3') - result.append('FNC2') - result.append('SHIFT') - return result - -# The map_extra method is used to slim down the amount -# of pre code and instead we generate the lists -CHAR_AB = list(" !\"#$%&\'()*+,-./0123456789:;<=>?@" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_") -CHAR_A = map_extra(CHAR_AB, range(0, 31)) # Offset 64 -CHAR_B = map_extra(CHAR_AB, range(96, 125)) # Offset -32 - -class Code128(Barcode): - """Main barcode object, generates the encoding bits here""" - def encode(self, text): - blocks = [] - block = '' - - # Split up into sections of numbers, or characters - # This makes sure that all the characters are encoded - # In the best way possible for Code128 - for datum in re.findall(r'(?:(?:\d\d){2,})|(?:^\d\d)|.', text): - if len(datum) == 1: - block = block + datum - else: - if block: - blocks.append(self.best_block(block)) - block = '' - blocks.append(['C', datum]) - - if block: - blocks.append(self.best_block(block)) - block = '' - - return self.encode_blocks(blocks) - - def best_block(self, block): - """If this has lower case then select B over A""" - if block.upper() == block: - return ['A', block] - return ['B', block] - - def encode_blocks(self, blocks): - """Encode the given blocks into A, B or C codes""" - encode = '' - total = 0 - pos = 0 - - for block in blocks: - b_set = block[0] - datum = block[1] - - # POS : 0, 1 - # A : 101, 103 - # B : 100, 104 - # C : 99, 105 - num = 0 - if b_set == 'A': - num = 103 - elif b_set == 'B': - num = 104 - elif b_set == 'C': - num = 105 - - i = pos - if pos: - num = 204 - num - else: - i = 1 - - total = total + num * i - encode = encode + CODE_MAP[num] - pos = pos + 1 - - if b_set == 'A' or b_set == 'B': - chars = CHAR_B - if b_set == 'A': - chars = CHAR_A - - for char in datum: - total = total + (chars.index(char) * pos) - encode = encode + CODE_MAP[chars.index(char)] - pos = pos + 1 - else: - for char in (datum[i:i+2] for i in range(0, len(datum), 2)): - total = total + (int(char) * pos) - encode = encode + CODE_MAP[int(char)] - pos = pos + 1 - - checksum = total % 103 - encode = encode + CODE_MAP[checksum] - encode = encode + CODE_MAP[106] - encode = encode + CODE_MAP[107] - - return encode - diff --git a/share/extensions/Barcode/Code25i.py b/share/extensions/Barcode/Code25i.py deleted file mode 100644 index 2c751559c..000000000 --- a/share/extensions/Barcode/Code25i.py +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright (C) 2010 Geoffrey Mosini -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Generate barcodes for Code25-interleaved 2 of 5, for Inkscape. -""" - -from .Base import Barcode - -# 1 means thick, 0 means thin -ENCODE = { - '0': '00110', - '1': '10001', - '2': '01001', - '3': '11000', - '4': '00101', - '5': '10100', - '6': '01100', - '7': '00011', - '8': '10010', - '9': '01010', -} - - -class Code25i(Barcode): - """Convert a text into string binary of black and white markers""" - # Start and stop code are already encoded into white (0) and black(1) bars - def encode(self, number): - if not number.isdigit(): - return self.error(number, "CODE25 can only encode numbers.") - - # Number of figures to encode must be even, - # a 0 is added to the left in case it's odd. - if len(number) % 2 > 0: - number = '0' + number - - # Number is encoded by pairs of 2 figures - size = len(number) / 2 - encoded = '1010' - for i in range(size): - # First in the pair is encoded in black (1), second in white (0) - black = ENCODE[number[i*2]] - white = ENCODE[number[i*2+1]] - for j in range(5): - if black[j] == '1': - encoded += '11' - else: - encoded += '1' - if white[j] == '1': - encoded += '00' - else: - encoded += '0' - return encoded + '1101' - diff --git a/share/extensions/Barcode/Code39.py b/share/extensions/Barcode/Code39.py deleted file mode 100644 index cfe619bb0..000000000 --- a/share/extensions/Barcode/Code39.py +++ /dev/null @@ -1,96 +0,0 @@ -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for Code39 barcodes. Designed for use with Inkscape. -""" - -from Base import Barcode - -ENCODE = { - '0': '000110100', - '1': '100100001', - '2': '001100001', - '3': '101100000', - '4': '000110001', - '5': '100110000', - '6': '001110000', - '7': '000100101', - '8': '100100100', - '9': '001100100', - 'A': '100001001', - 'B': '001001001', - 'C': '101001000', - 'D': '000011001', - 'E': '100011000', - 'F': '001011000', - 'G': '000001101', - 'H': '100001100', - 'I': '001001100', - 'J': '000011100', - 'K': '100000011', - 'L': '001000011', - 'M': '101000010', - 'N': '000010011', - 'O': '100010010', - 'P': '001010010', - 'Q': '000000111', - 'R': '100000110', - 'S': '001000110', - 'T': '000010110', - 'U': '110000001', - 'V': '011000001', - 'W': '111000000', - 'X': '010010001', - 'Y': '110010000', - 'Z': '011010000', - '-': '010000101', - '*': '010010100', - '+': '010001010', - '$': '010101000', - '%': '000101010', - '/': '010100010', - '.': '110000100', - ' ': '011000100', -} - -class Code39(Barcode): - """Convert a text into string binary of black and white markers""" - def encode(self, text): - self.text = text.upper() - result = '' - # It is possible for us to encode code39 - # into full ascii, but this feature is - # not enabled here - for char in '*' + self.text + '*': - if not ENCODE.has_key(char): - char = '-' - result = result + ENCODE[char] + '0' - - # Now we need to encode the code39, best read - # the code to understand what it's up to: - encoded = '' - colour = '1' # 1 = Black, 0 = White - for data in result: - if data == '1': - encoded = encoded + colour + colour - else: - encoded = encoded + colour - colour = colour == '1' and '0' or '1' - - return encoded - diff --git a/share/extensions/Barcode/Code39Ext.py b/share/extensions/Barcode/Code39Ext.py deleted file mode 100644 index 3edf82d2e..000000000 --- a/share/extensions/Barcode/Code39Ext.py +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -""" -Python barcode renderer for Code39 Extended barcodes. Designed for Inkscape. -""" - -from Code39 import Code39 - -encode = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ') - -map = {} - -i = 0 -for char in encode: - map[char] = i - i = i + 1 - -# Extended encoding maps for full ASCII Code93 -def getMap(array): - result = {} - y = 0 - for x in array: - result[chr(x)] = encode[y] - y = y + 1 - - return result; - -# MapA is eclectic, but B, C, D are all ASCII ranges -mapA = getMap([27,28,29,30,31,59,60,61,62,63,91,92,93,94,95,123,124,125,126,127,0,64,96,127,127,127]) # % -mapB = getMap(range(1, 26)) # $ -mapC = getMap(range(33, 58)) # / -mapD = getMap(range(97, 122)) # + - -class Code39Ext(Code39): - def encode(self, text): - # We are only going to extend the Code39 barcodes - result = '' - for char in text: - if mapA.has_key(char): - char = '%' + mapA[char] - elif mapB.has_key(char): - char = '$' + mapB[char] - elif mapC.has_key(char): - char = '/' + mapC[char] - elif mapD.has_key(char): - char = '+' + mapD[char] - result = result + char - - return Code39.encode(self, result); - diff --git a/share/extensions/Barcode/Code93.py b/share/extensions/Barcode/Code93.py deleted file mode 100644 index d09971fe7..000000000 --- a/share/extensions/Barcode/Code93.py +++ /dev/null @@ -1,113 +0,0 @@ -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for Code93 barcodes. Designed for use with Inkscape. -""" - -from .Base import Barcode - -PALLET = list('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%') -PALLET.append('($)') -PALLET.append('(/)') -PALLET.append('(+)') -PALLET.append('(%)') -PALLET.append('MARKER') - -MAP = dict((PALLET[i], i) for i in range(len(PALLET))) - -def get_map(array): - """Extended ENCODE maps for full ASCII Code93""" - result = {} - pos = 10 - for char in array: - result[chr(char)] = PALLET[pos] - pos = pos + 1 - return result - -# MapA is eclectic, but B, C, D are all ASCII ranges -MAP_A = get_map([27, 28, 29, 30, 31, 59, 60, 61, 62, 63, 91, 92, 93, 94, 95, - 123, 124, 125, 126, 127, 0, 64, 96, 127, 127, 127]) # % -MAP_B = get_map(range(1, 26)) # $ -MAP_C = get_map(range(33, 58)) # / -MAP_D = get_map(range(97, 122)) # + - -ENCODE = [ - '100010100', '101001000', '101000100', '101000010', '100101000', - '100100100', '100100010', '101010000', '100010010', '100001010', - '110101000', '110100100', '110100010', '110010100', '110010010', - '110001010', '101101000', '101100100', '101100010', '100110100', - '100011010', '101011000', '101001100', '101000110', '100101100', - '100010110', '110110100', '110110010', '110101100', '110100110', - '110010110', '110011010', '101101100', '101100110', '100110110', - '100111010', '100101110', '111010100', '111010010', '111001010', - '101101110', '101110110', '110101110', '100100110', '111011010', - '111010110', '100110010', '101011110', '' -] - -class Code93(Barcode): - def encode(self, text): - # start marker - bits = ENCODE[MAP.get('MARKER', -1)] - - # Extend to ASCII charset ( return Array ) - text = self.encode_ascii(text) - - # Calculate the checksums - text.append(self.checksum(text, 20)) # C - text.append(self.checksum(text, 15)) # K - - # Now convert text into the ENCODE bits (black and white stripes) - for char in text: - bits = bits + ENCODE[MAP.get(char, -1)] - - # end marker and termination bar - return bits + ENCODE[MAP.get('MARKER', -1)] + '1' - - def checksum(self, text, mod): - """Generate a code 93 checksum""" - weight = len(text) % mod - check = 0 - for char in text: - check = check + (MAP[char] * weight) - # Reset the weight is required - weight = weight - 1 - if weight == 0: - weight = mod - - return PALLET[check % 47] - - # Some characters need re-ENCODE into the code93 specification - def encode_ascii(self, text): - result = [] - for char in text: - if MAP.has_key(char): - result.append(char) - elif MAP_A.has_key(char): - result.append('(%)') - result.append(MAP_A[char]) - elif MAP_B.has_key(char): - result.append('($)') - result.append(MAP_B[char]) - elif MAP_C.has_key(char): - result.append('(/)') - result.append(MAP_C[char]) - elif MAP_D.has_key(char): - result.append('(+)') - result.append(MAP_D[char]) - return result - diff --git a/share/extensions/Barcode/Ean13.py b/share/extensions/Barcode/Ean13.py deleted file mode 100644 index 71fa2257e..000000000 --- a/share/extensions/Barcode/Ean13.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 2010 Martin Owens -# -# Thanks to Lineaire Chez of Inkbar ( www.inkbar.lineaire.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 -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for EAN13 barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -class Ean13(EanBarcode): - """Provide an Ean13 barcode generator""" - name = 'ean13' - extras = {2: 'Ean2', 5: 'Ean5'} - checks = [13] - lengths = [12] - - def _encode(self, num, guide=False): - """Encode an ean13 barcode""" - self.text = self.space(num[0:1], 4, num[1:7], 5, num[7:], 7) - if guide: - self.text = self.text[:-4] + '>' - return self.enclose( - self.encode_interleaved(num[0], num[1:7]), - self.encode_right(num[7:]) - ) - - diff --git a/share/extensions/Barcode/Ean2.py b/share/extensions/Barcode/Ean2.py deleted file mode 100644 index 8b2e6fadc..000000000 --- a/share/extensions/Barcode/Ean2.py +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (C) 2016 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for EAN2 barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -FAMS = ['00', '01', '10', '11'] -START = '01011' - -class Ean2(EanBarcode): - """Provide an Ean5 barcode generator""" - length = 2 - name = 'ean5' - - def _encode(self, num, guide=False): - if len(num) != 2: - num = ([0, 0] + num)[-2:] - self.text = ' '.join(self.space(num)) - family = ((num[0] * 10) + num[1]) % 4 - return START + '01'.join(self.encode_interleaved(family, num, FAMS)) - diff --git a/share/extensions/Barcode/Ean5.py b/share/extensions/Barcode/Ean5.py deleted file mode 100644 index 9c61d7a87..000000000 --- a/share/extensions/Barcode/Ean5.py +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (C) 2009 Aaron C Spike -# 2010 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for EAN5 barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -FAMS = ['11000', '10100', '10010', '10001', '01100', - '00110', '00011', '01010', '01001', '00101'] -START = '01011' - -class Ean5(EanBarcode): - """Provide an Ean5 barcode generator""" - name = 'ean5' - length = 5 - - def _encode(self, num, guide=False): - self.text = ' '.join(self.space(num)) - family = sum([int(n) * int(m) for n, m in zip(num, '39393')]) % 10 - return START + '01'.join(self.encode_interleaved(family, num, FAMS)) - diff --git a/share/extensions/Barcode/Ean8.py b/share/extensions/Barcode/Ean8.py deleted file mode 100644 index 91c4878f9..000000000 --- a/share/extensions/Barcode/Ean8.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (C) 2010 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for EAN8 barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -class Ean8(EanBarcode): - """Provide an EAN8 barcode generator""" - name = 'ean8' - checks = [8] - lengths = [7] - - def _encode(self, num, guide=False): - """Encode an ean8 barcode""" - self.text = self.space(num[:4], 3, num[4:]) - return self.enclose( - self.encode_left(num[:4]), - self.encode_right(num[4:]) - ) - diff --git a/share/extensions/Barcode/Rm4scc.py b/share/extensions/Barcode/Rm4scc.py deleted file mode 100644 index 7c36f26ee..000000000 --- a/share/extensions/Barcode/Rm4scc.py +++ /dev/null @@ -1,134 +0,0 @@ -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -""" -Python barcode renderer for RM4CC barcodes. Designed for use with Inkscape. -""" - -from Base import Barcode - -map = { - '(' : '25', - ')' : '3', - '0' : '05053535', - '1' : '05152535', - '2' : '05153525', - '3' : '15052535', - '4' : '15053525', - '5' : '15152525', - '6' : '05251535', - '7' : '05350535', - '8' : '05351525', - '9' : '15250535', - 'A' : '15251525', - 'B' : '15350525', - 'C' : '05253515', - 'D' : '05352515', - 'E' : '05353505', - 'F' : '15252515', - 'G' : '15253505', - 'H' : '15352505', - 'I' : '25051535', - 'J' : '25150535', - 'K' : '25151525', - 'L' : '35050535', - 'M' : '35051525', - 'N' : '35150525', - 'O' : '25053525', - 'P' : '25152515', - 'Q' : '25153505', - 'R' : '35052515', - 'S' : '35053505', - 'T' : '35152505', - 'U' : '25251515', - 'V' : '25350515', - 'W' : '25351505', - 'X' : '35250515', - 'Y' : '35251505', - 'Z' : '35350505', -} - -check = ['ZUVWXY','501234','B6789A','HCDEFG','NIJKLM','TOPQRS'] -(BAR_TRACK, BAR_DOWN, BAR_UP, BAR_FULL, BAR_NONE, WHITE_SPACE) = range(6) - -class Rm4scc(Barcode): - default_height = 18 - - def encode(self, text): - result = '' - - text = text.upper() - text.replace('(', '') - text.replace(')', '') - - text = '(' + text + self.checksum(text) + ')' - - i = 0 - for char in text: - if map.has_key(char): - result = result + map[char] - i = i + 1 - - return result; - - # given a string of data, return the check character - def checksum(self, text): - total_lower = 0 - total_upper = 0 - for char in text: - if map.has_key(char): - bars = map[char][0:8:2] - lower = 0 - upper = 0 - - if int(bars[0]) & 1: - lower = lower + 4 - if int(bars[1]) & 1: - lower = lower + 2 - if int(bars[2]) & 1: - lower = lower + 1 - if int(bars[0]) & 2: - upper = upper + 4 - if int(bars[1]) & 2: - upper = upper + 2 - if int(bars[2]) & 2: - upper = upper + 1 - total_lower = total_lower + (lower % 6) - total_upper = total_upper + (upper % 6) - - total_lower = total_upper % 6 - total_upper = total_upper % 6 - - checkchar = check[total_upper][total_lower] - return checkchar - - def get_style(self, index): - """Royal Mail Barcodes use a completely different style""" - result = { 'width' : 2, 'write' : True, 'top' : 0 } - if index == BAR_TRACK: # Track Bar - result['top'] = 6 - result['height'] = 5 - elif index == BAR_DOWN: # Decender Bar - result['top'] = 6 - result['height'] = 11 - elif index == BAR_UP: # Accender Bar - result['height'] = 11 - elif index == BAR_FULL: # Full Bar - result['height'] = 17 - elif index == WHITE_SPACE: # White Space - result['write'] = False - return result diff --git a/share/extensions/Barcode/Upca.py b/share/extensions/Barcode/Upca.py deleted file mode 100644 index fdd506648..000000000 --- a/share/extensions/Barcode/Upca.py +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for UPCA barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -class Upca(EanBarcode): - """Provides a renderer for EAN12 aka UPC-A Barcodes""" - name = 'upca' - font_size = 10 - lengths = [11] - checks = [12] - - def _encode(self, num, guide=False): - """Encode for a UPC-A Barcode""" - self.text = self.space(num[0:1], 3, num[1:6], 4, num[6:11], 3, num[11:]) - return self.enclose( - self.encode_left(num[0:6]), - self.encode_right(num[6:12]), - ) - diff --git a/share/extensions/Barcode/Upce.py b/share/extensions/Barcode/Upce.py deleted file mode 100644 index 6dfbaf0b6..000000000 --- a/share/extensions/Barcode/Upce.py +++ /dev/null @@ -1,99 +0,0 @@ -# -# Copyright (C) 2010 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Python barcode renderer for UPCE barcodes. Designed for use with Inkscape. -""" - -from .BaseEan import EanBarcode - -# This is almost exactly the same as the standard FAMILIES -# But flipped around and with the first 111000 instead of 000000. -FAMS = ['111000', '110100', '110010', '110001', '101100', - '100110', '100011', '101010', '101001', '100101'] - -class Upce(EanBarcode): - """Generate EAN6/UPC-E barcode generator""" - name = 'upce' - font_size = 10 - lengths = [6, 11] - checks = [7, 12] - center_bar = '020' - - def _encode(self, num, guide=False): - """Generate a UPC-E Barcode""" - self.text = self.space(['0'], 2, num[:6], 2, num[-1]) - code = self.encode_interleaved(num[-1], num[:6], FAMS) - return self.enclose(code) - - def append_checksum(self, number): - """Generate a UPCE Checksum""" - if len(number) == 6: - number = self.convert_e2a(number) - result = self.get_checksum(number) - return self.convert_a2e(number) + result - - def convert_a2e(self, number): - """Converting UPC-A to UPC-E, may cause errors.""" - # All UPC-E Numbers use number system 0 - if number[0] != '0' or len(number) != 11: - # If not then the code is invalid - raise ValueError("Invalid UPC Number") - - # Most of the conversions deal - # with the specific code parts - maker = number[1:6] - product = number[6:11] - - # There are 4 cases to convert: - if maker[2:] == '000' or maker[2:] == '100' or maker[2:] == '200': - # Maximum number product code digits can be encoded - if product[:2] == '00': - return maker[:2] + product[2:] + maker[2] - elif maker[3:5] == '00': - # Now only 2 product code digits can be used - if product[:3] == '000': - return maker[:3] + product[3:] + '3' - elif maker[4] == '0': - # With even more maker code we have less room for product code - if product[:4] == '0000': - return maker[0:4] + product[4] + '4' - elif product[:4] == '0000' and int(product[4]) > 4: - # The last recorse is to try and squeeze it in the last 5 numbers - # so long as the product is 00005-00009 so as not to conflict with - # the 0-4 used above. - return maker + product[4] - else: - # Invalid UPC-A Numbe - raise ValueError("Invalid UPC Number") - - def convert_e2a(self, number): - """Convert UPC-E to UPC-A by padding with zeros""" - # It's more likly to convert this without fault - # But we still must be mindful of the 4 conversions - if len(number) != 6: - return None - - if number[5] in ['0', '1', '2']: - return '0' + number[:2] + number[5] + '0000' + number[2:5] - elif number[5] == '3': - return '0' + number[:3] + '00000' + number[3:5] - elif number[5] == '4': - return '0' + number[:4] + '00000' + number[4] - else: - return '0' + number[:5] + '0000' + number[5] - diff --git a/share/extensions/Barcode/__init__.py b/share/extensions/Barcode/__init__.py deleted file mode 100644 index 486366c4c..000000000 --- a/share/extensions/Barcode/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright (C) 2014 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -""" -Renderer for barcodes, SVG extension for Inkscape. - -For supported barcodes see Barcode module directory. -""" - -# This lists all known Barcodes missing from this package -# ===== UPC-Based Extensions ====== # -# Code11 -# ========= Code25-Based ========== # -# Codabar -# Postnet -# ITF25 -# ========= Alpha-numeric ========= # -# Code39Mod -# USPS128 -# =========== 2D Based ============ # -# PDF417 -# PDF417-Macro -# PDF417-Truncated -# PDF417-GLI - -import sys - -class NoBarcode(object): - """Simple class for no barcode""" - def generate(self): - return None - -def getBarcode(code, **kw): - """Gets a barcode from a list of available barcode formats""" - if not code: - return sys.stderr.write("No barcode format given!\n") - - code = str(code).replace('-', '').strip() - mod = 'Barcode' - try: - return getattr(__import__(mod+'.'+code, fromlist=[mod]), code)(kw) - except ImportError: - sys.stderr.write("Invalid type of barcode: %s\n" % code) - except AttributeError: - sys.stderr.write("Barcode module is missing barcode class: %s\n" % code) - return NoBarcode() - diff --git a/share/extensions/CMakeLists.txt b/share/extensions/CMakeLists.txt deleted file mode 100644 index 47dfbe0a0..000000000 --- a/share/extensions/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -# Install the set of non-executable data files -file(GLOB _FILES - "README" - "fontfix.conf" - "inkweb.js" - "jessyInk.js" - "jessyInk_core_mouseHandler_noclick.js" - "jessyInk_core_mouseHandler_zoomControl.js" - "aisvg.xslt" - "colors.xml" - "jessyInk_video.svg" - "seamless_pattern.svg" - "svg2fxg.xsl" - "svg2xaml.xsl" - "xaml2svg.xsl" - "inkscape.extension.rng" - "*.inx" - ) - -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions) - -# Install the executable scripts -file(GLOB _SCRIPTS - "*.py" - "*.pl" - "*.sh" - "*.rb" - ) -# These files don't need the +x bit -set(_SCRIPTS_NOEXEC - "hersheydata.py" - "hpgl_decoder.py" - "hpgl_encoder.py" - "simplepath.py" - "simplestyle.py" - "simpletransform.py" -) -list(REMOVE_ITEM _SCRIPTS ${_SCRIPTS_NOEXEC}) -install(PROGRAMS ${_SCRIPTS} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions) -install(FILES ${_SCRIPTS_NOEXEC} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions) - -file(GLOB _FILES "alphabet_soup/*.svg") -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/alphabet_soup) - -file(GLOB _FILES "Barcode/*.py") -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/Barcode) - -file(GLOB _FILES "Poly3DObjects/*.obj") -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/Poly3DObjects) - -# file(GLOB _FILES -# "test/*.svg" -# "test/*.sh" -# "test/*.py" -# "test/*.js" -# "test/run-all-extension-tests" -# ) -# install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/test) - -file(GLOB _FILES "ink2canvas/*.py") -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/ink2canvas) - -file(GLOB _FILES "xaml2svg/*.xsl") -install(FILES ${_FILES} DESTINATION ${INKSCAPE_SHARE_INSTALL}/extensions/xaml2svg) diff --git a/share/extensions/Poly3DObjects/cube.obj b/share/extensions/Poly3DObjects/cube.obj deleted file mode 100644 index b577ce11d..000000000 --- a/share/extensions/Poly3DObjects/cube.obj +++ /dev/null @@ -1,19 +0,0 @@ -#Name:Cube -#Type:Face-specified -#Direction:Clockwise - -v -0.5 -0.5 -0.5 -v -0.5 -0.5 0.5 -v -0.5 0.5 -0.5 -v -0.5 0.5 0.5 -v 0.5 -0.5 -0.5 -v 0.5 -0.5 0.5 -v 0.5 0.5 -0.5 -v 0.5 0.5 0.5 - -f 8 4 2 6 -f 8 6 5 7 -f 8 7 3 4 -f 4 3 1 2 -f 1 3 7 5 -f 2 1 5 6
\ No newline at end of file diff --git a/share/extensions/Poly3DObjects/cuboct.obj b/share/extensions/Poly3DObjects/cuboct.obj deleted file mode 100644 index 709606bca..000000000 --- a/share/extensions/Poly3DObjects/cuboct.obj +++ /dev/null @@ -1,30 +0,0 @@ -#Name:Cuboctahedron -#Type:Face_specified - -v -1. 0 0 -v -0.5 -0.5 -0.70710678 -v -0.5 -0.5 0.70710678 -v -0.5 0.5 -0.70710678 -v -0.5 0.5 0.70710678 -v 0 -1. 0 -v 0 1. 0 -v 0.5 -0.5 -0.70710678 -v 0.5 -0.5 0.70710678 -v 0.5 0.5 -0.70710678 -v 0.5 0.5 0.70710678 -v 1. 0 0 - -f 12 11 9 -f 3 5 1 -f 6 9 3 -f 5 11 7 -f 8 10 12 -f 1 4 2 -f 2 8 6 -f 7 10 4 -f 4 10 8 2 -f 3 9 11 5 -f 9 6 8 12 -f 3 1 2 6 -f 5 7 4 1 -f 11 12 10 7 diff --git a/share/extensions/Poly3DObjects/dodec.obj b/share/extensions/Poly3DObjects/dodec.obj deleted file mode 100644 index 5b66f09e0..000000000 --- a/share/extensions/Poly3DObjects/dodec.obj +++ /dev/null @@ -1,36 +0,0 @@ -#NameDodecahedron -#Type:Face_specified - -v 0 0 1.4012585 -v 0 0 -1.4012585 -v 0.17841104 -1.3090170 0.46708618 -v 0.17841104 1.3090170 0.46708618 -v 0.46708618 -0.80901699 -1.0444364 -v 0.46708618 0.80901699 -1.0444364 -v 1.0444364 -0.80901699 0.46708618 -v 1.0444364 0.80901699 0.46708618 -v -1.2228475 -0.5 0.46708618 -v -1.2228475 0.5 0.46708618 -v 1.2228475 -0.5 -0.46708618 -v 1.2228475 0.5 -0.46708618 -v -0.93417236 0 -1.0444364 -v -0.46708618 -0.80901699 1.0444364 -v -0.46708618 0.80901699 1.0444364 -v 0.93417236 0 1.0444364 -v -1.0444364 -0.80901699 -0.46708618 -v -1.0444364 0.80901699 -0.46708618 -v -0.17841104 -1.3090170 -0.46708618 -v -0.17841104 1.3090170 -0.46708618 - -f 15 10 9 14 1 -f 2 6 12 11 5 -f 5 11 7 3 19 -f 11 12 8 16 7 -f 12 6 20 4 8 -f 6 2 13 18 20 -f 2 5 19 17 13 -f 4 20 18 10 15 -f 18 13 17 9 10 -f 17 19 3 14 9 -f 3 7 16 1 14 -f 16 8 4 15 1 diff --git a/share/extensions/Poly3DObjects/great_dodec.obj b/share/extensions/Poly3DObjects/great_dodec.obj deleted file mode 100644 index 2d12f028e..000000000 --- a/share/extensions/Poly3DObjects/great_dodec.obj +++ /dev/null @@ -1,96 +0,0 @@ -#Name:Great Dodecahedron -#Type:Face_specified - -v 0. 0. -0.951057 -v 0. 0. 0.951057 -v -0.425325 -0.309017 -0.100406 -v -0.425325 0.309017 -0.100406 -v 0.425325 -0.309017 0.100406 -v 0.425325 0.309017 0.100406 -v -0.688191 -0.5 0.425325 -v -0.688191 0.5 0.425325 -v 0.688191 -0.5 -0.425325 -v 0.688191 0.5 -0.425325 -v -0.850651 0. -0.425325 -v 0.850651 0. 0.425325 -v -0.100406 -0.309017 0.425325 -v -0.100406 0.309017 0.425325 -v 0.100406 -0.309017 -0.425325 -v 0.100406 0.309017 -0.425325 -v -0.32492 0. 0.425325 -v -0.16246 -0.5 0.100406 -v -0.16246 0.5 0.100406 -v 0.16246 -0.5 -0.100406 -v 0.16246 0.5 -0.100406 -v 0.32492 0. -0.425325 -v -0.525731 0. 0.100406 -v -0.262866 -0.809017 -0.425325 -v -0.262866 0.190983 -0.425325 -v -0.262866 -0.190983 -0.425325 -v -0.262866 0.809017 -0.425325 -v 0.262866 -0.809017 0.425325 -v 0.262866 0.190983 0.425325 -v 0.262866 -0.190983 0.425325 -v 0.262866 0.809017 0.425325 -v 0.525731 0. -0.100406 - -f 14 2 31 -f 14 31 8 -f 14 8 2 -f 17 2 8 -f 17 8 7 -f 17 7 2 -f 13 2 7 -f 13 7 28 -f 13 28 2 -f 30 2 28 -f 30 28 12 -f 30 12 2 -f 29 2 12 -f 29 12 31 -f 29 31 2 -f 15 9 24 -f 15 24 1 -f 15 1 9 -f 22 10 9 -f 22 9 1 -f 22 1 10 -f 16 27 10 -f 16 10 1 -f 16 1 27 -f 25 11 27 -f 25 27 1 -f 25 1 11 -f 26 24 11 -f 26 11 1 -f 26 1 24 -f 19 31 27 -f 19 27 8 -f 19 8 31 -f 23 8 11 -f 23 11 7 -f 23 7 8 -f 18 7 24 -f 18 24 28 -f 18 28 7 -f 5 28 9 -f 5 9 12 -f 5 12 28 -f 6 12 10 -f 6 10 31 -f 6 31 12 -f 20 9 28 -f 20 28 24 -f 20 24 9 -f 32 10 12 -f 32 12 9 -f 32 9 10 -f 21 27 31 -f 21 31 10 -f 21 10 27 -f 4 11 8 -f 4 8 27 -f 4 27 11 -f 3 24 7 -f 3 7 11 -f 3 11 24 diff --git a/share/extensions/Poly3DObjects/great_rhombicosidodec.obj b/share/extensions/Poly3DObjects/great_rhombicosidodec.obj deleted file mode 100644 index 88bdccc55..000000000 --- a/share/extensions/Poly3DObjects/great_rhombicosidodec.obj +++ /dev/null @@ -1,185 +0,0 @@ -#Name:Great Rhombicosidodecahedron -#Type:face_specified -v -1. -1.30902 -3.42705 -v -1. -1.30902 3.42705 -v -1. 1.30902 -3.42705 -v -1. 1.30902 3.42705 -v -0.5 -0.5 -3.73607 -v -0.5 -0.5 3.73607 -v -0.5 0.5 -3.73607 -v -0.5 0.5 3.73607 -v -0.5 -3.73607 -0.5 -v -0.5 -3.73607 0.5 -v -0.5 -2.11803 -3.11803 -v -0.5 -2.11803 3.11803 -v -0.5 3.73607 -0.5 -v -0.5 3.73607 0.5 -v -0.5 2.11803 -3.11803 -v -0.5 2.11803 3.11803 -v 0.5 -0.5 -3.73607 -v 0.5 -0.5 3.73607 -v 0.5 0.5 -3.73607 -v 0.5 0.5 3.73607 -v 0.5 -3.73607 -0.5 -v 0.5 -3.73607 0.5 -v 0.5 -2.11803 -3.11803 -v 0.5 -2.11803 3.11803 -v 0.5 3.73607 -0.5 -v 0.5 3.73607 0.5 -v 0.5 2.11803 -3.11803 -v 0.5 2.11803 3.11803 -v 1. -1.30902 -3.42705 -v 1. -1.30902 3.42705 -v 1. 1.30902 -3.42705 -v 1. 1.30902 3.42705 -v -3.42705 -1. -1.30902 -v -3.42705 -1. 1.30902 -v -3.42705 1. -1.30902 -v -3.42705 1. 1.30902 -v -2.92705 -1.80902 -1.61803 -v -2.92705 -1.80902 1.61803 -v -2.92705 1.80902 -1.61803 -v -2.92705 1.80902 1.61803 -v -1.80902 -1.61803 -2.92705 -v -1.80902 -1.61803 2.92705 -v -1.80902 1.61803 -2.92705 -v -1.80902 1.61803 2.92705 -v -1.30902 -3.42705 -1. -v -1.30902 -3.42705 1. -v -1.30902 -2.42705 -2.61803 -v -1.30902 -2.42705 2.61803 -v -1.30902 2.42705 -2.61803 -v -1.30902 2.42705 2.61803 -v -1.30902 3.42705 -1. -v -1.30902 3.42705 1. -v -2.61803 -1.30902 -2.42705 -v -2.61803 -1.30902 2.42705 -v -2.61803 1.30902 -2.42705 -v -2.61803 1.30902 2.42705 -v -3.73607 -0.5 -0.5 -v -3.73607 -0.5 0.5 -v -3.73607 0.5 -0.5 -v -3.73607 0.5 0.5 -v -1.61803 -2.92705 -1.80902 -v -1.61803 -2.92705 1.80902 -v -1.61803 2.92705 -1.80902 -v -1.61803 2.92705 1.80902 -v -3.11803 -0.5 -2.11803 -v -3.11803 -0.5 2.11803 -v -3.11803 0.5 -2.11803 -v -3.11803 0.5 2.11803 -v -2.11803 -3.11803 -0.5 -v -2.11803 -3.11803 0.5 -v -2.11803 3.11803 -0.5 -v -2.11803 3.11803 0.5 -v -2.42705 -2.61803 -1.30902 -v -2.42705 -2.61803 1.30902 -v -2.42705 2.61803 -1.30902 -v -2.42705 2.61803 1.30902 -v 1.61803 -2.92705 -1.80902 -v 1.61803 -2.92705 1.80902 -v 1.61803 2.92705 -1.80902 -v 1.61803 2.92705 1.80902 -v 2.42705 -2.61803 -1.30902 -v 2.42705 -2.61803 1.30902 -v 2.42705 2.61803 -1.30902 -v 2.42705 2.61803 1.30902 -v 3.73607 -0.5 -0.5 -v 3.73607 -0.5 0.5 -v 3.73607 0.5 -0.5 -v 3.73607 0.5 0.5 -v 2.11803 -3.11803 -0.5 -v 2.11803 -3.11803 0.5 -v 2.11803 3.11803 -0.5 -v 2.11803 3.11803 0.5 -v 1.30902 -3.42705 -1. -v 1.30902 -3.42705 1. -v 1.30902 -2.42705 -2.61803 -v 1.30902 -2.42705 2.61803 -v 1.30902 2.42705 -2.61803 -v 1.30902 2.42705 2.61803 -v 1.30902 3.42705 -1. -v 1.30902 3.42705 1. -v 2.61803 -1.30902 -2.42705 -v 2.61803 -1.30902 2.42705 -v 2.61803 1.30902 -2.42705 -v 2.61803 1.30902 2.42705 -v 3.11803 -0.5 -2.11803 -v 3.11803 -0.5 2.11803 -v 3.11803 0.5 -2.11803 -v 3.11803 0.5 2.11803 -v 1.80902 -1.61803 -2.92705 -v 1.80902 -1.61803 2.92705 -v 1.80902 1.61803 -2.92705 -v 1.80902 1.61803 2.92705 -v 2.92705 -1.80902 -1.61803 -v 2.92705 -1.80902 1.61803 -v 2.92705 1.80902 -1.61803 -v 2.92705 1.80902 1.61803 -v 3.42705 -1. -1.30902 -v 3.42705 -1. 1.30902 -v 3.42705 1. -1.30902 -v 3.42705 1. 1.30902 - -f 2 6 8 4 44 56 68 66 54 42 -f 109 29 17 19 31 111 103 107 105 101 -f 24 30 18 6 2 12 -f 7 3 15 27 31 19 -f 58 57 33 37 73 69 70 74 38 34 -f 84 116 120 88 87 119 115 83 91 92 -f 90 89 81 113 117 85 86 118 114 82 -f 36 40 76 72 71 75 39 35 59 60 -f 5 17 29 23 11 1 -f 4 8 20 32 28 16 -f 67 55 43 3 7 5 1 41 53 65 -f 18 30 110 102 106 108 104 112 32 20 -f 79 83 115 103 111 97 -f 38 74 62 48 42 54 -f 4 16 50 44 -f 23 29 109 95 -f 96 110 30 24 -f 43 49 15 3 -f 53 41 47 61 73 37 -f 98 112 104 116 84 80 -f 69 45 9 10 46 70 -f 26 100 92 91 99 25 -f 82 114 102 110 96 78 -f 55 39 75 63 49 43 -f 1 11 47 41 -f 28 32 112 98 -f 61 47 11 23 95 77 93 21 9 45 -f 50 16 28 98 80 100 26 14 52 64 -f 97 111 31 27 -f 42 48 12 2 -f 44 50 64 76 40 56 -f 77 95 109 101 113 81 -f 63 51 13 25 99 79 97 27 15 49 -f 46 10 22 94 78 96 24 12 48 62 -f 52 14 13 51 71 72 -f 22 21 93 89 90 94 -f 115 119 107 103 -f 34 38 54 66 -f 71 51 63 75 -f 94 90 82 78 -f 114 118 106 102 -f 35 39 55 67 -f 70 46 62 74 -f 99 91 83 79 -f 65 53 37 33 -f 104 108 120 116 -f 77 81 89 93 -f 76 64 52 72 -f 59 35 67 65 33 57 -f 106 118 86 88 120 108 -f 68 56 40 36 -f 101 105 117 113 -f 80 84 92 100 -f 73 61 45 69 -f 34 66 68 36 60 58 -f 105 107 119 87 85 117 -f 7 19 17 5 -f 6 18 20 8 -f 14 26 25 13 -f 9 21 22 10 -f 58 60 59 57 -f 85 87 88 86 diff --git a/share/extensions/Poly3DObjects/great_rhombicuboct.obj b/share/extensions/Poly3DObjects/great_rhombicuboct.obj deleted file mode 100644 index 1ef7b4c79..000000000 --- a/share/extensions/Poly3DObjects/great_rhombicuboct.obj +++ /dev/null @@ -1,77 +0,0 @@ -#Name:Great Rhombicuboctahedron -#Type:face_specified -v -0.5 1.20711 -1.91421 -v -0.5 1.20711 1.91421 -v -0.5 -1.20711 -1.91421 -v -0.5 -1.20711 1.91421 -v -0.5 -1.91421 1.20711 -v -0.5 -1.91421 -1.20711 -v -0.5 1.91421 1.20711 -v -0.5 1.91421 -1.20711 -v 0.5 1.20711 -1.91421 -v 0.5 1.20711 1.91421 -v 0.5 -1.20711 -1.91421 -v 0.5 -1.20711 1.91421 -v 0.5 -1.91421 1.20711 -v 0.5 -1.91421 -1.20711 -v 0.5 1.91421 1.20711 -v 0.5 1.91421 -1.20711 -v 1.20711 -0.5 -1.91421 -v 1.20711 -0.5 1.91421 -v 1.20711 0.5 -1.91421 -v 1.20711 0.5 1.91421 -v 1.20711 -1.91421 -0.5 -v 1.20711 -1.91421 0.5 -v 1.20711 1.91421 -0.5 -v 1.20711 1.91421 0.5 -v -1.20711 -0.5 -1.91421 -v -1.20711 -0.5 1.91421 -v -1.20711 0.5 -1.91421 -v -1.20711 0.5 1.91421 -v -1.20711 -1.91421 -0.5 -v -1.20711 -1.91421 0.5 -v -1.20711 1.91421 -0.5 -v -1.20711 1.91421 0.5 -v -1.91421 -0.5 1.20711 -v -1.91421 -0.5 -1.20711 -v -1.91421 0.5 1.20711 -v -1.91421 0.5 -1.20711 -v -1.91421 1.20711 -0.5 -v -1.91421 1.20711 0.5 -v -1.91421 -1.20711 -0.5 -v -1.91421 -1.20711 0.5 -v 1.91421 -0.5 1.20711 -v 1.91421 -0.5 -1.20711 -v 1.91421 0.5 1.20711 -v 1.91421 0.5 -1.20711 -v 1.91421 1.20711 -0.5 -v 1.91421 1.20711 0.5 -v 1.91421 -1.20711 -0.5 -v 1.91421 -1.20711 0.5 - -f 44 42 17 19 -f 14 6 3 11 -f 34 36 27 25 -f 8 16 9 1 -f 20 18 41 43 -f 12 4 5 13 -f 26 28 35 33 -f 2 10 15 7 -f 45 23 24 46 -f 39 29 30 40 -f 48 22 21 47 -f 38 32 31 37 -f 9 19 17 11 3 25 27 1 -f 2 28 26 4 12 18 20 10 -f 41 48 47 42 44 45 46 43 -f 35 38 37 36 34 39 40 33 -f 15 24 23 16 8 31 32 7 -f 5 30 29 6 14 21 22 13 -f 46 24 15 10 20 43 -f 35 28 2 7 32 38 -f 41 18 12 13 22 48 -f 40 30 5 4 26 33 -f 44 19 9 16 23 45 -f 37 31 8 1 27 36 -f 47 21 14 11 17 42 -f 34 25 3 6 29 39 diff --git a/share/extensions/Poly3DObjects/great_stel_dodec.obj b/share/extensions/Poly3DObjects/great_stel_dodec.obj deleted file mode 100644 index b0e542996..000000000 --- a/share/extensions/Poly3DObjects/great_stel_dodec.obj +++ /dev/null @@ -1,96 +0,0 @@ -#Name:Great Stellated Dodecahedron -#Type:face_specified - -v 0. 0. -0.951057 -v 0. 0. 0.951057 -v -0.425325 -1.30902 1.80171 -v -0.425325 1.30902 1.80171 -v 0.425325 -1.30902 -1.80171 -v 0.425325 1.30902 -1.80171 -v -0.688191 -0.5 0.425325 -v -0.688191 0.5 0.425325 -v -0.688191 -2.11803 0.425325 -v -0.688191 2.11803 0.425325 -v 0.688191 -0.5 -0.425325 -v 0.688191 0.5 -0.425325 -v 0.688191 -2.11803 -0.425325 -v 0.688191 2.11803 -0.425325 -v -0.850651 0. -0.425325 -v 0.850651 0. 0.425325 -v -1.11352 -0.809017 -1.80171 -v -1.11352 0.809017 -1.80171 -v 1.11352 -0.809017 1.80171 -v 1.11352 0.809017 1.80171 -v -1.80171 -1.30902 -0.425325 -v -1.80171 1.30902 -0.425325 -v 1.80171 -1.30902 0.425325 -v 1.80171 1.30902 0.425325 -v -2.22703 0. 0.425325 -v 2.22703 0. -0.425325 -v -0.262866 -0.809017 -0.425325 -v -0.262866 0.809017 -0.425325 -v 0.262866 -0.809017 0.425325 -v 0.262866 0.809017 0.425325 -v -1.37638 0. 1.80171 -v 1.37638 0. -1.80171 - -f 4 2 30 -f 4 30 8 -f 4 8 2 -f 31 2 8 -f 31 8 7 -f 31 7 2 -f 3 2 7 -f 3 7 29 -f 3 29 2 -f 19 2 29 -f 19 29 16 -f 19 16 2 -f 20 2 16 -f 20 16 30 -f 20 30 2 -f 5 11 27 -f 5 27 1 -f 5 1 11 -f 32 12 11 -f 32 11 1 -f 32 1 12 -f 6 28 12 -f 6 12 1 -f 6 1 28 -f 18 15 28 -f 18 28 1 -f 18 1 15 -f 17 27 15 -f 17 15 1 -f 17 1 27 -f 10 30 28 -f 10 28 8 -f 10 8 30 -f 25 8 15 -f 25 15 7 -f 25 7 8 -f 9 7 27 -f 9 27 29 -f 9 29 7 -f 23 29 11 -f 23 11 16 -f 23 16 29 -f 24 16 12 -f 24 12 30 -f 24 30 16 -f 13 11 29 -f 13 29 27 -f 13 27 11 -f 26 12 16 -f 26 16 11 -f 26 11 12 -f 14 28 30 -f 14 30 12 -f 14 12 28 -f 22 15 8 -f 22 8 28 -f 22 28 15 -f 21 27 7 -f 21 7 15 -f 21 15 27 diff --git a/share/extensions/Poly3DObjects/icos.obj b/share/extensions/Poly3DObjects/icos.obj deleted file mode 100644 index ed55ea4fc..000000000 --- a/share/extensions/Poly3DObjects/icos.obj +++ /dev/null @@ -1,36 +0,0 @@ -#Name:Icosahedron -#Type:face_specified - -v 0 0 -0.95105652 -v 0 0 0.95105652 -v -0.85065081 0 -0.42532540 -v 0.85065081 0 0.42532540 -v 0.68819096 -0.50000000 -0.42532540 -v 0.68819096 0.50000000 -0.42532540 -v -0.68819096 -0.50000000 0.42532540 -v -0.68819096 0.50000000 0.42532540 -v -0.26286556 -0.80901699 -0.42532540 -v -0.26286556 0.80901699 -0.42532540 -v 0.26286556 -0.80901699 0.42532540 -v 0.26286556 0.80901699 0.42532540 - -f 2 12 8 -f 2 8 7 -f 2 7 11 -f 2 11 4 -f 2 4 12 -f 5 9 1 -f 6 5 1 -f 10 6 1 -f 3 10 1 -f 9 3 1 -f 12 10 8 -f 8 3 7 -f 7 9 11 -f 11 5 4 -f 4 6 12 -f 5 11 9 -f 6 4 5 -f 10 12 6 -f 3 8 10 -f 9 7 3 diff --git a/share/extensions/Poly3DObjects/icosidodec.obj b/share/extensions/Poly3DObjects/icosidodec.obj deleted file mode 100644 index 961bec20f..000000000 --- a/share/extensions/Poly3DObjects/icosidodec.obj +++ /dev/null @@ -1,65 +0,0 @@ -#Name:Icosidodecahedron -#Type:face_specified -v 0. -1.61803 0. -v 0. 1.61803 0. -v 0.262866 -0.809017 -1.37638 -v 0.262866 0.809017 -1.37638 -v 0.425325 -1.30902 0.850651 -v 0.425325 1.30902 0.850651 -v 0.688191 -0.5 1.37638 -v 0.688191 0.5 1.37638 -v 1.11352 -0.809017 -0.850651 -v 1.11352 0.809017 -0.850651 -v -1.37638 0. -0.850651 -v -0.688191 -0.5 -1.37638 -v -0.688191 0.5 -1.37638 -v 1.37638 0. 0.850651 -v 0.951057 -1.30902 0. -v 0.951057 1.30902 0. -v 0.850651 0. -1.37638 -v -0.951057 -1.30902 0. -v -0.951057 1.30902 0. -v -1.53884 -0.5 0. -v -1.53884 0.5 0. -v 1.53884 -0.5 0. -v 1.53884 0.5 0. -v -0.850651 0. 1.37638 -v -1.11352 -0.809017 0.850651 -v -1.11352 0.809017 0.850651 -v -0.425325 -1.30902 -0.850651 -v -0.425325 1.30902 -0.850651 -v -0.262866 -0.809017 1.37638 -v -0.262866 0.809017 1.37638 - -f 30 24 29 7 8 -f 26 24 30 -f 25 29 24 -f 5 7 29 -f 14 8 7 -f 6 30 8 -f 16 2 6 -f 19 21 26 -f 20 18 25 -f 1 15 5 -f 22 23 14 -f 2 19 26 30 6 -f 21 20 25 24 26 -f 18 1 5 29 25 -f 15 22 14 7 5 -f 23 16 6 8 14 -f 12 13 4 17 3 -f 3 17 9 -f 17 4 10 -f 4 13 28 -f 13 12 11 -f 12 3 27 -f 27 1 18 -f 9 22 15 -f 10 16 23 -f 28 19 2 -f 11 20 21 -f 27 3 9 15 1 -f 9 17 10 23 22 -f 10 4 28 2 16 -f 28 13 11 21 19 -f 11 12 27 18 20 diff --git a/share/extensions/Poly3DObjects/jessens_orthog_icos.obj b/share/extensions/Poly3DObjects/jessens_orthog_icos.obj deleted file mode 100644 index 41aff7a62..000000000 --- a/share/extensions/Poly3DObjects/jessens_orthog_icos.obj +++ /dev/null @@ -1,35 +0,0 @@ -#Name:Jessen's Orthogonal Icosahedron -#Type:face_specified -v 0. -0.809017 0.5 -v 0. -0.809017 -0.5 -v 0. 0.809017 0.5 -v 0. 0.809017 -0.5 -v 0.5 0. -0.809017 -v 0.5 0. 0.809017 -v -0.5 0. -0.809017 -v -0.5 0. 0.809017 -v -0.809017 0.5 0. -v -0.809017 -0.5 0. -v 0.809017 0.5 0. -v 0.809017 -0.5 0. - -f 3 1 6 -f 6 1 12 -f 6 12 5 -f 11 3 6 -f 6 5 11 -f 12 1 10 -f 12 10 2 -f 5 12 2 -f 3 11 9 -f 1 3 8 -f 8 10 1 -f 7 2 10 -f 10 8 7 -f 3 9 8 -f 7 8 9 -f 5 2 4 -f 2 7 4 -f 7 9 4 -f 4 9 11 -f 5 4 11
\ No newline at end of file diff --git a/share/extensions/Poly3DObjects/methane.obj b/share/extensions/Poly3DObjects/methane.obj deleted file mode 100644 index 0b2d74411..000000000 --- a/share/extensions/Poly3DObjects/methane.obj +++ /dev/null @@ -1,13 +0,0 @@ -#Name:Methane Molecule -#Type:edge_specified - -v 0 0 0 -v 0 0 0.61237244 -v -0.28867513 -0.50000000 -0.20412415 -v -0.28867513 0.50000000 -0.20412415 -v 0.57735027 0 -0.20412415 - -l 1 2 -l 1 3 -l 1 4 -l 1 5 diff --git a/share/extensions/Poly3DObjects/oct.obj b/share/extensions/Poly3DObjects/oct.obj deleted file mode 100644 index f356b6986..000000000 --- a/share/extensions/Poly3DObjects/oct.obj +++ /dev/null @@ -1,17 +0,0 @@ -#Name:Octahedron -#Type:face_specified -v -0.5 -0.5 0 -v -0.5 0.5 0 -v 0 0 -0.70710678 -v 0 0 0.70710678 -v 0.5 -0.5 0 -v 0.5 0.5 0 - -f 4 5 6 -f 4 6 2 -f 4 2 1 -f 4 1 5 -f 5 1 3 -f 5 3 6 -f 3 1 2 -f 6 3 2 diff --git a/share/extensions/Poly3DObjects/rh_axes.obj b/share/extensions/Poly3DObjects/rh_axes.obj deleted file mode 100644 index cc6623fc2..000000000 --- a/share/extensions/Poly3DObjects/rh_axes.obj +++ /dev/null @@ -1,12 +0,0 @@ -#Name:Right Handed Coordinate Axes -#Type:Edge_specified - -v 0 0 0 -v 1 0 0 -v 0 1 0 -v 0 0 1 - -l 1 2 -l 1 3 -l 1 4 - diff --git a/share/extensions/Poly3DObjects/rhomb_dodec.obj b/share/extensions/Poly3DObjects/rhomb_dodec.obj deleted file mode 100644 index 9fde9d669..000000000 --- a/share/extensions/Poly3DObjects/rhomb_dodec.obj +++ /dev/null @@ -1,29 +0,0 @@ -#Name:Rhombic Dodecahedron -#Type:face_specified -v -0.816497 -0.816497 0. -v -0.816497 0. -0.57735 -v -0.816497 0. 0.57735 -v -0.816497 0.816497 0. -v 0. -0.816497 -0.57735 -v 0. -0.816497 0.57735 -v 0. 0. -1.1547 -v 0. 0. 1.1547 -v 0. 0.816497 -0.57735 -v 0. 0.816497 0.57735 -v 0.816497 -0.816497 0. -v 0.816497 0. -0.57735 -v 0.816497 0. 0.57735 -v 0.816497 0.816497 0. - -f 2 1 3 4 -f 1 2 7 5 -f 6 8 3 1 -f 2 4 9 7 -f 8 10 4 3 -f 11 6 1 5 -f 9 4 10 14 -f 5 7 12 11 -f 11 13 8 6 -f 7 9 14 12 -f 13 14 10 8 -f 14 13 11 12
\ No newline at end of file diff --git a/share/extensions/Poly3DObjects/rhomb_triacont.obj b/share/extensions/Poly3DObjects/rhomb_triacont.obj deleted file mode 100644 index 70acebf54..000000000 --- a/share/extensions/Poly3DObjects/rhomb_triacont.obj +++ /dev/null @@ -1,65 +0,0 @@ -#Name:Rhombic Triacontahedron -#Type:face_specified -v 0. 0. -1.61803 -v 0. 0. 1.61803 -v 0.276393 -0.850651 1.17082 -v 0.276393 0.850651 1.17082 -v 0.894427 0. 1.17082 -v 1.17082 -0.850651 0.723607 -v 1.17082 -0.850651 -0.276393 -v 1.17082 0.850651 0.723607 -v 1.17082 0.850651 -0.276393 -v -0.894427 0. -1.17082 -v -0.447214 -1.37638 0.723607 -v -0.447214 -1.37638 -0.276393 -v -0.447214 1.37638 0.723607 -v -0.447214 1.37638 -0.276393 -v 0.447214 -1.37638 0.276393 -v 0.447214 -1.37638 -0.723607 -v 0.447214 1.37638 0.276393 -v 0.447214 1.37638 -0.723607 -v -1.44721 0. 0.723607 -v -1.44721 0. -0.276393 -v -0.723607 -0.525731 1.17082 -v -0.723607 0.525731 1.17082 -v 0.723607 -0.525731 -1.17082 -v 0.723607 0.525731 -1.17082 -v 1.44721 0. 0.276393 -v 1.44721 0. -0.723607 -v -1.17082 -0.850651 0.276393 -v -1.17082 -0.850651 -0.723607 -v -1.17082 0.850651 0.276393 -v -1.17082 0.850651 -0.723607 -v -0.276393 -0.850651 -1.17082 -v -0.276393 0.850651 -1.17082 - -f 16 15 11 12 -f 14 13 17 18 -f 10 28 20 30 -f 8 5 6 25 -f 12 28 31 16 -f 32 30 14 18 -f 6 3 11 15 -f 8 17 13 4 -f 11 21 19 27 -f 13 29 19 22 -f 7 16 23 26 -f 24 18 9 26 -f 12 11 27 28 -f 30 29 13 14 -f 7 6 15 16 -f 18 17 8 9 -f 2 22 19 21 -f 23 1 24 26 -f 3 2 21 11 -f 4 13 22 2 -f 16 31 1 23 -f 1 32 18 24 -f 31 28 10 1 -f 10 30 32 1 -f 6 5 2 3 -f 8 4 2 5 -f 28 27 19 20 -f 20 19 29 30 -f 26 25 6 7 -f 9 8 25 26 diff --git a/share/extensions/Poly3DObjects/small_rhombicosidodec.obj b/share/extensions/Poly3DObjects/small_rhombicosidodec.obj deleted file mode 100644 index a209ba2c2..000000000 --- a/share/extensions/Poly3DObjects/small_rhombicosidodec.obj +++ /dev/null @@ -1,127 +0,0 @@ -#Name:Small Rhombicosidodecahedron -#Type:face_specified - -v -0.5 -0.5 -2.11803 -v -0.5 -0.5 2.11803 -v -0.5 0.5 -2.11803 -v -0.5 0.5 2.11803 -v -0.5 -2.11803 -0.5 -v -0.5 -2.11803 0.5 -v -0.5 2.11803 -0.5 -v -0.5 2.11803 0.5 -v 0. -1.30902 -1.80902 -v 0. -1.30902 1.80902 -v 0. 1.30902 -1.80902 -v 0. 1.30902 1.80902 -v 0.5 -0.5 -2.11803 -v 0.5 -0.5 2.11803 -v 0.5 0.5 -2.11803 -v 0.5 0.5 2.11803 -v 0.5 -2.11803 -0.5 -v 0.5 -2.11803 0.5 -v 0.5 2.11803 -0.5 -v 0.5 2.11803 0.5 -v -1.80902 0. -1.30902 -v -1.80902 0. 1.30902 -v -0.809017 -1.61803 -1.30902 -v -0.809017 -1.61803 1.30902 -v -0.809017 1.61803 -1.30902 -v -0.809017 1.61803 1.30902 -v -1.61803 -1.30902 -0.809017 -v -1.61803 -1.30902 0.809017 -v -1.61803 1.30902 -0.809017 -v -1.61803 1.30902 0.809017 -v -2.11803 -0.5 -0.5 -v -2.11803 -0.5 0.5 -v -2.11803 0.5 -0.5 -v -2.11803 0.5 0.5 -v -1.30902 -1.80902 0. -v -1.30902 -0.809017 -1.61803 -v -1.30902 -0.809017 1.61803 -v -1.30902 0.809017 -1.61803 -v -1.30902 0.809017 1.61803 -v -1.30902 1.80902 0. -v 0.809017 -1.61803 -1.30902 -v 0.809017 -1.61803 1.30902 -v 0.809017 1.61803 -1.30902 -v 0.809017 1.61803 1.30902 -v 1.61803 -1.30902 -0.809017 -v 1.61803 -1.30902 0.809017 -v 1.61803 1.30902 -0.809017 -v 1.61803 1.30902 0.809017 -v 2.11803 -0.5 -0.5 -v 2.11803 -0.5 0.5 -v 2.11803 0.5 -0.5 -v 2.11803 0.5 0.5 -v 1.30902 -1.80902 0. -v 1.30902 -0.809017 -1.61803 -v 1.30902 -0.809017 1.61803 -v 1.30902 0.809017 -1.61803 -v 1.30902 0.809017 1.61803 -v 1.30902 1.80902 0. -v 1.80902 0. -1.30902 -v 1.80902 0. 1.30902 - -f 36 23 27 -f 37 28 24 -f 40 8 7 -f 35 5 6 -f 38 29 25 -f 39 26 30 -f 10 14 2 -f 9 1 13 -f 12 4 16 -f 11 15 3 -f 54 45 41 -f 55 42 46 -f 58 19 20 -f 53 18 17 -f 56 43 47 -f 57 48 44 -f 34 32 22 -f 33 21 31 -f 59 51 49 -f 60 50 52 -f 27 31 21 36 -f 23 36 1 9 -f 10 2 37 24 -f 37 22 32 28 -f 8 40 30 26 -f 25 29 40 7 -f 35 27 23 5 -f 6 24 28 35 -f 3 38 25 11 -f 21 33 29 38 -f 39 30 34 22 -f 12 26 39 4 -f 55 14 10 42 -f 41 9 13 54 -f 57 44 12 16 -f 15 11 43 56 -f 45 54 59 49 -f 50 60 55 46 -f 48 58 20 44 -f 43 19 58 47 -f 53 17 41 45 -f 46 42 18 53 -f 59 56 47 51 -f 52 48 57 60 -f 31 32 34 33 -f 17 18 6 5 -f 1 3 15 13 -f 14 16 4 2 -f 7 8 20 19 -f 51 52 50 49 -f 3 1 36 21 38 -f 22 37 2 4 39 -f 29 33 34 30 40 -f 27 35 28 32 31 -f 42 10 24 6 18 -f 41 17 5 23 9 -f 20 8 26 12 44 -f 11 25 7 19 43 -f 56 59 54 13 15 -f 57 16 14 55 60 -f 58 48 52 51 47 -f 49 50 46 53 45 - diff --git a/share/extensions/Poly3DObjects/small_rhombicuboct.obj b/share/extensions/Poly3DObjects/small_rhombicuboct.obj deleted file mode 100644 index 2d064aba8..000000000 --- a/share/extensions/Poly3DObjects/small_rhombicuboct.obj +++ /dev/null @@ -1,54 +0,0 @@ -#Name:Small Rhombicuboctahedron -#Type:face_specified - -v -0.5 -0.5 -1.20711 -v -0.5 -0.5 1.20711 -v -0.5 0.5 -1.20711 -v -0.5 0.5 1.20711 -v -0.5 -1.20711 -0.5 -v -0.5 -1.20711 0.5 -v -0.5 1.20711 -0.5 -v -0.5 1.20711 0.5 -v 0.5 -0.5 -1.20711 -v 0.5 -0.5 1.20711 -v 0.5 0.5 -1.20711 -v 0.5 0.5 1.20711 -v 0.5 -1.20711 -0.5 -v 0.5 -1.20711 0.5 -v 0.5 1.20711 -0.5 -v 0.5 1.20711 0.5 -v -1.20711 -0.5 -0.5 -v -1.20711 -0.5 0.5 -v -1.20711 0.5 -0.5 -v -1.20711 0.5 0.5 -v 1.20711 -0.5 -0.5 -v 1.20711 -0.5 0.5 -v 1.20711 0.5 -0.5 -v 1.20711 0.5 0.5 - -f 3 11 9 1 -f 2 10 12 4 -f 24 22 21 23 -f 19 17 18 20 -f 5 13 14 6 -f 8 16 15 7 -f 13 21 22 14 -f 16 24 23 15 -f 6 18 17 5 -f 7 19 20 8 -f 6 14 10 2 -f 4 12 16 8 -f 22 24 12 10 -f 2 4 20 18 -f 1 9 13 5 -f 7 15 11 3 -f 9 11 23 21 -f 17 19 3 1 -f 22 10 14 -f 16 12 24 -f 6 2 18 -f 20 4 8 -f 13 9 21 -f 23 11 15 -f 17 1 5 -f 7 3 19 diff --git a/share/extensions/Poly3DObjects/small_triam_icos.obj b/share/extensions/Poly3DObjects/small_triam_icos.obj deleted file mode 100644 index 1d366ff25..000000000 --- a/share/extensions/Poly3DObjects/small_triam_icos.obj +++ /dev/null @@ -1,95 +0,0 @@ -#Name:Small Triambic Icosahedron -#Type:face_specified -v 0. 0. -0.951057 -v 0. 0. 0.951057 -v 0.262866 -0.809017 0.425325 -v 0.262866 0.809017 0.425325 -v 0.688191 -0.5 -0.425325 -v 0.688191 0.5 -0.425325 -v 0.995959 0. -0.190211 -v -0.688191 -0.5 0.425325 -v -0.688191 0.5 0.425325 -v -0.49798 -0.361803 -0.805748 -v -0.49798 0.361803 -0.805748 -v 0.49798 -0.361803 0.805748 -v 0.49798 0.361803 0.805748 -v 0.190211 -0.58541 -0.805748 -v 0.190211 0.58541 -0.805748 -v 0.850651 0. 0.425325 -v -0.190211 -0.58541 0.805748 -v -0.190211 0.58541 0.805748 -v -0.615537 0. 0.805748 -v -0.307768 -0.947214 0.190211 -v -0.307768 0.947214 0.190211 -v 0.307768 -0.947214 -0.190211 -v 0.307768 0.947214 -0.190211 -v 0.615537 0. -0.805748 -v 0.805748 -0.58541 0.190211 -v 0.805748 0.58541 0.190211 -v -0.850651 0. -0.425325 -v -0.262866 -0.809017 -0.425325 -v -0.262866 0.809017 -0.425325 -v -0.995959 0. 0.190211 -v -0.805748 -0.58541 -0.190211 -v -0.805748 0.58541 -0.190211 - -f 18 2 4 -f 18 4 9 -f 18 9 2 -f 19 2 9 -f 19 9 8 -f 19 8 2 -f 17 2 8 -f 17 8 3 -f 17 3 2 -f 12 2 3 -f 12 3 16 -f 12 16 2 -f 13 2 16 -f 13 16 4 -f 13 4 2 -f 14 5 28 -f 14 28 1 -f 14 1 5 -f 24 6 5 -f 24 5 1 -f 24 1 6 -f 15 29 6 -f 15 6 1 -f 15 1 29 -f 11 27 29 -f 11 29 1 -f 11 1 27 -f 10 28 27 -f 10 27 1 -f 10 1 28 -f 21 4 29 -f 21 29 9 -f 21 9 4 -f 30 9 27 -f 30 27 8 -f 30 8 9 -f 20 8 28 -f 20 28 3 -f 20 3 8 -f 25 3 5 -f 25 5 16 -f 25 16 3 -f 26 16 6 -f 26 6 4 -f 26 4 16 -f 22 5 3 -f 22 3 28 -f 22 28 5 -f 7 6 16 -f 7 16 5 -f 7 5 6 -f 23 29 4 -f 23 4 6 -f 23 6 29 -f 32 27 9 -f 32 9 29 -f 32 29 27 -f 31 28 8 -f 31 8 27 -f 31 27 28 diff --git a/share/extensions/Poly3DObjects/snub_cube.obj b/share/extensions/Poly3DObjects/snub_cube.obj deleted file mode 100644 index de018af23..000000000 --- a/share/extensions/Poly3DObjects/snub_cube.obj +++ /dev/null @@ -1,65 +0,0 @@ -#Name:Snub Cube -#Type:face_specified -v -1.1426135 -0.33775397 -0.62122641 -v -1.1426135 0.33775397 0.62122641 -v -1.1426135 -0.62122641 0.33775397 -v -1.1426135 0.62122641 -0.33775397 -v 1.1426135 -0.33775397 0.62122641 -v 1.1426135 0.33775397 -0.62122641 -v 1.1426135 -0.62122641 -0.33775397 -v 1.1426135 0.62122641 0.33775397 -v -0.33775397 -1.1426135 0.62122641 -v -0.33775397 1.1426135 -0.62122641 -v -0.33775397 -0.62122641 -1.1426135 -v -0.33775397 0.62122641 1.1426135 -v 0.33775397 -1.1426135 -0.62122641 -v 0.33775397 1.1426135 0.62122641 -v 0.33775397 -0.62122641 1.1426135 -v 0.33775397 0.62122641 -1.1426135 -v -0.62122641 -1.1426135 -0.33775397 -v -0.62122641 1.1426135 0.33775397 -v -0.62122641 -0.33775397 1.1426135 -v -0.62122641 0.33775397 -1.1426135 -v 0.62122641 -1.1426135 0.33775397 -v 0.62122641 1.1426135 -0.33775397 -v 0.62122641 -0.33775397 -1.1426135 -v 0.62122641 0.33775397 1.1426135 - -f 3 1 17 -f 3 17 9 -f 3 19 2 -f 3 9 19 -f 1 4 20 -f 1 20 11 -f 1 11 17 -f 2 19 12 -f 2 18 4 -f 2 12 18 -f 4 18 10 -f 4 10 20 -f 17 11 13 -f 19 9 15 -f 18 12 14 -f 20 10 16 -f 9 21 15 -f 11 23 13 -f 12 24 14 -f 10 22 16 -f 13 23 7 -f 13 7 21 -f 15 21 5 -f 15 5 24 -f 16 22 6 -f 16 6 23 -f 14 24 8 -f 14 8 22 -f 21 7 5 -f 23 6 7 -f 24 5 8 -f 22 8 6 -f 1 3 2 4 -f 21 9 17 13 -f 24 12 19 15 -f 10 18 14 22 -f 11 20 16 23 -f 8 5 7 6 diff --git a/share/extensions/Poly3DObjects/snub_dodec.obj b/share/extensions/Poly3DObjects/snub_dodec.obj deleted file mode 100644 index d8309789b..000000000 --- a/share/extensions/Poly3DObjects/snub_dodec.obj +++ /dev/null @@ -1,156 +0,0 @@ -#Name:Snub Dodecahedron -#Type:face_specified - -v -2.0502159 -0.64302961 0.17539263 -v 2.0502159 -0.64302961 -0.17539263 -v -1.6450691 0.64302961 1.2360806 -v 1.6450691 0.64302961 -1.2360806 -v -2.0927544 0.33092102 0.39812710 -v 2.0927544 0.33092102 -0.39812710 -v -1.3329632 1.6469179 -0.39812710 -v 1.3329632 1.6469179 0.39812710 -v -1.8252651 -0.33092102 1.0984232 -v 1.8252651 -0.33092102 -1.0984232 -v -0.62604653 1.7461864 -1.0984232 -v 0.62604653 1.7461864 1.0984232 -v -1.0622158 1.4540242 1.1853886 -v 1.0622158 1.4540242 -1.1853886 -v -1.9321359 0.84755005 -0.44288192 -v 1.9321359 0.84755005 0.44288192 -v -1.1448745 -0.84755005 1.6181953 -v 1.1448745 -0.84755005 -1.6181953 -v -1.5819879 -1.4540242 -0.17539263 -v 1.5819879 -1.4540242 0.17539263 -v -1.0574124 0.37482166 -1.8409298 -v 1.0574124 0.37482166 1.8409298 -v -0.43913786 -0.37482166 -2.0770897 -v 0.43913786 -0.37482166 2.0770897 -v -1.5624104 -1.2495038 0.80327387 -v 1.5624104 -1.2495038 -0.80327387 -v -1.8633072 -0.72833518 -0.80327387 -v 1.8633072 -0.72833518 0.80327387 -v -1.7000678 1.2495038 0.44288192 -v 1.7000678 1.2495038 -0.44288192 -v -0.72811404 -1.6469179 1.1853886 -v 0.72811404 -1.6469179 -1.1853886 -v -0.26565458 -1.7461864 -1.2360806 -v 0.26565458 -1.7461864 1.2360806 -v -0.75979117 -1.9778390 -0.39812710 -v 0.75979117 -1.9778390 0.39812710 -v -1.1992186 -1.4152654 -1.0984232 -v 1.1992186 -1.4152654 1.0984232 -v -1.7903298 0.19289371 -1.1853886 -v 1.7903298 0.19289371 1.1853886 -v -1.3064371 -0.56771537 -1.6181953 -v 1.3064371 -0.56771537 1.6181953 -v -0.85331128 0.72833518 1.8409298 -v 0.85331128 0.72833518 -1.8409298 -v -1.3794145 1.1031568 -1.2360806 -v 1.3794145 1.1031568 1.2360806 -v -0.10503615 0.56771537 -2.0770897 -v 0.10503615 0.56771537 2.0770897 -v -0.46822796 2.0970538 -0.17539263 -v 0.46822796 2.0970538 0.17539263 -v -0.30089684 1.9778390 0.80327387 -v 0.30089684 1.9778390 -0.80327387 -v -0.16156263 1.4152654 1.6181953 -v 0.16156263 1.4152654 -1.6181953 -v -0.54417401 -0.19289371 2.0770897 -v 0.54417401 -0.19289371 -2.0770897 -v -0.23206810 -2.0970538 0.44288192 -v 0.23206810 -2.0970538 -0.44288192 -v -0.20410113 -1.1031568 1.8409298 -v 0.20410113 -1.1031568 -1.8409298 - -f 5 1 9 -f 5 9 3 -f 5 29 15 -f 5 3 29 -f 1 27 19 -f 1 19 25 -f 1 25 9 -f 15 29 7 -f 15 45 39 -f 15 7 45 -f 27 39 41 -f 27 41 37 -f 27 37 19 -f 9 25 17 -f 39 45 21 -f 39 21 41 -f 29 3 13 -f 3 43 13 -f 19 37 35 -f 25 31 17 -f 45 7 11 -f 7 49 11 -f 41 21 23 -f 37 33 35 -f 17 31 59 -f 17 59 55 -f 13 43 53 -f 13 53 51 -f 21 47 23 -f 43 55 48 -f 43 48 53 -f 35 33 58 -f 35 58 57 -f 31 57 34 -f 31 34 59 -f 11 49 52 -f 11 52 54 -f 55 59 24 -f 55 24 48 -f 49 51 50 -f 49 50 52 -f 23 47 56 -f 23 56 60 -f 51 53 12 -f 51 12 50 -f 33 60 32 -f 33 32 58 -f 57 58 36 -f 57 36 34 -f 47 54 44 -f 47 44 56 -f 48 24 22 -f 54 52 14 -f 54 14 44 -f 60 56 18 -f 60 18 32 -f 34 36 38 -f 24 42 22 -f 50 12 8 -f 12 46 8 -f 32 18 26 -f 36 20 38 -f 44 14 4 -f 22 42 40 -f 22 40 46 -f 14 30 4 -f 18 10 26 -f 38 20 28 -f 38 28 42 -f 42 28 40 -f 8 46 16 -f 8 16 30 -f 46 40 16 -f 26 10 2 -f 26 2 20 -f 20 2 28 -f 4 30 6 -f 4 6 10 -f 30 16 6 -f 10 6 2 -f 39 27 1 5 15 -f 3 9 17 55 43 -f 51 49 7 29 13 -f 57 31 25 19 35 -f 47 21 45 11 54 -f 33 37 41 23 60 -f 42 24 59 34 38 -f 46 12 53 48 22 -f 36 58 32 26 20 -f 14 52 50 8 30 -f 44 4 10 18 56 -f 16 40 28 2 6 diff --git a/share/extensions/Poly3DObjects/szilassi.obj b/share/extensions/Poly3DObjects/szilassi.obj deleted file mode 100644 index 9dbce05a6..000000000 --- a/share/extensions/Poly3DObjects/szilassi.obj +++ /dev/null @@ -1,24 +0,0 @@ -#Face:Szilassi Polyhedron -#Type:face_specified -v -4.8 0. 4.8 -v -2.8 -1. 0.8 -v -2.8 0. 0.8 -v -1.8 1. 0.8 -v -1.5 -1.5 -1.2 -v -0.8 2. -3.2 -v 0. -5.04 -4.8 -v 0. 5.04 -4.8 -v 0.8 -2. -3.2 -v 1.5 1.5 -1.2 -v 1.8 -1. 0.8 -v 2.8 0. 0.8 -v 2.8 1. 0.8 -v 4.8 0. 4.8 - -f 4 10 6 1 14 13 -f 3 2 1 6 8 7 -f 5 10 4 3 7 9 -f 10 5 11 12 8 6 -f 12 13 14 9 7 8 -f 11 5 9 14 1 2 -f 13 12 11 2 3 4 diff --git a/share/extensions/Poly3DObjects/tet.obj b/share/extensions/Poly3DObjects/tet.obj deleted file mode 100644 index 3bd8f0ea4..000000000 --- a/share/extensions/Poly3DObjects/tet.obj +++ /dev/null @@ -1,12 +0,0 @@ -#Name:Tetrahedron -#Type:face_specified - -v 0 0 0.61237244 -v -0.28867513 -0.50000000 -0.20412415 -v -0.28867513 0.50000000 -0.20412415 -v 0.57735027 0 -0.20412415 - -f 2 3 4 -f 3 2 1 -f 4 1 2 -f 1 4 3 diff --git a/share/extensions/Poly3DObjects/trunc_cube.obj b/share/extensions/Poly3DObjects/trunc_cube.obj deleted file mode 100644 index 1dbcfa60b..000000000 --- a/share/extensions/Poly3DObjects/trunc_cube.obj +++ /dev/null @@ -1,42 +0,0 @@ -#Name:Truncated Cube -#Type:face_specified - -v -0.5 1.2071068 1.2071068 -v -0.5 1.2071068 -1.2071068 -v -0.5 -1.2071068 1.2071068 -v -0.5 -1.2071068 -1.2071068 -v 0.5 1.2071068 1.2071068 -v 0.5 1.2071068 -1.2071068 -v 0.5 -1.2071068 1.2071068 -v 0.5 -1.2071068 -1.2071068 -v 1.2071068 -0.5 1.2071068 -v 1.2071068 -0.5 -1.2071068 -v 1.2071068 0.5 1.2071068 -v 1.2071068 0.5 -1.2071068 -v 1.2071068 1.2071068 -0.5 -v 1.2071068 1.2071068 0.5 -v 1.2071068 -1.2071068 -0.5 -v 1.2071068 -1.2071068 0.5 -v -1.2071068 -0.5 1.2071068 -v -1.2071068 -0.5 -1.2071068 -v -1.2071068 0.5 1.2071068 -v -1.2071068 0.5 -1.2071068 -v -1.2071068 1.2071068 -0.5 -v -1.2071068 1.2071068 0.5 -v -1.2071068 -1.2071068 -0.5 -v -1.2071068 -1.2071068 0.5 - -f 6 12 10 8 4 18 20 2 -f 1 19 17 3 7 9 11 5 -f 3 24 23 4 8 15 16 7 -f 5 14 13 6 2 21 22 1 -f 9 16 15 10 12 13 14 11 -f 19 22 21 20 18 23 24 17 -f 16 9 7 -f 5 11 14 -f 3 17 24 -f 22 19 1 -f 8 10 15 -f 13 12 6 -f 23 18 4 -f 2 20 21 diff --git a/share/extensions/Poly3DObjects/trunc_dodec.obj b/share/extensions/Poly3DObjects/trunc_dodec.obj deleted file mode 100644 index 9a5743afe..000000000 --- a/share/extensions/Poly3DObjects/trunc_dodec.obj +++ /dev/null @@ -1,96 +0,0 @@ -#Name:Truncated Dodecahedron -#Type:face_specified - -v 0 -1.6180340 2.4898983 -v 0 -1.6180340 -2.4898983 -v 0 1.6180340 2.4898983 -v 0 1.6180340 -2.4898983 -v 0.42532540 -2.9270510 0.26286556 -v 0.42532540 2.9270510 0.26286556 -v 0.68819096 -2.1180340 1.9641672 -v 0.68819096 2.1180340 1.9641672 -v -2.7527638 0 -1.1135164 -v -2.0645729 -2.1180340 0.26286556 -v -2.0645729 2.1180340 0.26286556 -v -1.3763819 -2.6180340 -0.26286556 -v -1.3763819 2.6180340 -0.26286556 -v -0.68819096 -2.1180340 -1.9641672 -v -0.68819096 2.1180340 -1.9641672 -v 1.3763819 -2.6180340 0.26286556 -v 1.3763819 2.6180340 0.26286556 -v 2.7527638 0 1.1135164 -v 1.8017073 -1.3090170 -1.9641672 -v 1.8017073 1.3090170 -1.9641672 -v 2.0645729 -2.1180340 -0.26286556 -v 2.0645729 2.1180340 -0.26286556 -v 2.2270327 0 1.9641672 -v 2.2270327 -1.6180340 -1.1135164 -v 2.2270327 1.6180340 -1.1135164 -v -2.6523581 -1.3090170 0.26286556 -v -2.6523581 1.3090170 0.26286556 -v 2.6523581 -1.3090170 -0.26286556 -v 2.6523581 1.3090170 -0.26286556 -v 2.9152237 -0.5 0.26286556 -v 2.9152237 0.5 0.26286556 -v -2.9152237 -0.5 -0.26286556 -v -2.9152237 0.5 -0.26286556 -v 0.95105652 -1.3090170 2.4898983 -v 0.95105652 -1.3090170 -2.4898983 -v 0.95105652 1.3090170 2.4898983 -v 0.95105652 1.3090170 -2.4898983 -v 0.85065081 -2.6180340 1.1135164 -v 0.85065081 2.6180340 1.1135164 -v -0.95105652 -1.3090170 2.4898983 -v -0.95105652 -1.3090170 -2.4898983 -v -0.95105652 1.3090170 2.4898983 -v -0.95105652 1.3090170 -2.4898983 -v -1.5388418 -0.5 2.4898983 -v -1.5388418 -0.5 -2.4898983 -v -1.5388418 0.5 2.4898983 -v -1.5388418 0.5 -2.4898983 -v 1.5388418 -0.5 2.4898983 -v 1.5388418 -0.5 -2.4898983 -v 1.5388418 0.5 2.4898983 -v 1.5388418 0.5 -2.4898983 -v -2.2270327 0 -1.9641672 -v -2.2270327 -1.6180340 1.1135164 -v -2.2270327 1.6180340 1.1135164 -v -0.85065081 -2.6180340 -1.1135164 -v -0.85065081 2.6180340 -1.1135164 -v -1.8017073 -1.3090170 1.9641672 -v -1.8017073 1.3090170 1.9641672 -v -0.42532540 -2.9270510 -0.26286556 -v -0.42532540 2.9270510 -0.26286556 - -f 3 42 46 44 40 1 34 48 50 36 -f 47 43 4 37 51 49 35 2 41 45 -f 2 35 19 24 21 16 5 59 55 14 -f 49 51 20 25 29 31 30 28 24 19 -f 37 4 15 56 60 6 17 22 25 20 -f 43 47 52 9 33 27 11 13 56 15 -f 45 41 14 55 12 10 26 32 9 52 -f 6 60 13 11 54 58 42 3 8 39 -f 27 33 32 26 53 57 44 46 58 54 -f 10 12 59 5 38 7 1 40 57 53 -f 16 21 28 30 18 23 48 34 7 38 -f 31 29 22 17 39 8 36 50 23 18 -f 9 32 33 -f 18 30 31 -f 47 45 52 -f 50 48 23 -f 10 53 26 -f 27 54 11 -f 21 24 28 -f 29 25 22 -f 40 44 57 -f 58 46 42 -f 35 49 19 -f 20 51 37 -f 12 55 59 -f 60 56 13 -f 41 2 14 -f 15 4 43 -f 34 1 7 -f 8 3 36 -f 38 5 16 -f 17 6 39 diff --git a/share/extensions/Poly3DObjects/trunc_icos.obj b/share/extensions/Poly3DObjects/trunc_icos.obj deleted file mode 100644 index 4b535ba5a..000000000 --- a/share/extensions/Poly3DObjects/trunc_icos.obj +++ /dev/null @@ -1,96 +0,0 @@ -#Name:Truncated Icosahedron -#Type:Face_specified - -v -0.16245985 -2.1180340 1.2759762 -v -0.16245985 2.1180340 1.2759762 -v 0.16245985 -2.1180340 -1.2759762 -v 0.16245985 2.1180340 -1.2759762 -v -0.26286556 -0.80901699 -2.3274384 -v -0.26286556 -2.4270510 -0.42532540 -v -0.26286556 0.80901699 -2.3274384 -v -0.26286556 2.4270510 -0.42532540 -v 0.26286556 -0.80901699 2.3274384 -v 0.26286556 -2.4270510 0.42532540 -v 0.26286556 0.80901699 2.3274384 -v 0.26286556 2.4270510 0.42532540 -v 0.68819096 -0.5 -2.3274384 -v 0.68819096 0.5 -2.3274384 -v 1.2139221 -2.1180340 0.42532540 -v 1.2139221 2.1180340 0.42532540 -v -2.0645729 -0.5 1.2759762 -v -2.0645729 0.5 1.2759762 -v -1.3763819 -1.0 1.8017073 -v -1.3763819 1.0 1.8017073 -v -1.3763819 -1.6180340 -1.2759762 -v -1.3763819 1.6180340 -1.2759762 -v -0.68819096 -0.5 2.3274384 -v -0.68819096 0.5 2.3274384 -v 1.3763819 -1.0 -1.8017073 -v 1.3763819 1.0 -1.8017073 -v 1.3763819 -1.6180340 1.2759762 -v 1.3763819 1.6180340 1.2759762 -v -1.7013016 0 -1.8017073 -v 1.7013016 0 1.8017073 -v -1.2139221 -2.1180340 -0.42532540 -v -1.2139221 2.1180340 -0.42532540 -v -1.9641672 -0.80901699 -1.2759762 -v -1.9641672 0.80901699 -1.2759762 -v 2.0645729 -0.5 -1.2759762 -v 2.0645729 0.5 -1.2759762 -v 2.2270327 -1.0 -0.42532540 -v 2.2270327 1.0 -0.42532540 -v 2.3894926 -0.5 0.42532540 -v 2.3894926 0.5 0.42532540 -v -1.1135164 -1.8090170 1.2759762 -v -1.1135164 1.8090170 1.2759762 -v 1.1135164 -1.8090170 -1.2759762 -v 1.1135164 1.8090170 -1.2759762 -v -2.3894926 -0.5 -0.42532540 -v -2.3894926 0.5 -0.42532540 -v -1.6392475 -1.8090170 0.42532540 -v -1.6392475 1.8090170 0.42532540 -v 1.6392475 -1.8090170 -0.42532540 -v 1.6392475 1.8090170 -0.42532540 -v 1.9641672 -0.80901699 1.2759762 -v 1.9641672 0.80901699 1.2759762 -v 0.85065081 0 2.3274384 -v -2.2270327 -1.0 0.42532540 -v -2.2270327 1.0 0.42532540 -v -0.85065081 0 -2.3274384 -v -0.52573111 -1.6180340 -1.8017073 -v -0.52573111 1.6180340 -1.8017073 -v 0.52573111 -1.6180340 1.8017073 -v 0.52573111 1.6180340 1.8017073 - -f 53 11 24 23 9 -f 51 39 40 52 30 -f 60 28 16 12 2 -f 20 42 48 55 18 -f 19 17 54 47 41 -f 1 10 15 27 59 -f 36 26 44 50 38 -f 4 58 22 32 8 -f 34 29 33 45 46 -f 21 57 3 6 31 -f 37 49 43 25 35 -f 13 5 56 7 14 -f 9 59 27 51 30 53 -f 53 30 52 28 60 11 -f 11 60 2 42 20 24 -f 24 20 18 17 19 23 -f 23 19 41 1 59 9 -f 13 25 43 3 57 5 -f 5 57 21 33 29 56 -f 56 29 34 22 58 7 -f 7 58 4 44 26 14 -f 14 26 36 35 25 13 -f 40 38 50 16 28 52 -f 16 50 44 4 8 12 -f 12 8 32 48 42 2 -f 48 32 22 34 46 55 -f 55 46 45 54 17 18 -f 54 45 33 21 31 47 -f 47 31 6 10 1 41 -f 10 6 3 43 49 15 -f 15 49 37 39 51 27 -f 39 37 35 36 38 40 diff --git a/share/extensions/Poly3DObjects/trunc_oct.obj b/share/extensions/Poly3DObjects/trunc_oct.obj deleted file mode 100644 index 0c7c8ad91..000000000 --- a/share/extensions/Poly3DObjects/trunc_oct.obj +++ /dev/null @@ -1,42 +0,0 @@ -#Name:Truncated Octahedron -#Type:face_specified - -v -1.5 -0.5 0 -v -1.5 0.5 0 -v -1. -1. -0.70710678 -v -1. -1. 0.70710678 -v -1. 1. -0.70710678 -v -1. 1. 0.70710678 -v -0.5 -1.5 0 -v -0.5 -0.5 -1.4142136 -v -0.5 -0.5 1.4142136 -v -0.5 0.5 -1.4142136 -v -0.5 0.5 1.4142136 -v -0.5 1.5 0 -v 0.5 -1.5 0 -v 0.5 -0.5 -1.4142136 -v 0.5 -0.5 1.4142136 -v 0.5 0.5 -1.4142136 -v 0.5 0.5 1.4142136 -v 0.5 1.5 0 -v 1. -1. -0.70710678 -v 1. -1. 0.70710678 -v 1. 1. -0.70710678 -v 1. 1. 0.70710678 -v 1.5 -0.5 0 -v 1.5 0.5 0 - -f 17 11 9 15 -f 14 8 10 16 -f 22 24 21 18 -f 12 5 2 6 -f 13 19 23 20 -f 4 1 3 7 -f 19 13 7 3 8 14 -f 15 9 4 7 13 20 -f 16 10 5 12 18 21 -f 22 18 12 6 11 17 -f 20 23 24 22 17 15 -f 14 16 21 24 23 19 -f 9 11 6 2 1 4 -f 3 1 2 5 10 8
\ No newline at end of file diff --git a/share/extensions/Poly3DObjects/trunc_tet.obj b/share/extensions/Poly3DObjects/trunc_tet.obj deleted file mode 100644 index d2c9cebb1..000000000 --- a/share/extensions/Poly3DObjects/trunc_tet.obj +++ /dev/null @@ -1,24 +0,0 @@ -#Name:Truncated Tetrahedron -#Type:face_specified - -v 0 -1. -0.61237244 -v 0 1. -0.61237244 -v -0.57735027 -1. 0.20412415 -v -0.57735027 1. 0.20412415 -v -0.28867513 -0.5 1.0206207 -v -0.28867513 0.5 1.0206207 -v 0.57735027 0 1.0206207 -v 1.1547005 0 0.20412415 -v -0.86602540 -0.5 -0.61237244 -v -0.86602540 0.5 -0.61237244 -v 0.86602540 -0.5 -0.61237244 -v 0.86602540 0.5 -0.61237244 - -f 11 12 8 -f 3 9 1 -f 2 10 4 -f 6 5 7 -f 11 8 7 5 3 1 -f 2 4 6 7 8 12 -f 9 3 5 6 4 10 -f 2 12 11 1 9 10
\ No newline at end of file diff --git a/share/extensions/README b/share/extensions/README deleted file mode 100644 index 0d6e544e8..000000000 --- a/share/extensions/README +++ /dev/null @@ -1,12 +0,0 @@ -This folder contains Inkscape extensions, i.e. the scripts that -implement some commands that you can use from within Inkscape. Most of -these commands are in the Extensions menu. - -Each *.inx file describes an extension, listing its name, purpose, -prerequisites, location within the menu, etc. These files are read by -Inkscape on launch. Other files are the scripts themselves (Perl, -Python, and Ruby are supported, as well as shell scripts). - -Only include extensions here which are GPL-compatible. This includes -Apache-2, MPL 1.1, certain Creative Commons licenses, and more. See -https://www.gnu.org/licenses/license-list.html for guidance. diff --git a/share/extensions/addnodes.inx b/share/extensions/addnodes.inx deleted file mode 100644 index b61d0a92d..000000000 --- a/share/extensions/addnodes.inx +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Add Nodes</_name> - <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="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> - <effect needs-live-preview="false"> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">addnodes.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/addnodes.py b/share/extensions/addnodes.py deleted file mode 100755 index 4e57f0185..000000000 --- a/share/extensions/addnodes.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python -''' -This extension either adds nodes to a path so that - a) no segment is longer than a maximum value - or - b) so that each segment is divided into a given number of equal segments - -Copyright (C) 2005,2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import cubicsuperpath, simplestyle, copy, math, re, bezmisc - -def numsegs(csp): - return sum([len(p)-1 for p in csp]) -def tpoint((x1,y1), (x2,y2), t = 0.5): - return [x1+t*(x2-x1),y1+t*(y2-y1)] -def cspbezsplit(sp1, sp2, t = 0.5): - m1=tpoint(sp1[1],sp1[2],t) - m2=tpoint(sp1[2],sp2[0],t) - m3=tpoint(sp2[0],sp2[1],t) - m4=tpoint(m1,m2,t) - m5=tpoint(m2,m3,t) - m=tpoint(m4,m5,t) - return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]] -def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001): - bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) - t = bezmisc.beziertatlength(bez, l, tolerance) - return cspbezsplit(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: - lengths.append([]) - for i in xrange(1,len(sp)): - l = cspseglength(sp[i-1],sp[i]) - lengths[-1].append(l) - total += l - return lengths, total -def numlengths(csplen): - retval = 0 - for sp in csplen: - for l in sp: - if l > 0: - retval += 1 - return retval - -class SplitIt(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--segments", - action="store", type="int", - dest="segments", default=2, - help="Number of segments to divide the path into") - self.OptionParser.add_option("--max", - action="store", type="float", - dest="max", default=2, - help="Number of segments to divide the path into") - self.OptionParser.add_option("--method", - action="store", type="string", - dest="method", default='', - help="The kind of division to perform") - - def effect(self): - - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - p = cubicsuperpath.parsePath(node.get('d')) - - #lens, total = csplength(p) - #avg = total/numlengths(lens) - #inkex.debug("average segment length: %s" % avg) - - new = [] - for sub in p: - new.append([sub[0][:]]) - i = 1 - while i <= len(sub)-1: - length = cspseglength(new[-1][-1], sub[i]) - - if self.options.method == 'bynum': - splits = self.options.segments - else: - splits = math.ceil(length/self.options.max) - - for s in xrange(int(splits),1,-1): - new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s) - new[-1].append(next[:]) - new[-1].append(sub[i]) - i+=1 - - node.set('d',cubicsuperpath.formatPath(new)) - -if __name__ == '__main__': - e = SplitIt() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/ai_input.inx b/share/extensions/ai_input.inx deleted file mode 100644 index bc4919500..000000000 --- a/share/extensions/ai_input.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>AI 8.0 Input</_name> - <id>org.inkscape.input.ai8</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.ai</extension> - <mimetype>image/x-adobe-illustrator</mimetype> - <_filetypename>Adobe Illustrator 8.0 and below (UC) (*.ai)</_filetypename> - <_filetypetooltip>Open files saved with Adobe Illustrator 8.0 or - older</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/aisvg.inx b/share/extensions/aisvg.inx deleted file mode 100644 index 929fd4546..000000000 --- a/share/extensions/aisvg.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>AI SVG Input</_name> - <id>org.inkscape.input.aisvg</id> - <input> - <extension>.ai.svg</extension> - <mimetype>text/xml+svg</mimetype> - <_filetypename>Adobe Illustrator SVG (*.ai.svg)</_filetypename> - <_filetypetooltip>Cleans the cruft out of Adobe Illustrator SVGs before opening</_filetypetooltip> - </input> - <xslt> - <file reldir="extensions">aisvg.xslt</file> - </xslt> -</inkscape-extension> diff --git a/share/extensions/aisvg.xslt b/share/extensions/aisvg.xslt deleted file mode 100644 index 2faebc7f3..000000000 --- a/share/extensions/aisvg.xslt +++ /dev/null @@ -1,36 +0,0 @@ -<?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/alphabet_soup/2.svg b/share/extensions/alphabet_soup/2.svg deleted file mode 100644 index d1989397a..000000000 --- a/share/extensions/alphabet_soup/2.svg +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - version="1.0" - width="864" - height="648"> - <path - d="M 354.48922,275.5 C 328.85769,240.23214 347.25731,205.35861 385.1251,189.388 C 426.61805,172.91106 475.68507,179.24583 515.30616,198.41751 C 546.67876,214.6078 576,239.79094 576,278 L 558.40623,278 C 552.10387,234.59412 509.90256,216.75448 470,216.5712 C 447.74393,214.18055 400.44831,233.68796 416.17747,262.5 L 468.03189,324 L 396.02454,324 L 354.48922,275.5 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/3.svg b/share/extensions/alphabet_soup/3.svg deleted file mode 100644 index 3c6d97dda..000000000 --- a/share/extensions/alphabet_soup/3.svg +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - version="1.0" - width="864" - height="648"> - <path - d="M 501.05404,466.85224 C 476.23121,464.26 450.75956,455.65261 431.87769,443.47613 C 411.95632,430.91317 396.56831,411.01358 396.56831,387 C 395.84362,362.80636 412.72694,342.89906 432.21417,330.29284 C 440.0046,325.25324 455.28275,317.82286 461.75,315.92839 C 463.24592,315.49019 464.58333,314.62784 466,313.97757 C 460.54092,310.85142 454.62917,308.18456 449.14094,304.90725 C 430.18578,293.04365 414.6003,275.02312 414.6003,252 C 413.48545,214.23492 454.91385,193.54639 486.5,184.14099 C 495.98819,181.95601 510.61229,180.02198 517.75,180.0082 L 522,180 L 522,198 L 518.7101,198 C 490.39366,199.42169 468,224.07106 468,252 C 467.62164,280.07697 490.67991,304.37293 518.7101,306 C 519.80673,306 520.90337,306 522,306 L 522,323.55734 L 514.90208,324.67499 C 493.1939,327.67962 477.89904,345.53362 471.28084,365.47892 C 467.15061,378.95077 466.81709,395.06873 471.28084,408.52108 C 474.68237,422.00803 482.98703,432.65142 493.36034,441.06884 C 501.39086,447.58519 511.75825,448.93827 522,450.44266 L 522,468 L 515.75,467.86712 C 512.3125,467.79404 505.69932,467.33734 501.05404,466.85224 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/6.svg b/share/extensions/alphabet_soup/6.svg deleted file mode 100644 index d05c5083d..000000000 --- a/share/extensions/alphabet_soup/6.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396.5,342.5 L 396.5,162.5 C 396.5,93.306633 448.26539,42.674512 522,35.765025 L 522,53.526698 C 477.03387,63.188766 469.41841,134.18931 468.29791,173.27138 L 467.70239,194.04275 C 484.49529,185.35766 502.93862,180 522,180 L 522,197.5267 C 475.47262,207.87556 468.5,285.09855 468.5,324 C 468.4888,363.50529 475.41445,439.42379 522,450.4733 L 522,459.23665 L 522,468 C 448.80371,465.88421 396.5,413.20428 396.5,342.5 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/7.svg b/share/extensions/alphabet_soup/7.svg deleted file mode 100644 index e921bb5ff..000000000 --- a/share/extensions/alphabet_soup/7.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 389.34645,312.75 C 348.64746,255.09556 327.02961,192.99032 323.47153,123.5 C 321.51456,95.318458 329.46832,77.247033 360,72.504642 C 388.88058,72.729583 395.35983,93.02294 395.61308,118 C 395.02551,188.7017 421.08456,252.40074 459.21132,311.25733 C 462.22246,315.46393 465.41066,319.55695 468.07037,324 L 397.28797,324 L 389.34645,312.75 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Cblob.svg b/share/extensions/alphabet_soup/Cblob.svg deleted file mode 100644 index b5b104edb..000000000 --- a/share/extensions/alphabet_soup/Cblob.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 432,432 c 51.35068,0.0519 82.50621,-17.08791 115.74987,-54.56643 6.11036,-10.44205 6.1546,-10.95161 1.35156,-15.5668 -6.47094,-6.21786 -8.55507,-11.05768 -8.55507,-19.86677 -0.0541,-15.68008 11.45913,-25.65125 26.45364,-26.45364 23.16466,0.63832 28.48079,19.03525 26.06817,38.86707 C 571.0029,436.23549 512.75953,467.88531 432,468 l 0,-36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Chook.svg b/share/extensions/alphabet_soup/Chook.svg deleted file mode 100644 index 2e3cf99cd..000000000 --- a/share/extensions/alphabet_soup/Chook.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 432,36 0,-36 c 35.12642,0.15801183 68.19031,10.978322 99,27.408775 5.225,3.184493 11.17901,6.028377 13.23113,6.319744 C 551.95635,34.825369 558,29.837576 558,22.365141 L 558,18 l 18,0 0,108 -17.72381,0 C 553.02167,64.41188 486.96487,36 432,36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Ctail.svg b/share/extensions/alphabet_soup/Ctail.svg deleted file mode 100644 index 54d55dec1..000000000 --- a/share/extensions/alphabet_soup/Ctail.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 432,432 C 488.00932,432.67049 552.04586,402.81177 558.27619,342 L 594,342 C 592.58099,426.9715 505.82574,463.87984 432,468.29351 L 432,432 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Delta.svg b/share/extensions/alphabet_soup/Delta.svg deleted file mode 100644 index 82e60c34f..000000000 --- a/share/extensions/alphabet_soup/Delta.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 312,36 L 306,36 L 306,18 L 270,18 L 270,33 L 257.02684,33 C 254.86698,25.169754 250.63249,18.043924 242.5,18.043924 L 234,18 L 234,0 L 630,0 L 630,18 L 625.5651,18 C 615.63677,17.396793 609.71136,24.314484 606.8449,33 L 594,33 L 594,18 L 522,18 L 522,36 L 516,36 L 516,48 L 513,48 L 513,41.272727 L 507.72727,36 L 320.84615,36 L 315,41.846154 L 315,48 L 312,48 L 312,36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Eb.svg b/share/extensions/alphabet_soup/Eb.svg deleted file mode 100644 index 490671b62..000000000 --- a/share/extensions/alphabet_soup/Eb.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 234,450.23743 C 243.83007,450.1558 251.21138,441.4123 252,432 l 180,0 0,36 -198,0 0,-17.76257 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Eserif.svg b/share/extensions/alphabet_soup/Eserif.svg deleted file mode 100644 index 51e46b90e..000000000 --- a/share/extensions/alphabet_soup/Eserif.svg +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648" - id="svg3291"> - <defs - id="defs3294" /> - <path - d="M 442.75,252.02196 L 432,252 L 432,216.15894 L 444.9307,215.82947 C 458.70874,216.8737 466.45417,211.48843 468.26334,198 L 486,198 L 486,270 L 468.41481,270 C 465.95779,255.6718 456.18131,252.74723 442.75,252.02196 z" - id="path3300" - style="fill:#000000" /> -</svg> diff --git a/share/extensions/alphabet_soup/Et.svg b/share/extensions/alphabet_soup/Et.svg deleted file mode 100644 index 49a3a5f34..000000000 --- a/share/extensions/alphabet_soup/Et.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 234,17.58519 234,0 432,0 432,36 252,36 C 251.9603,23.895333 246.34816,17.721488 234,17.58519 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/G.svg b/share/extensions/alphabet_soup/G.svg deleted file mode 100644 index f7cd3cc0d..000000000 --- a/share/extensions/alphabet_soup/G.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 432,432 c 40.73753,0.0266 88.26593,-36.02956 89.0448,-77.37997 l 0,-48.62003 C 520.74967,296.51193 512.02142,287.43179 504,287.58519 L 504,270 l 108,0 0,17.58519 C 603.54056,287.1223 595.2197,296.35671 595.89633,306 l 0,91.21641 C 557.61928,448.03031 481.8354,468.10728 432,468 l 0,-36 z" /> -</svg> diff --git a/share/extensions/alphabet_soup/IBSerif.svg b/share/extensions/alphabet_soup/IBSerif.svg deleted file mode 100644 index dfb69877f..000000000 --- a/share/extensions/alphabet_soup/IBSerif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 234,450.41481 c 10.36553,-0.16751 18.17938,-8.842 18,-18.41481 l 90,0 c 0.30635,10.08784 8.28835,17.76285 18,18 l 0,18 -126,0 0,-17.58519 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/ITSerif.svg b/share/extensions/alphabet_soup/ITSerif.svg deleted file mode 100644 index 492aff59d..000000000 --- a/share/extensions/alphabet_soup/ITSerif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 216,18 0,-18 126,0 0,18 c -9.949,0.167507 -17.90169,8.010662 -18,18 l -90,0 C 233.69365,25.703901 225.43397,18.167722 216,18 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Lb.svg b/share/extensions/alphabet_soup/Lb.svg deleted file mode 100644 index 3fa9f9784..000000000 --- a/share/extensions/alphabet_soup/Lb.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 432,432 117,0 c 14.59492,-0.0666 26.75442,-13.39796 27,-27 l 0,-9 18,0 0,72 -162,0 0,-36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Lt.svg b/share/extensions/alphabet_soup/Lt.svg deleted file mode 100644 index 1f4c18f39..000000000 --- a/share/extensions/alphabet_soup/Lt.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 576,61.467881 C 575.8351,48.463709 564.09019,35.953164 549,36 l -117,0 0,-36 162,0 0,72 -18,0 0,-10.532119 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Ocross.svg b/share/extensions/alphabet_soup/Ocross.svg deleted file mode 100644 index 63b1caafa..000000000 --- a/share/extensions/alphabet_soup/Ocross.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 324,216 L 432,216 L 432,252 L 324,252 L 324,216 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Oterm.svg b/share/extensions/alphabet_soup/Oterm.svg deleted file mode 100644 index e167a57ac..000000000 --- a/share/extensions/alphabet_soup/Oterm.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 432,432.28491 C 520.9663,433.84056 539.41817,304.57049 539.90939,235.96367 540.40061,167.35685 519.19629,35.736893 432,35.715087 L 432,0 C 560.70357,0.52071898 630.31496,121.84151 629.90669,235.8117 629.49842,349.78189 555.79773,468 432,468 l 0,-35.71509 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/P.svg b/share/extensions/alphabet_soup/P.svg deleted file mode 100644 index 034408272..000000000 --- a/share/extensions/alphabet_soup/P.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 432,216 c 47.35472,-0.50816 70.54401,-48.78939 71.44374,-90 C 504.34347,84.789389 477.64109,36 432,36 432,24.235496 432,11.764504 432,0 503.94288,0.16988052 593.35821,43.100441 593.33321,126.5 593.30821,209.89956 504.23622,251.96228 432,252 c 0,-12.09784 0,-23.90216 0,-36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Q.svg b/share/extensions/alphabet_soup/Q.svg deleted file mode 100644 index c60ea4230..000000000 --- a/share/extensions/alphabet_soup/Q.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 526.32135,439.9524 C 498.13523,459.02351 460.91524,468.33538 432,468 c 0.0271,-12.10181 -0.0369,-23.89822 0,-36 C 505.94261,431.996 539.38316,302.46313 539.38316,234 539.38316,165.53687 513.54685,35.82655 432,36 l 0,-36 c 120.87878,0.32641387 196.43844,118.49285 197.44733,234 0.57378,65.69198 -23.16612,128.36397 -67.46294,176.7975 C 578.58768,433.83295 602.18706,446.20739 630,450 l 0,18 c -37.05949,1.08844 -70.95355,-12.44439 -103.67865,-28.0476 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Rblock.svg b/share/extensions/alphabet_soup/Rblock.svg deleted file mode 100644 index a2f4e9d70..000000000 --- a/share/extensions/alphabet_soup/Rblock.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 504,252 L 432,252 L 432,216 L 612,216 L 612,233.58519 C 604.95991,234.94718 599.47776,238.02235 595.89633,244.4214 L 594,432 L 504,432 L 504,252 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Tb.svg b/share/extensions/alphabet_soup/Tb.svg deleted file mode 100644 index 2a75ac5b4..000000000 --- a/share/extensions/alphabet_soup/Tb.svg +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648" - id="svg3065"> - <defs - id="defs3068" /> - <path - d="M 108,396 L 126,396 L 126.02196,406.75 C 125.07553,420.73151 130.7333,430.53865 144.52406,431.29389 L 445.96524,431.29389 C 463.34999,431.83879 467.23245,423.88343 467.97804,406.75 L 468,396 L 486,396 L 486,468 L 108,468 L 108,396 z" - id="path3074" - style="fill:#000000" /> -</svg> diff --git a/share/extensions/alphabet_soup/Tt.svg b/share/extensions/alphabet_soup/Tt.svg deleted file mode 100644 index 04d2a1829..000000000 --- a/share/extensions/alphabet_soup/Tt.svg +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648" - id="svg3153"> - <defs - id="defs3156" /> - <path - d="M 108,0 L 486,0 L 486,72 L 468,72 L 467.97804,61.25 C 468.91706,47.366193 463.32904,37.374009 449.58384,36.611397 L 146.90384,36.611397 C 130.1191,36.264077 126.71932,45.224839 126.02196,61.25 L 126,72 L 108,72 L 108,0 z" - id="path3162" - style="fill:#000000" /> -</svg> diff --git a/share/extensions/alphabet_soup/U.svg b/share/extensions/alphabet_soup/U.svg deleted file mode 100644 index e8b8244c3..000000000 --- a/share/extensions/alphabet_soup/U.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 234.2538,221.55362 C 238.26909,109.31485 312.74266,6.5178358 432,-0.30557714 L 432,36 C 356.62772,39.243159 327.51759,150.96639 324.28264,213.63018 L 323.88378,432 L 233.91947,432 C 234.742,361.8557 233.64814,291.69659 234.2538,221.55362 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Vser.svg b/share/extensions/alphabet_soup/Vser.svg deleted file mode 100644 index a06b247d4..000000000 --- a/share/extensions/alphabet_soup/Vser.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 234,18 0,-18 94,0 0,18 -6.57692,0 c -5.94588,-0.462067 -11.16407,6.690532 -8.71399,14 L 309,32 l -3,0 0,-14 -36,0 0.43636,14 -15.80952,0 C 251.35659,20.992194 245.07284,18.057219 234,18 z m 360,0 -72,0 0,14 -2.86353,0 c -0.0921,-0.480406 -3.84556,0.500695 -3.84556,-0.218182 C 517.61482,24.518889 512.35553,18.083131 506.36364,18 L 499,18 l 0,-18 131,0 0,18 -4.4349,0 c -8.8741,-0.217422 -13.97429,5.278338 -16.21086,14 L 594,32 594,18 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Xh.svg b/share/extensions/alphabet_soup/Xh.svg deleted file mode 100644 index c60f3048f..000000000 --- a/share/extensions/alphabet_soup/Xh.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 432,0 L 594,0 L 594,36 L 432,36 L 432,0 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Xne.svg b/share/extensions/alphabet_soup/Xne.svg deleted file mode 100644 index 9dc54f19d..000000000 --- a/share/extensions/alphabet_soup/Xne.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 395.39741,251.53432 L 575.49466,0 L 630,0 L 630,18 L 623.65728,18 C 619.03208,17.930759 614.47611,18.564007 611.50395,22.236834 L 415.8113,289.94104 L 395.39741,251.53432 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Xnw.svg b/share/extensions/alphabet_soup/Xnw.svg deleted file mode 100644 index 98cd8bc1f..000000000 --- a/share/extensions/alphabet_soup/Xnw.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 258.12827,29.840962 C 253.41405,22.06427 248.80253,18 239.78811,18 L 234,18 L 234,-0.017224956 L 342.39639,0.5 L 469.79391,214.60701 L 415.80338,289.94584 L 258.12827,29.840962 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Xvb.svg b/share/extensions/alphabet_soup/Xvb.svg deleted file mode 100644 index 16e80b42c..000000000 --- a/share/extensions/alphabet_soup/Xvb.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 252,429.20461 L 252,234 L 342,234 L 342,360 L 324,360 L 324,414 L 288,414 L 288,450 L 237.5,449.95608 C 247.55043,446.50275 251.36734,439.32286 252,429.20461 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/Xvt.svg b/share/extensions/alphabet_soup/Xvt.svg deleted file mode 100644 index 3a5c5dcb9..000000000 --- a/share/extensions/alphabet_soup/Xvt.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 252,36 c 0.29636,-9.768721 -7.64197,-18.037114 -18,-18 l 108,0 0,216 -90,0 0,-198 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/a.svg b/share/extensions/alphabet_soup/a.svg deleted file mode 100644 index 284de78ea..000000000 --- a/share/extensions/alphabet_soup/a.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 468,306 L 498.2899,306 C 538.44742,306 573.0077,295.57591 575.93995,251.64459 C 575.7071,228.53229 560.49601,206.14824 534.5399,199.52162 C 530.43899,198.30967 526.23826,198 522,198 L 522,180 C 528.87688,179.85504 535.7342,180.44311 542.57632,181.06622 C 581.12986,186.50294 646.26955,202.54828 647.49865,251.92825 C 645.69329,302.14545 581.63206,316.22267 542.57632,322.93378 C 536.5683,323.5202 517.3308,324 499.82632,324 L 468,324 L 468,306 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/abase.svg b/share/extensions/alphabet_soup/abase.svg deleted file mode 100644 index 1da2bb1d7..000000000 --- a/share/extensions/alphabet_soup/abase.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 396,271.5 c 0.33614,-72.76543 62.75438,-91.16949 126,-91.5 l 0,18 c -33.67997,-0.42526 -54,38.9573 -54,66.557 l 0,131.443 -72,0 0,-124.5 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/acap.svg b/share/extensions/alphabet_soup/acap.svg deleted file mode 100644 index dfc7ede1b..000000000 --- a/share/extensions/alphabet_soup/acap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 322,160 L 506,160 L 506,200 L 322,200 L 322,160 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/b.svg b/share/extensions/alphabet_soup/b.svg deleted file mode 100644 index fd01a263b..000000000 --- a/share/extensions/alphabet_soup/b.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,180 L 468,180 L 468,191.90142 C 484.59512,182.33029 503.29608,180.63132 522,179.70572 L 522,197.64142 C 491.45484,201.06591 472.13382,222.38085 467.64142,252 L 396,252 L 396,180 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/bar.svg b/share/extensions/alphabet_soup/bar.svg deleted file mode 100644 index 8b477e378..000000000 --- a/share/extensions/alphabet_soup/bar.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,252 L 468,252 L 468,396 L 396,396 L 396,252 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/bar2.svg b/share/extensions/alphabet_soup/bar2.svg deleted file mode 100644 index 39ed825ae..000000000 --- a/share/extensions/alphabet_soup/bar2.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,252 L 468,252 L 468,414 L 396,414 L 396,252 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/barcap.svg b/share/extensions/alphabet_soup/barcap.svg deleted file mode 100644 index 5831e83ed..000000000 --- a/share/extensions/alphabet_soup/barcap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 252,36 90,0 0,396 -90,0 0,-396 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/c.svg b/share/extensions/alphabet_soup/c.svg deleted file mode 100644 index c6261a0e5..000000000 --- a/share/extensions/alphabet_soup/c.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 522,450.28755 C 524.6521,450.06637 527.3042,449.8452 529.9563,449.62402 C 553.24409,447.68189 577.42489,434.76058 591.92978,416.50771 C 598.87621,407.76635 605.88482,394.3104 608.47094,384.75 L 610.29684,378 L 627.75096,377.95348 C 624.09745,394.97614 617.77483,410.68918 608.08707,425.0933 C 589.83064,449.11135 560.59369,465.14357 530.61383,467.57612 C 527.74255,467.80909 524.87128,468.04207 522,468.27504 L 522,450.28755 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/cross.svg b/share/extensions/alphabet_soup/cross.svg deleted file mode 100644 index 89b67fefe..000000000 --- a/share/extensions/alphabet_soup/cross.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,198 L 378,198 L 378,180 L 504,180 L 504,198 L 468,198 L 468,252 L 396,252 L 396,198 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/cserif.svg b/share/extensions/alphabet_soup/cserif.svg deleted file mode 100644 index 14669a0ad..000000000 --- a/share/extensions/alphabet_soup/cserif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 522,450.27586 C 577.04846,446.35647 605.97828,412.81324 612.30948,360 L 630,360 L 630,450 L 612.22709,450 C 611.45458,444.02962 610.39687,437.37255 604.52088,434.41588 C 601.84003,433.74303 601.94975,433.67255 589.52556,444.049 C 570.2855,460.25388 546.48114,466.37309 522,468.29505 L 522,450.27586 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/e.svg b/share/extensions/alphabet_soup/e.svg deleted file mode 100644 index 03106dd97..000000000 --- a/share/extensions/alphabet_soup/e.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 468,306 L 575.5984,306 C 571.81773,269.10345 564.72169,207.65975 522,197.5267 L 522,180 C 602.29926,181.10794 643.28869,251.19261 648.28591,324 L 468,324 L 468,306 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/epsilon.svg b/share/extensions/alphabet_soup/epsilon.svg deleted file mode 100644 index a2dd33e60..000000000 --- a/share/extensions/alphabet_soup/epsilon.svg +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> -</svg> diff --git a/share/extensions/alphabet_soup/f.svg b/share/extensions/alphabet_soup/f.svg deleted file mode 100644 index c0f94c3ed..000000000 --- a/share/extensions/alphabet_soup/f.svg +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648" - id="svg3379"> - <defs - id="defs3382" /> - <path - d="M 396,108 L 468,108 L 468,180 L 396,180 L 396,108 z" - id="path3388" - style="fill:#000000" /> -</svg> diff --git a/share/extensions/alphabet_soup/gamma.svg b/share/extensions/alphabet_soup/gamma.svg deleted file mode 100644 index feb6b366d..000000000 --- a/share/extensions/alphabet_soup/gamma.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 413.74236,645.64547 C 383.0319,635.17985 363.9313,598.29804 370.41198,561.97779 372.2609,551.61571 374.419,546.6985 395.41883,505 l 18.3818,-37 36.39874,0 18.3818,37 c 20.99983,41.6985 23.15793,46.61571 25.00685,56.97779 5.44246,30.50163 -6.58165,61.17182 -30.16644,76.94629 -14.36564,9.56051 -33.1973,11.79876 -49.67922,6.72139 z M 441.26639,611.4249 C 453.76562,607.16598 466.11947,585.75784 461.95112,567 460.95667,562.52492 433.16738,505 432,505 c -1.16738,0 -28.95667,57.52492 -29.95112,62 -3.22119,14.49556 1.38417,29.9298 11.61874,38.93863 7.65072,6.73443 15.09954,9.74518 27.59877,5.48627 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/h.svg b/share/extensions/alphabet_soup/h.svg deleted file mode 100644 index 23be3806f..000000000 --- a/share/extensions/alphabet_soup/h.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 575.2219,287.78922 C 575.1595,253.50817 561.4074,197.88262 522,197.72815 l 0,-17.99396 c 68.28223,0.0831 125.45445,25.34454 125.45445,91.76581 l 0.63064,124.5 -71.94737,0 -0.91582,-108.21078 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/h2.svg b/share/extensions/alphabet_soup/h2.svg deleted file mode 100644 index 636b4dfd4..000000000 --- a/share/extensions/alphabet_soup/h2.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 522,197.72815 L 522,179.73419 C 590.28223,178.93273 647.45445,202.45781 647.45445,271.5 L 648.08509,396 L 576.13772,396 L 576.48224,300.74674 C 575.32181,264.18339 567.07556,203.90649 522,197.72815 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/hcap.svg b/share/extensions/alphabet_soup/hcap.svg deleted file mode 100644 index a6048b667..000000000 --- a/share/extensions/alphabet_soup/hcap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 342,216 90,0 0,36 -90,0 0,-36 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/idot.svg b/share/extensions/alphabet_soup/idot.svg deleted file mode 100644 index d3d0dadb0..000000000 --- a/share/extensions/alphabet_soup/idot.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396.4094,107.43029 C 396.42229,88.427407 412.3363,72.550017 432.21078,72.501168 C 452.18507,72.452074 467.66287,88.422867 467.69183,107.97927 C 467.72094,127.63549 452.65182,143.43658 432.00005,143.53592 C 411.24846,143.63574 396.39651,126.4335 396.4094,107.43029 z" /> -</svg> diff --git a/share/extensions/alphabet_soup/j.svg b/share/extensions/alphabet_soup/j.svg deleted file mode 100644 index 07c680519..000000000 --- a/share/extensions/alphabet_soup/j.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 522,0 0,18 c -40.93265,-0.04875 -53.96001,54.416193 -54,90 l -72,0 C 396.21762,44.123031 460.42158,0.17295425 522,0 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/k.svg b/share/extensions/alphabet_soup/k.svg deleted file mode 100644 index 314f2b0b9..000000000 --- a/share/extensions/alphabet_soup/k.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 468,359.49318 L 468,342.53957 L 584,207.36758 C 583.19563,203.56902 580.27236,200.82404 577.79282,198 L 558,198 L 558,180 L 648,180 L 648,198 C 640.42767,197.67211 633.17994,198.29561 626.83386,202.78843 L 522.1552,323.78851 C 564.42919,364.26962 603.76044,407.93742 647.06955,447.34097 C 652.84594,450.23664 659.67138,449.89061 666,450.25697 L 666,468 L 576.49312,468 L 468,359.49318 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/l.svg b/share/extensions/alphabet_soup/l.svg deleted file mode 100644 index 00beccf9f..000000000 --- a/share/extensions/alphabet_soup/l.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,108 L 468,108 L 468,252 L 396,252 L 396,108 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/lserif.svg b/share/extensions/alphabet_soup/lserif.svg deleted file mode 100644 index 7ab2c0ded..000000000 --- a/share/extensions/alphabet_soup/lserif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 377.93068,432.20912 0,-17.77577 C 387.72752,413.90818 396.04182,405.2313 396,396 l 72,0 0,71.95278 -90.06932,-35.74366 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/m.svg b/share/extensions/alphabet_soup/m.svg deleted file mode 100644 index ce3cd05ca..000000000 --- a/share/extensions/alphabet_soup/m.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 576.13772,280.98105 C 576.87501,248.84942 559.52731,198.85849 522,197.72815 L 522,180 c 43.19741,0.40036 82.08134,12.77489 108.21232,47.91572 C 647.33056,203.82949 664.91637,180.11613 702,180 l 0,17.74234 c -31.68499,-0.0754 -53.93869,48.95303 -54,84.95053 L 648,396 l -71.86228,0 0,-115.01895 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/mcap.svg b/share/extensions/alphabet_soup/mcap.svg deleted file mode 100644 index 25c8c8a5c..000000000 --- a/share/extensions/alphabet_soup/mcap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 198,36 C 197.9768,27.008298 190.09906,18 180,18 L 180,0 302.81899,0 308.4585,18.042372 288,18.042 288,432 l -90,0 0,-396 z m 378,20 -20,0 0,-38 -36,0 L 525.63278,0 686,0 l 0,18 c -9.03999,-0.625908 -20.60333,7.51861 -20,18 l 0,396 -90,0 0,-376 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/n.svg b/share/extensions/alphabet_soup/n.svg deleted file mode 100644 index 420042a19..000000000 --- a/share/extensions/alphabet_soup/n.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396,217.21055 C 395.97058,205.94989 388.09247,200.51206 378,197.58519 L 378,180 L 468,180 L 468,191.90142 C 484.59512,182.33029 503.29608,180.63132 522,179.70572 L 522,197.64142 C 491.44636,201.07259 472.13525,222.37147 467.64142,252 L 396,252 L 396,217.21055 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/o.svg b/share/extensions/alphabet_soup/o.svg deleted file mode 100644 index 3c08f073b..000000000 --- a/share/extensions/alphabet_soup/o.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 396.40448,322.99577 C 395.61641,252.63556 448.00479,180 522,180 l 0,17.5267 c -37.73872,0.42783 -53.59673,85.8386 -53.5,126.4733 0.0967,40.6347 16.33088,126.80441 53.5,126.4733 L 522,468 C 445.49339,467.3577 397.19254,393.35597 396.40448,322.99577 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/ocap.svg b/share/extensions/alphabet_soup/ocap.svg deleted file mode 100644 index 1c50fd223..000000000 --- a/share/extensions/alphabet_soup/ocap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 232,234 C 231.43948,112.8671 300.98118,0 432,0 l 0,36 C 347.8511,35.970211 328.00004,169.86413 327.43561,234 326.87118,298.13587 354.5529,432 432,432 l 0,36 C 302.64047,467.72235 232.56052,355.1329 232,234 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/question.svg b/share/extensions/alphabet_soup/question.svg deleted file mode 100644 index ddecb15b0..000000000 --- a/share/extensions/alphabet_soup/question.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 379.1115,243.87415 C 331.66919,220.96836 304.53108,179.04281 304,126 303.46892,72.957187 335.24929,25.47568 385.13135,5.8274636 400.20766,-0.11099414 416.03391,-0.18850556 432.68,0 l 0,18 c -44.57249,0.07686 -51.34382,66.045556 -51.15555,108 0.18827,41.95444 8.49951,103.93178 65.3394,105.99421 8.86675,0.32173 10.93679,0.32781 14.34805,2.24504 C 468.73163,238.58122 468,244.15478 468,252 l -72,0 c -2.91874,-5.25257 -11.7046,-5.62299 -16.8885,-8.12585 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/r.svg b/share/extensions/alphabet_soup/r.svg deleted file mode 100644 index bb2273a0a..000000000 --- a/share/extensions/alphabet_soup/r.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 592.99353,251.12139 C 575.14192,244.35645 572.91506,227.77213 582.80984,213.1914 C 563.81023,203.88337 543.23105,198.02637 522,198 L 522,179.7048 C 555.52946,180.64247 588.14157,191.68258 613.84732,213.34814 C 622.68687,220.79837 622.73967,235.92625 614.63303,244.84732 C 609.95629,249.9939 599.04087,253.41305 592.99353,251.12139 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/rcap.svg b/share/extensions/alphabet_soup/rcap.svg deleted file mode 100644 index e835f5068..000000000 --- a/share/extensions/alphabet_soup/rcap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 499.24145,321.47832 C 491.28205,288.08485 468.98548,252 432,252 l 0,-36 c 79.22032,0.18906 162.09041,61.50434 162,124 l 0,92 -90,0 c 10e-4,-37.17134 1.98901,-73.69026 -4.75855,-110.52168 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/s.svg b/share/extensions/alphabet_soup/s.svg deleted file mode 100644 index dc7c6fc16..000000000 --- a/share/extensions/alphabet_soup/s.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 522,450 C 547.86042,450.23399 575.18402,432.48473 575.5,405 C 575.83952,374.49118 546.90062,362.54174 520.5,360.00916 C 467.65402,359.84026 420.037,334.76552 402.52136,297.88256 C 380.20717,218.58166 454.09823,180.1172 522,180 L 522,198 C 496.13958,197.76601 468.81598,215.51527 468.5,243 C 468.16048,273.50882 497.09938,285.45826 523.5,287.99084 C 576.34598,288.15974 623.963,313.23448 641.47864,350.11744 C 663.79283,429.41835 589.90178,467.88278 522,468 L 522,450 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/serif.svg b/share/extensions/alphabet_soup/serif.svg deleted file mode 100644 index d2bf55e0a..000000000 --- a/share/extensions/alphabet_soup/serif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 378,450.41481 C 385.04009,449.05282 390.71188,446.07357 394.10367,439.5786 C 395.89343,436.15137 395.95907,432.81034 395.97804,415.75 L 396,396 L 468,396 L 468.02196,415.75 C 468.04093,432.81034 468.35354,436.03025 469.89633,439.5786 C 472.90125,446.4898 479.36545,448.64033 486,450.41481 L 486,468 L 378,468 L 378,450.41481 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/t.svg b/share/extensions/alphabet_soup/t.svg deleted file mode 100644 index 7940a68e2..000000000 --- a/share/extensions/alphabet_soup/t.svg +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648" - id="svg3021"> - <defs - id="defs3024" /> - <path - d="M 396,144.00541 L 468,107.99459 L 468,180 L 396,180 L 396,144.00541 z" - id="path3030" - style="fill:#000000" /> -</svg> diff --git a/share/extensions/alphabet_soup/tserif.svg b/share/extensions/alphabet_soup/tserif.svg deleted file mode 100644 index f04cfcf60..000000000 --- a/share/extensions/alphabet_soup/tserif.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 396,396 72,0 c -0.003,12.59674 10.03593,35.45141 28.28288,35.8016 C 507.19866,431.37331 510.32553,421.46179 516.756,415 L 532,427.78714 c -9.31588,24.90944 -37.02355,39.3497 -61.66612,40.25162 C 425.31789,469.68634 396.13284,433.43678 396,396 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/v.svg b/share/extensions/alphabet_soup/v.svg deleted file mode 100644 index 917580771..000000000 --- a/share/extensions/alphabet_soup/v.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 324,288.0044 L 324.11177,216.5 L 413.99956,395 L 522.04609,179.90536 L 540,216.07787 L 540,288.0044 L 449.9978,468 L 414.0022,468 L 324,288.0044 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/vcap.svg b/share/extensions/alphabet_soup/vcap.svg deleted file mode 100644 index 792989e4c..000000000 --- a/share/extensions/alphabet_soup/vcap.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="m 250,18 58.5,0 105.5,326 106,-326 94,0 -143.5,450 -77,0 L 250,18 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/vserl.svg b/share/extensions/alphabet_soup/vserl.svg deleted file mode 100644 index 10e32d355..000000000 --- a/share/extensions/alphabet_soup/vserl.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 286.04853,213.28223 C 281.1125,203.56679 275.32901,198.99797 264.3185,198 l -3.3185,0 0,-18 81,0 0,18 -7.57692,0 c -7.04116,0 -7.75193,0.23896 -10.5,2.92308 -5.21608,5.09469 -2.20175,11.07828 0.23324,15.75315 l -0.10939,71.39718 -37.9984,-74.79118 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/vserr.svg b/share/extensions/alphabet_soup/vserr.svg deleted file mode 100644 index 964ae97a8..000000000 --- a/share/extensions/alphabet_soup/vserr.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 522,211 L 508,211 C 509.16261,197.0674 496.43802,198 486,198 L 486,180 L 603,180 L 603,197.72222 C 593.98444,198.08146 586.01933,199.57834 580.98041,207.54755 L 539.95908,288 L 522,288 L 522,211 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/x.svg b/share/extensions/alphabet_soup/x.svg deleted file mode 100644 index f40b0a9fb..000000000 --- a/share/extensions/alphabet_soup/x.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 299.40862,211.63998 C 290.61894,201.41815 282.83995,198 270,198 L 270,180 L 378,180 L 378,198 C 369.69256,197.41657 364.67798,201.39745 370.12904,208.69118 L 443.32874,295.21127 L 528.37629,208.62443 C 533.96348,202.2222 528.37929,198 522,198 L 522,180 L 594,180 L 594,197.73699 C 587.7236,198.11755 580.04945,196.29498 575.5,200.77484 L 459.90086,314.60579 L 468.16997,324 L 396.02616,324 L 299.40862,211.63998 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/y.svg b/share/extensions/alphabet_soup/y.svg deleted file mode 100644 index 089cec9c8..000000000 --- a/share/extensions/alphabet_soup/y.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 477.09103,593.15836 L 413.99683,468 L 450.5,468.15564 L 504.72008,577.46901 C 509.65203,566.06508 518.51623,558.70062 531,558.54636 C 547.21611,558.34598 556.41762,570.43408 557.78184,585.5 C 559.88329,608.70762 538.91445,618.7373 518.64216,619.95485 C 498.86713,621.14254 485.44673,609.73335 477.09103,593.15836 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/yogh.svg b/share/extensions/alphabet_soup/yogh.svg deleted file mode 100644 index 6e6f19d19..000000000 --- a/share/extensions/alphabet_soup/yogh.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 288.42793,465.05582 C 289.40321,397.00935 327.95172,357.80486 387.6958,331.06026 C 398.23942,327.59968 398.83579,325.57963 397.25615,324 L 431.73781,324 L 467.9042,324 L 483.02394,341.5 L 433.17281,342.5295 C 424.38848,342.88033 421.26737,343.37986 418.5,344.38769 C 372.71776,365.93027 362.26294,420.9786 360.21638,466.75049 C 360.12169,509.28116 377.39271,594 432,594 C 432,600 432,606 432,612 C 349.58791,610.79376 289.07182,545.91599 288.42793,465.05582 z"/> -</svg> diff --git a/share/extensions/alphabet_soup/z.svg b/share/extensions/alphabet_soup/z.svg deleted file mode 100644 index 7826d59e0..000000000 --- a/share/extensions/alphabet_soup/z.svg +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.0" - width="864" - height="648"> - <path - d="M 288,199.19309 L 288,180 L 576,180 L 576,216 L 558.41481,216 C 555.77854,201.15181 545.97442,198.02196 532.61943,198.02196 L 378.91141,198.02196 C 369.66544,198.02196 363.51424,201.38267 370.14435,209.16095 L 468.03168,324 L 396.0296,324 L 288,199.19309 z"/> -</svg> diff --git a/share/extensions/bezmisc.py b/share/extensions/bezmisc.py deleted file mode 100755 index 1119b85e2..000000000 --- a/share/extensions/bezmisc.py +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2010 Nick Drobchenko, nick@cnc-club.ru -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import math, cmath - -def rootWrapper(a,b,c,d): - if a: - # 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.0*a**3 - 9.0*a*b + 27.0*c - k = a**2 - 3.0*b - n = m**2 - 4.0*k**3 - w1 = -.5 + .5*cmath.sqrt(-3.0) - w2 = -.5 - .5*cmath.sqrt(-3.0) - if n < 0: - m1 = pow(complex((m+cmath.sqrt(n))/2),1./3) - n1 = pow(complex((m-cmath.sqrt(n))/2),1./3) - else: - if m+math.sqrt(n) < 0: - m1 = -pow(-(m+math.sqrt(n))/2,1./3) - else: - m1 = pow((m+math.sqrt(n))/2,1./3) - if m-math.sqrt(n) < 0: - n1 = -pow(-(m-math.sqrt(n))/2,1./3) - else: - n1 = pow((m-math.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: - det=c**2.0-4.0*b*d - if det: - return (-c+cmath.sqrt(det))/(2.0*b),(-c-cmath.sqrt(det))/(2.0*b) - else: - return -c/(2.0*b), - elif c: - return 1.0*(-d/c), - return () - -def bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))): - #parametric bezier - x0=bx0 - y0=by0 - cx=3*(bx1-x0) - bx=3*(bx2-bx1)-cx - ax=bx3-x0-cx-bx - cy=3*(by1-y0) - by=3*(by2-by1)-cy - ay=by3-y0-cy-by - - return ax,ay,bx,by,cx,cy,x0,y0 - #ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - -def linebezierintersect(((lx1,ly1),(lx2,ly2)),((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))): - #parametric line - dd=lx1 - cc=lx2-lx1 - bb=ly1 - aa=ly2-ly1 - - if aa: - coef1=cc/aa - coef2=1 - else: - coef1=1 - coef2=aa/cc - - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - #cubic intersection coefficients - a=coef1*ay-coef2*ax - b=coef1*by-coef2*bx - c=coef1*cy-coef2*cx - d=coef1*(y0-bb)-coef2*(x0-dd) - - roots = rootWrapper(a,b,c,d) - retval = [] - 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: - retval.append(bezierpointatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),i)) - return retval - -def bezierpointatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t): - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - x=ax*(t**3)+bx*(t**2)+cx*t+x0 - y=ay*(t**3)+by*(t**2)+cy*t+y0 - return x,y - -def bezierslopeatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t): - ax,ay,bx,by,cx,cy,x0,y0=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 - return dx,dy - -def beziertatslope(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),(dy,dx)): - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - #quadratic coefficients of slope formula - if dx: - slope = 1.0*(dy/dx) - a=3*ay-3*ax*slope - b=2*by-2*bx*slope - c=cy-cx*slope - elif dy: - slope = 1.0*(dx/dy) - a=3*ax-3*ay*slope - b=2*bx-2*by*slope - c=cx-cy*slope - else: - return [] - - roots = rootWrapper(0,a,b,c) - retval = [] - 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: - retval.append(i) - return retval - -def tpoint((x1,y1),(x2,y2),t): - return x1+t*(x2-x1),y1+t*(y2-y1) -def beziersplitatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t): - m1=tpoint((bx0,by0),(bx1,by1),t) - m2=tpoint((bx1,by1),(bx2,by2),t) - m3=tpoint((bx2,by2),(bx3,by3),t) - m4=tpoint(m1,m2,t) - m5=tpoint(m2,m3,t) - m=tpoint(m4,m5,t) - - return ((bx0,by0),m1,m4,m),(m,m5,m3,(bx3,by3)) - -''' -Approximating the arc length of a bezier curve -according to <http://www.cit.gu.edu.au/~anthony/info/graphics/bezier.curves> - -if: - L1 = |P0 P1| +|P1 P2| +|P2 P3| - L0 = |P0 P3| -then: - L = 1/2*L0 + 1/2*L1 - ERR = L1-L0 -ERR approaches 0 as the number of subdivisions (m) increases - 2^-4m - -Reference: -Jens Gravesen <gravesen@mat.dth.dk> -"Adaptive subdivision and the length of Bezier curves" -mat-report no. 1992-10, Mathematical Institute, The Technical -University of Denmark. -''' -def pointdistance((x1,y1),(x2,y2)): - return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2)) -def Gravesen_addifclose(b, len, error = 0.001): - box = 0 - for i in range(1,4): - box += pointdistance(b[i-1], b[i]) - chord = pointdistance(b[0], b[3]) - if (box - chord) > error: - first, second = beziersplitatt(b, 0.5) - Gravesen_addifclose(first, len, error) - Gravesen_addifclose(second, len, error) - else: - len[0] += (box / 2.0) + (chord / 2.0) -def bezierlengthGravesen(b, error = 0.001): - len = [0] - Gravesen_addifclose(b, len, error) - return len[0] - -# balf = Bezier Arc Length Function -balfax,balfbx,balfcx,balfay,balfby,balfcy = 0,0,0,0,0,0 -def balf(t): - retval = (balfax*(t**2) + balfbx*t + balfcx)**2 + (balfay*(t**2) + balfby*t + balfcy)**2 - return math.sqrt(retval) - -def Simpson(f, a, b, n_limit, tolerance): - n = 2 - multiplier = (b - a)/6.0 - endsum = f(a) + f(b) - interval = (b - a)/2.0 - asum = 0.0 - bsum = f(a + interval) - est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum)) - est0 = 2.0 * est1 - #print multiplier, endsum, interval, asum, bsum, est1, est0 - while n < n_limit and abs(est1 - est0) > tolerance: - n *= 2 - multiplier /= 2.0 - interval /= 2.0 - asum += bsum - bsum = 0.0 - est0 = est1 - for i in xrange(1, n, 2): - bsum += f(a + (i * interval)) - est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum)) - #print multiplier, endsum, interval, asum, bsum, est1, est0 - return est1 - -def bezierlengthSimpson(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)), tolerance = 0.001): - global balfax,balfbx,balfcx,balfay,balfby,balfcy - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy - return Simpson(balf, 0.0, 1.0, 4096, tolerance) - -def beziertatlength(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)), l = 0.5, tolerance = 0.001): - global balfax,balfbx,balfcx,balfay,balfby,balfcy - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy - t = 1.0 - tdiv = t - curlen = Simpson(balf, 0.0, t, 4096, tolerance) - targetlen = l * curlen - diff = curlen - targetlen - while abs(diff) > tolerance: - tdiv /= 2.0 - if diff < 0: - t += tdiv - else: - t -= tdiv - curlen = Simpson(balf, 0.0, t, 4096, tolerance) - diff = curlen - targetlen - return t - -#default bezier length method -bezierlength = bezierlengthSimpson - -if __name__ == '__main__': - import timing - #print linebezierintersect(((,),(,)),((,),(,),(,),(,))) - #print linebezierintersect(((0,1),(0,-1)),((-1,0),(-.5,0),(.5,0),(1,0))) - tol = 0.00000001 - curves = [((0,0),(1,5),(4,5),(5,5)), - ((0,0),(0,0),(5,0),(10,0)), - ((0,0),(0,0),(5,1),(10,0)), - ((-10,0),(0,0),(10,0),(10,10)), - ((15,10),(0,0),(10,0),(-5,10))] - ''' - for curve in curves: - timing.start() - g = bezierlengthGravesen(curve,tol) - timing.finish() - gt = timing.micro() - - timing.start() - s = bezierlengthSimpson(curve,tol) - timing.finish() - st = timing.micro() - - print g, gt - print s, st - ''' - for curve in curves: - print beziertatlength(curve,0.5) - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/ccx_input.inx b/share/extensions/ccx_input.inx deleted file mode 100644 index a44697c52..000000000 --- a/share/extensions/ccx_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Corel DRAW Compressed Exchange files input (UC)</_name> - <id>org.inkscape.input.ccx.uniconvertor</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.ccx</extension> - <mimetype>application/x-xccx</mimetype> - <_filetypename>Corel DRAW Compressed Exchange files (UC) (*.ccx)</_filetypename> - <_filetypetooltip>Open compressed exchange files saved in Corel DRAW (UC)</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/cdr_input.inx b/share/extensions/cdr_input.inx deleted file mode 100644 index 6fd7f90ab..000000000 --- a/share/extensions/cdr_input.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Corel DRAW Input (UC)</_name> - <id>org.inkscape.input.cdr.uniconvertor</id> - <!-- the uniconv or uniconvertor dependency will be tested by uniconv-ext.py --> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.cdr</extension> - <mimetype>image/x-xcdr</mimetype> - <_filetypename>Corel DRAW 7-X4 files (UC) (*.cdr)</_filetypename> - <_filetypetooltip>Open files saved in Corel DRAW 7-X4 (UC)</_filetypetooltip> - <output_extension>org.inkscape.output.cdr</output_extension> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/cdt_input.inx b/share/extensions/cdt_input.inx deleted file mode 100644 index 912503643..000000000 --- a/share/extensions/cdt_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Corel DRAW templates input (UC)</_name> - <id>org.inkscape.input.cdt.uniconvertor</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.cdt</extension> - <mimetype>application/x-xcdt</mimetype> - <_filetypename>Corel DRAW 7-13 template files (UC) (*.cdt)</_filetypename> - <_filetypetooltip>Open files saved in Corel DRAW 7-13 (UC)</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/cgm_input.inx b/share/extensions/cgm_input.inx deleted file mode 100644 index 5c1ccd937..000000000 --- a/share/extensions/cgm_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Computer Graphics Metafile files input</_name> - <id>org.inkscape.input.cgm</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.cgm</extension> - <mimetype>application/x-xcgm</mimetype> - <_filetypename>Computer Graphics Metafile files (UC) (*.cgm)</_filetypename> - <_filetypetooltip>Open Computer Graphics Metafile files</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/chardataeffect.py b/share/extensions/chardataeffect.py deleted file mode 100755 index f81de6b80..000000000 --- a/share/extensions/chardataeffect.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jos Hirth, kaioa.com -Copyright (C) 2007 bulia byak -Copyright (C) 2007 Aaron C. Spike - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import sys, optparse, inkex - -class CharDataEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.visited = [] - - newline = True - newpar = True - - def effect(self): - if len(self.selected)==0: - self.recurse(self.document.getroot()) - else: - for id,node in self.selected.iteritems(): - self.recurse(node) - - def recurse(self,node): - istext = (node.tag == '{http://www.w3.org/2000/svg}flowPara' or node.tag == '{http://www.w3.org/2000/svg}flowDiv' or node.tag == '{http://www.w3.org/2000/svg}text') - if node.get('{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}role') == 'line': - self.newline = True - elif istext: - self.newline = True - self.newpar = True - - if node.text != None: - node.text = self.process_chardata(node.text, self.newline, self.newpar) - self.newline = False - self.newpar = False - - for child in node: - self.recurse(child) - - if node.tail != None: - node.tail = self.process_chardata(node.tail, self.newline, self.newpar) - - def process_chardata(self,text, line, par): - pass - diff --git a/share/extensions/cmx_input.inx b/share/extensions/cmx_input.inx deleted file mode 100644 index 75f9aa10a..000000000 --- a/share/extensions/cmx_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Corel DRAW Presentation Exchange files input (UC)</_name> - <id>org.inkscape.input.cmx.uniconvertor</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.cmx</extension> - <mimetype>application/x-xcmx</mimetype> - <_filetypename>Corel DRAW Presentation Exchange files (UC) (*.cmx)</_filetypename> - <_filetypetooltip>Open presentation exchange files saved in Corel DRAW (UC)</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_HSL_adjust.inx b/share/extensions/color_HSL_adjust.inx deleted file mode 100644 index bf86a9856..000000000 --- a/share/extensions/color_HSL_adjust.inx +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>HSL Adjust</_name> - <id>org.inkscape.color.HSL_adjust</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_HSL_adjust.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <param name="tab" type="notebook"> - <page name="Options" _gui-text="Options"> - <param name="hue" type="int" appearance="full" min="-360" max="360" indent="0" _gui-text="Hue (°)">0</param> - <param name="random_h" type="boolean" _gui-text="Random hue">false</param> - <param name="saturation" type="int" appearance="full" min="-100" max="100" indent="0" _gui-text="Saturation (%)">0</param> - <param name="random_s" type="boolean" _gui-text="Random saturation">false</param> - <param name="lightness" type="int" appearance="full" min="-100" max="100" indent="0" _gui-text="Lightness (%)">0</param> - <param name="random_l" type="boolean" _gui-text="Random lightness">false</param> - </page> - <page name="Help" _gui-text="Help"> - <_param name="instructions" type="description" xml:space="preserve">Adjusts hue, saturation and lightness in the HSL representation of the selected objects's color. -Options: - * Hue: rotate by degrees (wraps around). - * Saturation: add/subtract % (min=-100, max=100). - * Lightness: add/subtract % (min=-100, max=100). - * Random Hue/Saturation/Lightness: randomize the parameter's value. - </_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_HSL_adjust.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_HSL_adjust.py b/share/extensions/color_HSL_adjust.py deleted file mode 100755 index 473c4bd1e..000000000 --- a/share/extensions/color_HSL_adjust.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python - -# standard library -import random -# local library -import coloreffect -import inkex - -class C(coloreffect.ColorEffect): - def __init__(self): - coloreffect.ColorEffect.__init__(self) - self.OptionParser.add_option("-x", "--hue", - action="store", type="int", - dest="hue", default="0", - help="Adjust hue") - self.OptionParser.add_option("-s", "--saturation", - action="store", type="int", - dest="saturation", default="0", - help="Adjust saturation") - self.OptionParser.add_option("-l", "--lightness", - action="store", type="int", - dest="lightness", default="0", - help="Adjust lightness") - self.OptionParser.add_option("", "--random_h", - action="store", type="inkbool", - dest="random_hue", default=False, - help="Randomize hue") - self.OptionParser.add_option("", "--random_s", - action="store", type="inkbool", - dest="random_saturation", default=False, - help="Randomize saturation") - self.OptionParser.add_option("", "--random_l", - action="store", type="inkbool", - dest="random_lightness", default=False, - help="Randomize lightness") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", - help="The selected UI-tab when OK was pressed") - - def clamp(self, minimum, x, maximum): - return max(minimum, min(x, maximum)) - - def colmod(self, r, g, b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl old: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - if (self.options.random_hue): - hsl[0] = random.random() - elif (self.options.hue): - hueval = hsl[0] + (self.options.hue / 360.0) - hsl[0] = hueval % 1 - if(self.options.random_saturation): - hsl[1] = random.random() - elif (self.options.saturation): - satval = hsl[1] + (self.options.saturation / 100.0) - hsl[1] = self.clamp(0.0, satval, 1.0) - if(self.options.random_lightness): - hsl[2] = random.random() - elif (self.options.lightness): - lightval = hsl[2] + (self.options.lightness / 100.0) - hsl[2] = self.clamp(0.0, lightval, 1.0) - #inkex.debug("hsl new: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/color_blackandwhite.inx b/share/extensions/color_blackandwhite.inx deleted file mode 100644 index 0fa58a128..000000000 --- a/share/extensions/color_blackandwhite.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Black and White</_name> - <id>org.inkscape.color.blackandwhite</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_blackandwhite.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <param name="threshold" type="int" min="1" max="255" _gui-text="Threshold Color (1-255):">127</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_blackandwhite.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_blackandwhite.py b/share/extensions/color_blackandwhite.py deleted file mode 100755 index fcee057c7..000000000 --- a/share/extensions/color_blackandwhite.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -import coloreffect,sys - -class C(coloreffect.ColorEffect): - def __init__(self): - coloreffect.ColorEffect.__init__(self) - self.OptionParser.add_option("-t", "--threshold", - action="store", type="int", - dest="threshold", default=127, - help="Threshold Color Level") - - def colmod(self,r,g,b): - #ITU-R Recommendation BT.709 - #l = 0.2125 * r + 0.7154 * g + 0.0721 * b - #NTSC and PAL - l = 0.299 * r + 0.587 * g + 0.114 * b - if l > self.options.threshold: - ig = 255 - else: - ig = 0 - #coloreffect.debug('gs '+hex(r)+' '+hex(g)+' '+hex(b)+'%02x%02x%02x' % (ig,ig,ig)) - return '%02x%02x%02x' % (ig,ig,ig) - -c = C() -c.affect() diff --git a/share/extensions/color_brighter.inx b/share/extensions/color_brighter.inx deleted file mode 100644 index 437478ef5..000000000 --- a/share/extensions/color_brighter.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Brighter</_name> - <id>org.inkscape.color.brighter</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_brighter.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_brighter.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_brighter.py b/share/extensions/color_brighter.py deleted file mode 100755 index 6cec075d4..000000000 --- a/share/extensions/color_brighter.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - FACTOR=0.9 - - i=int(1.0/(1.0-FACTOR)) - if r==0 and g==0 and b==0: - return '%02x%02x%02x' % (i,i,i) - if r>0 and r<i: - r=i - if g>0 and g<i: - g=i - if b>0 and b<i: - b=i; - - r=min(int(round((r/FACTOR))), 255) - g=min(int(round((g/FACTOR))), 255) - b=min(int(round((b/FACTOR))), 255) - - return '%02x%02x%02x' % (r,g,b) - -c = C() -c.affect() diff --git a/share/extensions/color_custom.inx b/share/extensions/color_custom.inx deleted file mode 100644 index 6b2b97adb..000000000 --- a/share/extensions/color_custom.inx +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name msgctxt="Custom color extension">Custom</_name> - <id>org.inkscape.color.custom</id> - <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="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> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_custom.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_custom.py b/share/extensions/color_custom.py deleted file mode 100755 index 3eefc3f55..000000000 --- a/share/extensions/color_custom.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/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") - 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() diff --git a/share/extensions/color_darker.inx b/share/extensions/color_darker.inx deleted file mode 100644 index f977b827a..000000000 --- a/share/extensions/color_darker.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Darker</_name> - <id>org.inkscape.color.darker</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_darker.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_darker.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_darker.py b/share/extensions/color_darker.py deleted file mode 100755 index a8edb07c6..000000000 --- a/share/extensions/color_darker.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - FACTOR=0.9 - r=int(round(max(r*FACTOR,0))) - g=int(round(max(g*FACTOR,0))) - b=int(round(max(b*FACTOR,0))) - return '%02x%02x%02x' % (r,g,b) - -c = C() -c.affect() diff --git a/share/extensions/color_desaturate.inx b/share/extensions/color_desaturate.inx deleted file mode 100644 index e249b8903..000000000 --- a/share/extensions/color_desaturate.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Desaturate</_name> - <id>org.inkscape.color.desaturate</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_desaturate.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_desaturate.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_desaturate.py b/share/extensions/color_desaturate.py deleted file mode 100755 index a2350a4d3..000000000 --- a/share/extensions/color_desaturate.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - l = (max(r,g,b)+min(r,g,b))/2 - ig=int(round(l)) - return '%02x%02x%02x' % (ig,ig,ig) - -c = C() -c.affect() diff --git a/share/extensions/color_grayscale.inx b/share/extensions/color_grayscale.inx deleted file mode 100644 index e1a3b48e1..000000000 --- a/share/extensions/color_grayscale.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Grayscale</_name> - <id>org.inkscape.color.grayscale</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_grayscale.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_grayscale.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_grayscale.py b/share/extensions/color_grayscale.py deleted file mode 100755 index 727f23570..000000000 --- a/share/extensions/color_grayscale.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - #ITU-R Recommendation BT.709 - #l = 0.2125 * r + 0.7154 * g + 0.0721 * b - #NTSC and PAL - l = 0.299 * r + 0.587 * g + 0.114 * b - ig=int(round(l)) - #coloreffect.debug('gs '+hex(r)+' '+hex(g)+' '+hex(b)+'%02x%02x%02x' % (ig,ig,ig)) - return '%02x%02x%02x' % (ig,ig,ig) - -c = C() -c.affect() diff --git a/share/extensions/color_lesshue.inx b/share/extensions/color_lesshue.inx deleted file mode 100644 index 11aad6106..000000000 --- a/share/extensions/color_lesshue.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Less Hue</_name> - <id>org.inkscape.color.lesshue</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_lesshue.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_lesshue.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_lesshue.py b/share/extensions/color_lesshue.py deleted file mode 100755 index d34a75019..000000000 --- a/share/extensions/color_lesshue.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[0] = hsl[0] - 0.05 - if hsl[0] < 0.0: - hsl[0] = 1.0 + hsl[0] - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_lesslight.inx b/share/extensions/color_lesslight.inx deleted file mode 100644 index 5d66c900f..000000000 --- a/share/extensions/color_lesslight.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Less Light</_name> - <id>org.inkscape.color.lesslight</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_lesslight.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_lesslight.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_lesslight.py b/share/extensions/color_lesslight.py deleted file mode 100755 index 94dfb412d..000000000 --- a/share/extensions/color_lesslight.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[2] = hsl[2] - 0.05 - if hsl[2] < 0.0: - hsl[2] = 0.0 - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_lesssaturation.inx b/share/extensions/color_lesssaturation.inx deleted file mode 100644 index 7ace6f947..000000000 --- a/share/extensions/color_lesssaturation.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Less Saturation</_name> - <id>org.inkscape.color.lesssaturation</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_lesssaturation.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_lesssaturation.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_lesssaturation.py b/share/extensions/color_lesssaturation.py deleted file mode 100755 index 1d3702c76..000000000 --- a/share/extensions/color_lesssaturation.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[1] = hsl[1] - 0.05 - if hsl[1] < 0.0: - hsl[1] = 0.0 - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_morehue.inx b/share/extensions/color_morehue.inx deleted file mode 100644 index 279747d45..000000000 --- a/share/extensions/color_morehue.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>More Hue</_name> - <id>org.inkscape.color.morehue</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_morehue.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_morehue.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_morehue.py b/share/extensions/color_morehue.py deleted file mode 100755 index 7d3406ec0..000000000 --- a/share/extensions/color_morehue.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[0] = hsl[0] + 0.05 - if hsl[0] > 1.0: - hsl[0] = hsl[0] - 1.0 - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_morelight.inx b/share/extensions/color_morelight.inx deleted file mode 100644 index 416f7a362..000000000 --- a/share/extensions/color_morelight.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>More Light</_name> - <id>org.inkscape.color.morelight</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_morelight.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_morelight.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_morelight.py b/share/extensions/color_morelight.py deleted file mode 100755 index bbc418c3f..000000000 --- a/share/extensions/color_morelight.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[2] = hsl[2] + 0.05 - if hsl[2] > 1.0: - hsl[2] = 1.0 - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_moresaturation.inx b/share/extensions/color_moresaturation.inx deleted file mode 100644 index 0f479ab85..000000000 --- a/share/extensions/color_moresaturation.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>More Saturation</_name> - <id>org.inkscape.color.moresaturation</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_moresaturation.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_moresaturation.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_moresaturation.py b/share/extensions/color_moresaturation.py deleted file mode 100755 index 4ecb4987c..000000000 --- a/share/extensions/color_moresaturation.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import coloreffect, inkex - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - #inkex.debug("hsl: " + str(hsl[0]) + ", " + str(hsl[1]) + ", " + str(hsl[2])) - hsl[1] = hsl[1] + 0.05 - if hsl[1] > 1.0: - hsl[1] = 1.0 - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - -c = C() -c.affect() diff --git a/share/extensions/color_negative.inx b/share/extensions/color_negative.inx deleted file mode 100644 index cae536336..000000000 --- a/share/extensions/color_negative.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Negative</_name> - <id>org.inkscape.color.negative</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_negative.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_negative.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_negative.py b/share/extensions/color_negative.py deleted file mode 100755 index 87a4bdce3..000000000 --- a/share/extensions/color_negative.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - return '%02x%02x%02x' % (255-r,255-g,255-b) - -c = C() -c.affect() diff --git a/share/extensions/color_randomize.inx b/share/extensions/color_randomize.inx deleted file mode 100644 index c0c0d9ea2..000000000 --- a/share/extensions/color_randomize.inx +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Randomize</_name> - <id>org.inkscape.color.randomize</id> - <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="tab" type="notebook"> - <page name="Options" _gui-text="Options"> - <param name="hue_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Hue range (%)">100</param> - <param name="saturation_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Saturation range (%)">100</param> - <param name="lightness_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Lightness range (%)">100</param> - <param name="opacity_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Opacity range (%)">0</param> - </page> - <page name="Help" _gui-text="Help"> - <_param name="instructions" type="description" xml:space="preserve">Randomizes hue, saturation, lightness and/or opacity (opacity randomization only for objects and groups). Change the range values to limit the distance between the original color and the randomized one.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_randomize.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_randomize.py b/share/extensions/color_randomize.py deleted file mode 100755 index 93abcf174..000000000 --- a/share/extensions/color_randomize.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python - -import random - -import coloreffect -import inkex - -class C(coloreffect.ColorEffect): - def __init__(self): - coloreffect.ColorEffect.__init__(self) - self.OptionParser.add_option("-y", "--hue_range", - action="store", type="int", - dest="hue_range", default=0, - help="Hue range") - self.OptionParser.add_option("-t", "--saturation_range", - action="store", type="int", - dest="saturation_range", default=0, - help="Saturation range") - self.OptionParser.add_option("-m", "--lightness_range", - action="store", type="int", - dest="lightness_range", default=0, - help="Lightness range") - self.OptionParser.add_option("-o", "--opacity_range", - action="store", type="int", - dest="opacity_range", default=0, - help="Opacity range") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", - help="The selected UI-tab when OK was pressed") - - def randomize_hsl(self, limit, current_value): - limit = 255.0 * limit / 100.0 - limit /= 2 - max = int((current_value * 255.0) + limit) - min = int((current_value * 255.0) - limit) - if max > 255: - min = min - (max - 255) - max = 255 - if min < 0: - max = max - min - min = 0 - return random.randrange(min, max) / 255.0 - - def colmod(self,r,g,b): - hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - if self.options.hue_range > 0: - hsl[0] = self.randomize_hsl(self.options.hue_range, hsl[0]) - if self.options.saturation_range > 0: - hsl[1] = self.randomize_hsl(self.options.saturation_range, hsl[1]) - if self.options.lightness_range > 0: - hsl[2] = self.randomize_hsl(self.options.lightness_range, hsl[2]) - rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2]) - return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255) - - def opacmod(self, opacity): - if self.options.opacity_range > 0: - # maybe not necessary, but better not change things that shouldn't change - try: - opacity = float(opacity) - except ValueError: - return opacity - - limit = self.options.opacity_range - limit /= 2 - max = opacity*100 + limit - min = opacity*100 - limit - if max > 100: - min = min - (max - 100) - max = 100 - if min < 0: - max = max - min - min = 0 - ret = str(random.uniform(min,max)/100) - return ret - return opacity - - -if __name__ == '__main__': - c = C() - c.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/color_removeblue.inx b/share/extensions/color_removeblue.inx deleted file mode 100644 index 6f7ce46df..000000000 --- a/share/extensions/color_removeblue.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Remove Blue</_name> - <id>org.inkscape.color.removeblue</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_removeblue.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_removeblue.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_removeblue.py b/share/extensions/color_removeblue.py deleted file mode 100755 index 1ea207bdd..000000000 --- a/share/extensions/color_removeblue.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - return '%02x%02x%02x' % (r,g,0) - -c = C() -c.affect() diff --git a/share/extensions/color_removegreen.inx b/share/extensions/color_removegreen.inx deleted file mode 100644 index 1d35a58d3..000000000 --- a/share/extensions/color_removegreen.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Remove Green</_name> - <id>org.inkscape.color.removegreen</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_removegreen.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_removegreen.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_removegreen.py b/share/extensions/color_removegreen.py deleted file mode 100755 index 86fdc73e0..000000000 --- a/share/extensions/color_removegreen.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - return '%02x%02x%02x' % (r,0,b) - -c = C() -c.affect() diff --git a/share/extensions/color_removered.inx b/share/extensions/color_removered.inx deleted file mode 100644 index 918e7c1c2..000000000 --- a/share/extensions/color_removered.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Remove Red</_name> - <id>org.inkscape.color.removered</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_removered.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_removered.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_removered.py b/share/extensions/color_removered.py deleted file mode 100755 index a6b92fd45..000000000 --- a/share/extensions/color_removered.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - return '%02x%02x%02x' % (0,g,b) - -c = C() -c.affect() diff --git a/share/extensions/color_replace.inx b/share/extensions/color_replace.inx deleted file mode 100644 index 289c4424d..000000000 --- a/share/extensions/color_replace.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Replace color</_name> - <id>org.inkscape.color.replacecolor</id> - <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):" _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> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_replace.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/color_replace.py b/share/extensions/color_replace.py deleted file mode 100755 index edfd90a76..000000000 --- a/share/extensions/color_replace.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -import inkex - -class C(coloreffect.ColorEffect): - def __init__(self): - coloreffect.ColorEffect.__init__(self) - self.OptionParser.add_option("-f", "--from_color", action="store", type="string", dest="from_color", default="000000", help="Replace color") - self.OptionParser.add_option("-t", "--to_color", action="store", type="string", dest="to_color", default="000000", help="By color") - - def colmod(self,r,g,b): - this_color = '%02x%02x%02x' % (r, g, b) - - fr = self.options.from_color.strip('"').replace('#', '').lower() - to = self.options.to_color.strip('"').replace('#', '').lower() - - #inkex.debug(this_color+"|"+fr+"|"+to) - if this_color == fr: - return to - else: - return this_color - -c = C() -c.affect() diff --git a/share/extensions/color_rgbbarrel.inx b/share/extensions/color_rgbbarrel.inx deleted file mode 100644 index f956ab961..000000000 --- a/share/extensions/color_rgbbarrel.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>RGB Barrel</_name> - <id>org.inkscape.color.rgbbarrel</id> - <dependency type="executable" location="extensions">coloreffect.py</dependency> - <dependency type="executable" location="extensions">color_rgbbarrel.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Color"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">color_rgbbarrel.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/color_rgbbarrel.py b/share/extensions/color_rgbbarrel.py deleted file mode 100755 index 0fdcd47bc..000000000 --- a/share/extensions/color_rgbbarrel.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import coloreffect - -class C(coloreffect.ColorEffect): - def colmod(self,r,g,b): - return '%02x%02x%02x' % (b,r,g) - -c = C() -c.affect() diff --git a/share/extensions/coloreffect.py b/share/extensions/coloreffect.py deleted file mode 100755 index d33ac41fe..000000000 --- a/share/extensions/coloreffect.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jos Hirth, kaioa.com -Copyright (C) 2007 Aaron C. Spike -Copyright (C) 2009 Monash University - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import sys, copy, simplestyle, inkex -import random - -color_props_fill = ('fill', 'stop-color', 'flood-color', 'lighting-color') -color_props_stroke = ('stroke',) -opacity_props = ('opacity',) #'stop-opacity', 'fill-opacity', 'stroke-opacity' don't work with clones -color_props = color_props_fill + color_props_stroke - - -class ColorEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.visited = [] - - def effect(self): - if len(self.selected)==0: - self.getAttribs(self.document.getroot()) - else: - for id,node in self.selected.iteritems(): - self.getAttribs(node) - - def getAttribs(self,node): - self.changeStyle(node) - for child in node: - self.getAttribs(child) - - def changeStyle(self,node): - for attr in color_props: - val = node.get(attr) - if val: - new_val = self.process_prop(val) - if new_val != val: - node.set(attr, new_val) - - if node.attrib.has_key('style'): - # References for style attribute: - # http://www.w3.org/TR/SVG11/styling.html#StyleAttribute, - # http://www.w3.org/TR/CSS21/syndata.html - # - # The SVG spec is ambiguous as to how style attributes should be parsed. - # For example, it isn't clear whether semicolons are allowed to appear - # within strings or comments, or indeed whether comments are allowed to - # appear at all. - # - # The processing here is just something simple that should usually work, - # without trying too hard to get everything right. - # (Won't work for the pathological case that someone escapes a property - # name, probably does the wrong thing if colon or semicolon is used inside - # a comment or string value.) - style = node.get('style') # fixme: this will break for presentation attributes! - if style: - #inkex.debug('old style:'+style) - declarations = style.split(';') - opacity_in_style = False - for i,decl in enumerate(declarations): - parts = decl.split(':', 2) - if len(parts) == 2: - (prop, val) = parts - prop = prop.strip().lower() - if prop in color_props: - val = val.strip() - new_val = self.process_prop(val) - if new_val != val: - declarations[i] = prop + ':' + new_val - elif prop in opacity_props: - opacity_in_style = True - val = val.strip() - new_val = self.process_prop(val) - if new_val != val: - declarations[i] = prop + ':' + new_val - if not opacity_in_style: - new_val = self.process_prop("1") - declarations.append('opacity' + ':' + new_val) - #inkex.debug('new style:'+';'.join(declarations)) - node.set('style', ';'.join(declarations)) - - def process_prop(self, col): - #inkex.debug('got:'+col+str(type(col))) - if simplestyle.isColor(col): - c=simplestyle.parseColor(col) - col='#'+self.colmod(c[0], c[1], c[2]) - #inkex.debug('made:'+col) - elif col.startswith('url(#'): - id = col[len('url(#'):col.find(')')] - newid = '%s-%d' % (id, int(random.random() * 1000)) - #inkex.debug('ID:' + id ) - path = '//*[@id="%s"]' % id - for node in self.document.xpath(path, namespaces=inkex.NSS): - self.process_gradient(node, newid) - col = 'url(#%s)' % newid - # what remains should be opacity - else: - col = self.opacmod(col) - - #inkex.debug('col:'+str(col)) - return col - - def process_gradient(self, node, newid): - #if node.hasAttributes(): - #this_id=node.getAttribute('id') - #if this_id in self.visited: - ## prevent multiple processing of the same gradient if it is used by more than one selected object - ##inkex.debug("already had: " + this_id) - #return - #self.visited.append(this_id) - #inkex.debug("visited: " + str(self.visited)) - newnode = copy.deepcopy(node) - newnode.set('id', newid) - node.getparent().append(newnode) - self.changeStyle(newnode) - for child in newnode: - self.changeStyle(child) - xlink = inkex.addNS('href','xlink') - if newnode.attrib.has_key(xlink): - href=newnode.get(xlink) - if href.startswith('#'): - id = href[len('#'):len(href)] - #inkex.debug('ID:' + id ) - newhref = '%s-%d' % (id, int(random.random() * 1000)) - newnode.set(xlink, '#%s' % newhref) - path = '//*[@id="%s"]' % id - for node in self.document.xpath(path, namespaces=inkex.NSS): - self.process_gradient(node, newhref) - - def colmod(self,r,g,b): - pass - - def opacmod(self, opacity): - return opacity - - def rgb_to_hsl(self,r, g, b): - rgb_max = max (max (r, g), b) - rgb_min = min (min (r, g), b) - delta = rgb_max - rgb_min - hsl = [0.0, 0.0, 0.0] - hsl[2] = (rgb_max + rgb_min)/2.0 - if delta == 0: - hsl[0] = 0.0 - hsl[1] = 0.0 - else: - if hsl[2] <= 0.5: - hsl[1] = delta / (rgb_max + rgb_min) - else: - hsl[1] = delta / (2 - rgb_max - rgb_min) - if r == rgb_max: - hsl[0] = (g - b) / delta - else: - if g == rgb_max: - hsl[0] = 2.0 + (b - r) / delta - else: - if b == rgb_max: - hsl[0] = 4.0 + (r - g) / delta - hsl[0] = hsl[0] / 6.0 - if hsl[0] < 0: - hsl[0] = hsl[0] + 1 - if hsl[0] > 1: - hsl[0] = hsl[0] - 1 - return hsl - - def hue_2_rgb (self, v1, v2, h): - if h < 0: - h += 6.0 - if h > 6: - h -= 6.0 - if h < 1: - return v1 + (v2 - v1) * h - if h < 3: - return v2 - if h < 4: - return v1 + (v2 - v1) * (4 - h) - return v1 - - def hsl_to_rgb (self,h, s, l): - rgb = [0, 0, 0] - if s == 0: - rgb[0] = l - rgb[1] = l - rgb[2] = l - else: - if l < 0.5: - v2 = l * (1 + s) - else: - v2 = l + s - l*s - v1 = 2*l - v2 - rgb[0] = self.hue_2_rgb (v1, v2, h*6 + 2.0) - rgb[1] = self.hue_2_rgb (v1, v2, h*6) - rgb[2] = self.hue_2_rgb (v1, v2, h*6 - 2.0) - return rgb - - -# vi: set autoindent shiftwidth=2 tabstop=8 expandtab softtabstop=2 : diff --git a/share/extensions/colors.xml b/share/extensions/colors.xml deleted file mode 100644 index 7ed8592d5..000000000 --- a/share/extensions/colors.xml +++ /dev/null @@ -1,151 +0,0 @@ -<?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="rebeccapurple" hex="#663399" rgb="102,51,153" /> -<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 deleted file mode 100644 index 1230ff2d8..000000000 --- a/share/extensions/convert2dashes.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?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 deleted file mode 100755 index 1d1ba9736..000000000 --- a/share/extensions/convert2dashes.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python -''' -This extension converts a path into a dashed line using 'stroke-dasharray' -It is a modification of the file addnodes.py - -Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org -Copyright (C) 2009 Alvin Penner, penner@vaxxine.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -import inkex -import cubicsuperpath -import bezmisc -import simplestyle - -def tpoint((x1,y1), (x2,y2), t = 0.5): - return [x1+t*(x2-x1),y1+t*(y2-y1)] -def cspbezsplit(sp1, sp2, t = 0.5): - m1=tpoint(sp1[1],sp1[2],t) - m2=tpoint(sp1[2],sp2[0],t) - m3=tpoint(sp2[0],sp2[1],t) - m4=tpoint(m1,m2,t) - m5=tpoint(m2,m3,t) - m=tpoint(m4,m5,t) - return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]] -def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001): - bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) - t = bezmisc.beziertatlength(bez, l, tolerance) - return cspbezsplit(sp1, sp2, t) -def cspseglength(sp1,sp2, tolerance = 0.001): - bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) - return bezmisc.bezierlength(bez, tolerance) - -class SplitIt(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.not_converted = [] - - def effect(self): - for i, node in self.selected.iteritems(): - self.convert2dash(node) - if len(self.not_converted): - inkex.errormsg(_('Total number of objects not converted: {}\n').format(len(self.not_converted))) - # return list of IDs in case the user needs to find a specific object - inkex.debug(self.not_converted) - - def convert2dash(self, node): - if node.tag == inkex.addNS('g', 'svg'): - for child in node: - self.convert2dash(child) - else: - if node.tag == inkex.addNS('path','svg'): - dashes = [] - offset = 0 - style = simplestyle.parseStyle(node.get('style')) - if style.has_key('stroke-dasharray'): - if style['stroke-dasharray'].find(',') > 0: - dashes = [float (dash) for dash in style['stroke-dasharray'].split(',')] - if style.has_key('stroke-dashoffset'): - offset = style['stroke-dashoffset'] - if dashes: - p = cubicsuperpath.parsePath(node.get('d')) - new = [] - for sub in p: - idash = 0 - dash = dashes[0] - length = float (offset) - while dash < length: - length = length - dash - idash = (idash + 1) % len(dashes) - dash = dashes[idash] - new.append([sub[0][:]]) - i = 1 - while i < len(sub): - dash = dash - length - length = cspseglength(new[-1][-1], sub[i]) - while dash < length: - new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], dash/length) - if idash % 2: # create a gap - new.append([next[:]]) - else: # splice the curve - new[-1].append(next[:]) - length = length - dash - idash = (idash + 1) % len(dashes) - dash = dashes[idash] - if idash % 2: - new.append([sub[i]]) - else: - new[-1].append(sub[i]) - i+=1 - node.set('d',cubicsuperpath.formatPath(new)) - del style['stroke-dasharray'] - node.set('style', simplestyle.formatStyle(style)) - if node.get(inkex.addNS('type','sodipodi')): - del node.attrib[inkex.addNS('type', 'sodipodi')] - else: - self.not_converted.append(node.get('id')) - -if __name__ == '__main__': - e = SplitIt() - e.affect() - - -# 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 deleted file mode 100755 index c34236afe..000000000 --- a/share/extensions/cspsubdiv.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -from bezmisc import * -from ffgeom import * - -def maxdist(((p0x,p0y),(p1x,p1y),(p2x,p2y),(p3x,p3y))): - p0 = Point(p0x,p0y) - p1 = Point(p1x,p1y) - p2 = Point(p2x,p2y) - p3 = Point(p3x,p3y) - - s1 = Segment(p0,p3) - return max(s1.distanceToPoint(p1),s1.distanceToPoint(p2)) - - -def cspsubdiv(csp,flat): - for sp in csp: - subdiv(sp,flat) - -def subdiv(sp,flat,i=1): - while i < len(sp): - p0 = sp[i-1][1] - p1 = sp[i-1][2] - p2 = sp[i][0] - p3 = sp[i][1] - - b = (p0,p1,p2,p3) - m = maxdist(b) - if m <= flat: - i += 1 - else: - one, two = beziersplitatt(b,0.5) - sp[i-1][2] = one[1] - sp[i][0] = two[2] - p = [one[2],one[3],two[1]] - sp[i:1] = [p] - -# 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 deleted file mode 100755 index b505e8c4f..000000000 --- a/share/extensions/cubicsuperpath.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env python -""" -cubicsuperpath.py - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -import simplepath -from math import * - -def matprod(mlist): - prod=mlist[0] - for m in mlist[1:]: - a00=prod[0][0]*m[0][0]+prod[0][1]*m[1][0] - a01=prod[0][0]*m[0][1]+prod[0][1]*m[1][1] - a10=prod[1][0]*m[0][0]+prod[1][1]*m[1][0] - a11=prod[1][0]*m[0][1]+prod[1][1]*m[1][1] - prod=[[a00,a01],[a10,a11]] - return prod -def rotmat(teta): - return [[cos(teta),-sin(teta)],[sin(teta),cos(teta)]] -def applymat(mat, pt): - x=mat[0][0]*pt[0]+mat[0][1]*pt[1] - y=mat[1][0]*pt[0]+mat[1][1]*pt[1] - pt[0]=x - pt[1]=y -def norm(pt): - return sqrt(pt[0]*pt[0]+pt[1]*pt[1]) - -def ArcToPath(p1,params): - A=p1[:] - rx,ry,teta,longflag,sweepflag,x2,y2=params[:] - teta = teta*pi/180.0 - B=[x2,y2] - if rx==0 or ry==0 or A==B: - return([[A[:],A[:],A[:]],[B[:],B[:],B[:]]]) - mat=matprod((rotmat(teta),[[1/rx,0],[0,1/ry]],rotmat(-teta))) - applymat(mat, A) - applymat(mat, B) - k=[-(B[1]-A[1]),B[0]-A[0]] - d=k[0]*k[0]+k[1]*k[1] - k[0]/=sqrt(d) - k[1]/=sqrt(d) - d=sqrt(max(0,1-d/4)) - if longflag==sweepflag: - d*=-1 - O=[(B[0]+A[0])/2+d*k[0],(B[1]+A[1])/2+d*k[1]] - OA=[A[0]-O[0],A[1]-O[1]] - OB=[B[0]-O[0],B[1]-O[1]] - start=acos(OA[0]/norm(OA)) - if OA[1]<0: - start*=-1 - end=acos(OB[0]/norm(OB)) - if OB[1]<0: - end*=-1 - - if sweepflag and start>end: - end +=2*pi - if (not sweepflag) and start<end: - end -=2*pi - - NbSectors=int(abs(start-end)*2/pi)+1 - dTeta=(end-start)/NbSectors - #v=dTeta*2/pi*0.552 - #v=dTeta*2/pi*4*(sqrt(2)-1)/3 - v = 4*tan(dTeta/4)/3 - #if not sweepflag: - # v*=-1 - p=[] - for i in range(0,NbSectors+1,1): - angle=start+i*dTeta - v1=[O[0]+cos(angle)-(-v)*sin(angle),O[1]+sin(angle)+(-v)*cos(angle)] - pt=[O[0]+cos(angle) ,O[1]+sin(angle) ] - v2=[O[0]+cos(angle)- v *sin(angle),O[1]+sin(angle)+ v *cos(angle)] - p.append([v1,pt,v2]) - p[ 0][0]=p[ 0][1][:] - p[-1][2]=p[-1][1][:] - - mat=matprod((rotmat(teta),[[rx,0],[0,ry]],rotmat(-teta))) - for pts in p: - applymat(mat, pts[0]) - applymat(mat, pts[1]) - applymat(mat, pts[2]) - return(p) - -def CubicSuperPath(simplepath): - csp = [] - subpath = -1 - subpathstart = [] - last = [] - lastctrl = [] - for s in simplepath: - cmd, params = s - if cmd == 'M': - if last: - csp[subpath].append([lastctrl[:],last[:],last[:]]) - subpath += 1 - csp.append([]) - subpathstart = params[:] - last = params[:] - lastctrl = params[:] - elif cmd == 'L': - csp[subpath].append([lastctrl[:],last[:],last[:]]) - last = params[:] - lastctrl = params[:] - elif cmd == 'C': - csp[subpath].append([lastctrl[:],last[:],params[:2]]) - last = params[-2:] - lastctrl = params[2:4] - elif cmd == 'Q': - q0=last[:] - q1=params[0:2] - q2=params[2:4] - x0= q0[0] - x1=1./3*q0[0]+2./3*q1[0] - x2= 2./3*q1[0]+1./3*q2[0] - x3= q2[0] - y0= q0[1] - y1=1./3*q0[1]+2./3*q1[1] - y2= 2./3*q1[1]+1./3*q2[1] - y3= q2[1] - csp[subpath].append([lastctrl[:],[x0,y0],[x1,y1]]) - last = [x3,y3] - lastctrl = [x2,y2] - elif cmd == 'A': - arcp=ArcToPath(last[:],params[:]) - arcp[ 0][0]=lastctrl[:] - last=arcp[-1][1] - lastctrl = arcp[-1][0] - csp[subpath]+=arcp[:-1] - elif cmd == 'Z': - csp[subpath].append([lastctrl[:],last[:],last[:]]) - last = subpathstart[:] - lastctrl = subpathstart[:] - #append final superpoint - csp[subpath].append([lastctrl[:],last[:],last[:]]) - return csp - -def unCubicSuperPath(csp): - a = [] - for subpath in csp: - if subpath: - a.append(['M',subpath[0][1][:]]) - for i in range(1,len(subpath)): - a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]]) - return a - -def parsePath(d): - return CubicSuperPath(simplepath.parsePath(d)) - -def formatPath(p): - return simplepath.formatPath(unCubicSuperPath(p)) - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dhw_input.inx b/share/extensions/dhw_input.inx deleted file mode 100644 index ec43577b2..000000000 --- a/share/extensions/dhw_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DHW file input</_name> - <id>org.inkscape.input.dhw</id> - <dependency type="executable" location="extensions">dm2svg.py</dependency> - <input> - <extension>.dhw</extension> - <mimetype>application/x-extension-DHW</mimetype> - <_filetypename>ACECAD Digimemo File (*.dhw)</_filetypename> - <_filetypetooltip>Open files from ACECAD Digimemo</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">dm2svg.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dia.inx b/share/extensions/dia.inx deleted file mode 100644 index 746fbcd56..000000000 --- a/share/extensions/dia.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Dia Input</_name> - <id>org.inkscape.input.dia</id> - <dependency type="executable" location="extensions" _description="The dia2svg.sh script should be installed with your Inkscape distribution. If you do not have it, there is likely to be something wrong with your Inkscape installation.">dia2svg.sh</dependency> - <dependency type="executable" _description="In order to import Dia files, Dia itself must be installed. You can get Dia at http://live.gnome.org/Dia">dia</dependency> - <input> - <extension>.dia</extension> - <mimetype>application/x-dia</mimetype> - <_filetypename>Dia Diagram (*.dia)</_filetypename> - <_filetypetooltip>A diagram created with the program Dia</_filetypetooltip> - </input> - <script> - <command reldir="extensions">dia2svg.sh</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dia2svg.sh b/share/extensions/dia2svg.sh deleted file mode 100755 index 86acd593e..000000000 --- a/share/extensions/dia2svg.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -rc=0 - -# dia version 0.93 (the only version I've tested) allows `--export=-', but then -# ruins it by writing other cruft to stdout. So we'll have to use a temp file. -# dia 0.95 removes --export-to-format but still allows -t. -TMPDIR="${TMPDIR-/tmp}" -TEMPFILENAME=`mktemp 2>/dev/null || echo "$TMPDIR/tmpdia$$.svg"` -dia -n --export="${TEMPFILENAME}" -t svg "$1" > /dev/null 2>&1 || rc=1 - -cat < "${TEMPFILENAME}" || rc=1 -rm -f "${TEMPFILENAME}" -exit $rc diff --git a/share/extensions/dimension.inx b/share/extensions/dimension.inx deleted file mode 100644 index d89e5afa4..000000000 --- a/share/extensions/dimension.inx +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Dimensions</_name> - <id>se.lewerin.filter.dimension</id> - <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="enum" _gui-text="Bounding box type:"> - <_item value="geometric">Geometric</_item> - <_item value="visual">Visual</_item> - </param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Visualize Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">dimension.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dimension.py b/share/extensions/dimension.py deleted file mode 100755 index e6b2d8f85..000000000 --- a/share/extensions/dimension.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python -''' -dimension.py -An Inkscape effect for adding CAD style dimensions to selected objects -in a drawing. - -It uses the selection's bounding box, so if the bounding box has empty -space in the x- or y-direction (such as with some stars) the results -will look strange. Strokes might also overlap the edge of the -bounding box. - -The dimension arrows aren't measured: use the "Visualize Path/Measure -Path" effect to add measurements. - -This code contains snippets from existing effects in the Inkscape -extensions library, and marker data from markers.svg. - -Copyright (C) 2007 Peter Lewerin, peter.lewerin@tele2.se - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard library -import sys -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False -# local library -import inkex -import pathmodifier -from simpletransform import * - - -class Dimension(pathmodifier.PathModifier): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-x", "--xoffset", - action="store", type="float", - dest="xoffset", default=100.0, - help="x offset of the vertical dimension arrow") - self.OptionParser.add_option("-y", "--yoffset", - action="store", type="float", - dest="yoffset", default=100.0, - help="y offset of the horizontal dimension arrow") - self.OptionParser.add_option("-t", "--type", - action="store", type="string", - dest="type", default="geometric", - help="Bounding box type") - - def addMarker(self, name, rotate): - defs = self.xpathSingle('/svg:svg//svg:defs') - if defs == None: - defs = inkex.etree.SubElement(self.document.getroot(),inkex.addNS('defs','svg')) - marker = inkex.etree.SubElement(defs ,inkex.addNS('marker','svg')) - marker.set('id', name) - marker.set('orient', 'auto') - marker.set('refX', '0.0') - marker.set('refY', '0.0') - marker.set('style', 'overflow:visible') - marker.set(inkex.addNS('stockid','inkscape'), name) - - arrow = inkex.etree.Element("path") - arrow.set('d', 'M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z ') - if rotate: - arrow.set('transform', 'scale(0.8) rotate(180) translate(12.5,0)') - else: - arrow.set('transform', 'scale(0.8) translate(12.5,0)') - arrow.set('style', 'fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none') - marker.append(arrow) - - def dimHLine(self, y, xlat): - line = inkex.etree.Element("path") - x1 = self.bbox[0] - xlat[0] * self.xoffset - x2 = self.bbox[1] - y = y - xlat[1] * self.yoffset - line.set('d', 'M %f %f H %f' % (x1, y, x2)) - return line - - def dimVLine(self, x, xlat): - line = inkex.etree.Element("path") - x = x - xlat[0] * self.xoffset - y1 = self.bbox[2] - xlat[1] * self.yoffset - y2 = self.bbox[3] - line.set('d', 'M %f %f V %f' % (x, y1, y2)) - return line - - def effect(self): - scale = self.unittouu('1px') # convert to document units - self.xoffset = scale*self.options.xoffset - self.yoffset = scale*self.options.yoffset - - # query inkscape about the bounding box - if len(self.options.ids) == 0: - inkex.errormsg(_("Please select an object.")) - exit() - if self.options.type == "geometric": - self.bbox = computeBBox(self.selected.values()) - else: - q = {'x':0,'y':0,'width':0,'height':0} - file = self.args[-1] - id = self.options.ids[0] - for query in q.keys(): - if bsubprocess: - p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query,id,file), shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - q[query] = scale*float(p.stdout.read()) - err = p.stderr.read() - else: - f,err = os.popen3('inkscape --query-%s --query-id=%s "%s"' % (query,id,file))[1:] - q[query] = scale*float(f.read()) - f.close() - err.close() - self.bbox = (q['x'], q['x']+q['width'], q['y'], q['y']+q['height']) - - # Avoid ugly failure on rects and texts. - try: - testing_the_water = self.bbox[0] - except TypeError: - inkex.errormsg(_('Unable to process this object. Try changing it into a path first.')) - exit() - - layer = self.current_layer - - self.addMarker('Arrow1Lstart', False) - self.addMarker('Arrow1Lend', True) - - group = inkex.etree.SubElement(layer, 'g') - # group = inkex.etree.Element("g") - group.set('fill', 'none') - group.set('stroke', 'black') - - line = self.dimHLine(self.bbox[2], [0, 1]) - line.set('marker-start', 'url(#Arrow1Lstart)') - line.set('marker-end', 'url(#Arrow1Lend)') - line.set('stroke-width', str(scale)) - group.append(line) - - line = self.dimVLine(self.bbox[0], [0, 2]) - line.set('stroke-width', str(0.5*scale)) - group.append(line) - - line = self.dimVLine(self.bbox[1], [0, 2]) - line.set('stroke-width', str(0.5*scale)) - group.append(line) - - line = self.dimVLine(self.bbox[0], [1, 0]) - line.set('marker-start', 'url(#Arrow1Lstart)') - line.set('marker-end', 'url(#Arrow1Lend)') - line.set('stroke-width', str(scale)) - group.append(line) - - line = self.dimHLine(self.bbox[2], [2, 0]) - line.set('stroke-width', str(0.5*scale)) - group.append(line) - - line = self.dimHLine(self.bbox[3], [2, 0]) - line.set('stroke-width', str(0.5*scale)) - group.append(line) - - for id, node in self.selected.iteritems(): - group.append(node) - - layer.append(group) - -if __name__ == '__main__': - e = Dimension() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dm2svg.py b/share/extensions/dm2svg.py deleted file mode 100755 index 74afe6adf..000000000 --- a/share/extensions/dm2svg.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python -''' -dm2svg.py - import a DHW file from ACECAD DigiMemo - -Copyright (C) 2009 Kevin Lindsey, https://github.com/thelonious/DM2SVG -Copyright (C) 2011 Nikita Kitaev, https://github.com/nikitakit/DM2SVG -Copyright (C) 2011 Chris Morgan, https://gist.github.com/1471691 - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import struct - -def process_file(filename): - try: - f = open(filename, 'rb') - except IOError as e: - print >> sys.stderr, 'Unable to open %s: %s' % (filename, e) - return - - with f: - height = emit_header(f) - - layer = 'layer1' - timestamp = 0 - svg_element = '<g inkscape:groupmode="layer" id="%s">' % layer - - while True: - tag = f.read(1) - if tag == '': - break - - if ord(tag) > 128: - if tag == '\x90': - # Emit the current element and close the last layer - emit_element(svg_element) - emit_element('</g>') - - # Start a new layer - layer = 'layer%d' % (ord(f.read(1)) + 1) - timestamp = 0 - svg_element = '<g inkscape:groupmode="layer" id="%s">' % layer - elif tag == '\x88': - # Read the timestamp next - timestamp += ord(f.read(1)) * 20 - else: - # Emit the current svg element - emit_element(svg_element) - - coords = [] - - # Pen down - while True: - coords.append(read_point(f, height)) - if ord(f.read(1)) >= 128: - break - f.seek(-1, 1) # It wasn't the magic value, don't miss it - - # Pen up - coords.append(read_point(f, height)) - points = ' '.join(','.join(map(str, e)) for e in coords) - svg_element = '<polyline points="%s" dm:timestamp="%s" />' % (points, timestamp) - else: - print >> sys.stderr, 'Unsupported tag: %s\n' % tag - - # Emit the footer to finish it off - print '\n</svg>\n' - - -def read_point(f, ymax): - x1, x2, y1, y2 = map(ord, f.read(4)) - x = x1 | x2 << 7 - y = y1 | y2 << 7 - - return x, ymax - y - - -def emit_header(f): - id, version, width, height, page_type = struct.unpack('<32sBHHBxx', f.read(40)) - - print ''' -<svg viewBox="0 0 %(width)s %(height)s" fill="none" stroke="black" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" - xmlns="http://www.w3.org/2000/svg" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:dm="http://github.com/nikitakit/DM2SVG"> - <metadata> - <dm:page - id="%(id)s" - version="%(version)s" - width="%(width)s" - height="%(height)s" - page_type="%(page_type)s"> - </dm:page> - </metadata> - <rect width="%(width)s" height="%(height)s" fill="aliceblue"/> -''' % locals() - - return height - - -def emit_element(message): - if message: - print '%s\n' % message - - -if __name__ == '__main__': - import sys - - if len(sys.argv) == 2: - process_file(sys.argv[1]) - else: - print >> sys.stderr, 'Usage: %s <dhw-file>' % sys.argv[0] - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/docinfo.inx b/share/extensions/docinfo.inx deleted file mode 100644 index c3d76a960..000000000 --- a/share/extensions/docinfo.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DOC Info</_name> - <id>org.inkscape.docinfo</id> - <dependency type="executable" location="extensions">dpiswitcher.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="action" type="notebook" gui-hidden="true"> - <page name="page_info" _gui-text="Show page info"> - <_param name="d" type="description">Choose this tab if you would like to see page info previously to apply DPI Switcher.</_param> - </page> - </param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Document"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">dpiswitcher.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dots.inx b/share/extensions/dots.inx deleted file mode 100644 index 190418cac..000000000 --- a/share/extensions/dots.inx +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Number Nodes</_name> - <id>org.ekips.filter.dots</id> - <dependency type="executable" location="extensions">dots.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <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> - <submenu _name="Visualize Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">dots.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dots.py b/share/extensions/dots.py deleted file mode 100755 index 296a56dfc..000000000 --- a/share/extensions/dots.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplestyle, simplepath, math - -class Dots(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-d", "--dotsize", - action="store", type="string", - dest="dotsize", default="10px", - help="Size of the dots placed at path nodes") - self.OptionParser.add_option("-f", "--fontsize", - 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 - lastDot = -1 - if p[lastDot][1] == []: lastDot = -2 - if round(p[lastDot][1][-2]) == round(p[0][1][-2]) and \ - round(p[lastDot][1][-1]) == round(p[0][1][-1]): - x1 = p[lastDot][1][-2] - y1 = p[lastDot][1][-1] - x2 = p[lastDot-1][1][-2] - y2 = p[lastDot-1][1][-1] - dx = abs( max(x1,x2) - min(x1,x2) ) - dy = abs( max(y1,y2) - min(y1,y2) ) - dist = math.sqrt( dx**2 + dy**2 ) - x = dx/dist - y = dy/dist - if x1 > x2: x *= -1 - if y1 > y2: y *= -1 - p[lastDot][1][-2] += x * self.unittouu(self.options.dotsize) - p[lastDot][1][-1] += y * self.unittouu(self.options.dotsize) - - 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( self.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] + ( self.unittouu(self.options.dotsize) / 2 ), - params[-1] - ( self.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')) - s = {'font-size': self.unittouu(self.options.fontsize), 'fill-opacity': '1.0', 'stroke': 'none', - 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#999'} - new.set('style', simplestyle.formatStyle(s)) - new.set('x', str(x)) - new.set('y', str(y)) - new.text = str(text) - -if __name__ == '__main__': - e = Dots() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/doxygen-main.dox b/share/extensions/doxygen-main.dox deleted file mode 100644 index 759b0a7e7..000000000 --- a/share/extensions/doxygen-main.dox +++ /dev/null @@ -1,55 +0,0 @@ -/** \mainpage Inkscape Extensions Source Code Documentation - * This documentation contains API documentation for Inkscape extensions. - * - * It describes in more detail common libraries for creating extensions - * and some extensions that are good examples for inspiration. - * - * \section groups Main directory documentation - * - \subpage CommonClasses - Common classes used for writing extensions. - * - \subpage ExampleExtensions - Links to selected extensions. - * - \subpage Testing - How to write tests for extensions. - * - \subpage CommandLine - Command-line usage - * - * \section extlinks Links to external documentation - * - * \subpage ExtensionGuides - Extension guides - */ - -/** - * \page CommonClasses Common classes - * - * \section inkex - * [\ref inkex.py] - * The inkex module exposes the primary interface for writing extensions. - * \subsection effect inkex.Effect - * inkex.Effect is a class from which all extensions are derived. It provides the pipeline that directs the original svg document to the extension, and then reads the resulting svg and inserts it into the document. It also manages effect options, and provides tools for working with them. There are also functions for operating on svgs, converting units, working with guides, writing debug messages to Inkscape's debug window, etc. - * \subsection inkoption inkex.InkOption - * inkex.InkOption is a thin wrapper around optparse that adds the "inkbool" option - * - * \section simplepath - * [\ref simplepath.py] - * - * Utility module for working with paths - * - parse and serialize svg paths - * - transform paths - * - * \section simpletransform - * [\ref simpletransform.py] - * - * Utility module for working with transforms - * - matrices - * - points - * - bounding boxes - * - * \section simplestyle - * [\ref simplestyle.py] - * - * Utility module for working with styles - * - parse and serialize stylesheets - * - parse and format colors - */ -/** \page ExtensionGuides Extension writing guides on the wiki - * - <a href="http://wiki.inkscape.org/wiki/index.php/Script_extensions">Script_extensions</a> - * - <a href="http://wiki.inkscape.org/wiki/index.php/PythonEffectTutorial">PythonEffectTutorial</a> - * - <a href="http://wiki.inkscape.org/wiki/index.php/Category:Developer_Documentation">Category Developer_Documentation</a> - */
\ No newline at end of file diff --git a/share/extensions/dpi90to96.inx b/share/extensions/dpi90to96.inx deleted file mode 100644 index e7ad4a895..000000000 --- a/share/extensions/dpi90to96.inx +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DPI 90 to 96</_name> - <id>org.inkscape.dpi90to96</id> - <dependency type="executable" location="extensions">dpiswitcher.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="action" type="notebook" gui-hidden="true"> - <page name="dpi_swicher" > - <param name="switcher" type="enum" gui-hidden="true"> - <item value="0">DPI Switch from 90 to 96</item> - </param> - </page> - </param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Document"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">dpiswitcher.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dpi96to90.inx b/share/extensions/dpi96to90.inx deleted file mode 100644 index 11d1cb40b..000000000 --- a/share/extensions/dpi96to90.inx +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DPI 96 to 90</_name> - <id>org.inkscape.dpi96to90</id> - <dependency type="executable" location="extensions">dpiswitcher.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="action" type="notebook" gui-hidden="true"> - <page name="dpi_swicher" > - <param name="switcher" type="enum" gui-hidden="true"> - <item value="1">DPI Switch from 96 to 90</item> - </param> - </page> - </param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Document"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">dpiswitcher.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dpiswitcher.py b/share/extensions/dpiswitcher.py deleted file mode 100755 index 7d9f16001..000000000 --- a/share/extensions/dpiswitcher.py +++ /dev/null @@ -1,425 +0,0 @@ -#!/usr/bin/env python -''' -This extension scales a document to fit different SVG DPI -90/96- - -Copyright (C) 2012 Jabiertxo Arraiza, jabier.arraiza@marker.es -Copyright (C) 2016 su_v, <suv-sf@users.sf.net> - -Version 0.6 - DPI Switcher - -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 since v0.5: - - transform all top-level containers and graphics elements - - support scientific notation in SVG lengths - - fix scaling with existing matrix() (use functions from simpletransform.py) - - support different units for document width, height attributes - - improve viewBox support (syntax, offset) - - support common cases of text-put-on-path in SVG root - - support common cases of <use> references in SVG root - - examples from http://tavmjong.free.fr/INKSCAPE/UNITS/ tested - -TODO: - - check grids/guides created with 0.91: - http://tavmjong.free.fr/INKSCAPE/UNITS/units_mm_nv_90dpi.svg - - check <symbol> instances - - check more <use> and text-on-path cases (reverse scaling needed?) - - scale perspective of 3dboxes - -''' -# standard libraries -import sys -import re -import string -import math -from lxml import etree -# local libraries -import inkex -import simpletransform -import simplestyle - - -# globals -SKIP_CONTAINERS = [ - 'defs', - 'glyph', - 'marker', - 'mask', - 'missing-glyph', - 'pattern', - 'symbol', -] -CONTAINER_ELEMENTS = [ - 'a', - 'g', - 'switch', -] -GRAPHICS_ELEMENTS = [ - 'circle', - 'ellipse', - 'image', - 'line', - 'path', - 'polygon', - 'polyline', - 'rect', - 'text', - 'use', -] - -def is_3dbox(element): - """Check whether element is an Inkscape 3dbox type.""" - return element.get(inkex.addNS('type', 'sodipodi')) == 'inkscape:box3d' - - -def is_use(element): - """Check whether element is of type <text>.""" - return element.tag == inkex.addNS('use', 'svg') - - -def is_text(element): - """Check whether element is of type <text>.""" - return element.tag == inkex.addNS('text', 'svg') - - -def is_text_on_path(element): - """Check whether text element is put on a path.""" - if is_text(element): - text_path = element.find(inkex.addNS('textPath', 'svg')) - if text_path is not None and len(text_path): - return True - return False - - -def is_sibling(element1, element2): - """Check whether element1 and element2 are siblings of same parent.""" - return element2 in element1.getparent() - - -def is_in_defs(doc, element): - """Check whether element is in defs.""" - if element is not None: - defs = doc.find('defs', namespaces=inkex.NSS) - if defs is not None: - return linked_node in defs.iterdescendants() - return False - - -def get_linked(doc, element): - """Return linked element or None.""" - if element is not None: - href = element.get(inkex.addNS('href', 'xlink'), None) - if href is not None: - linked_id = href[href.find('#')+1:] - path = '//*[@id="%s"]' % linked_id - el_list = doc.xpath(path, namespaces=inkex.NSS) - if isinstance(el_list, list) and len(el_list): - return el_list[0] - else: - return None - - -def check_3dbox(svg, element, scale_x, scale_y): - """Check transformation for 3dbox element.""" - skip = False - if skip: - # 3dbox elements ignore preserved transforms - # FIXME: manually update geometry of 3dbox? - pass - return skip - - -def check_text_on_path(svg, element, scale_x, scale_y): - """Check whether to skip scaling a text put on a path.""" - skip = False - path = get_linked(svg, element.find(inkex.addNS('textPath', 'svg'))) - if not is_in_defs(svg, path): - if is_sibling(element, path): - # skip common element scaling if both text and path are siblings - skip = True - # scale offset - if 'transform' in element.attrib: - mat = simpletransform.parseTransform(element.get('transform')) - mat[0][2] *= scale_x - mat[1][2] *= scale_y - element.set('transform', simpletransform.formatTransform(mat)) - # scale font size - mat = simpletransform.parseTransform( - 'scale({},{})'.format(scale_x, scale_y)) - det = abs(mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0]) - descrim = math.sqrt(abs(det)) - prop = 'font-size' - # outer text - sdict = simplestyle.parseStyle(element.get('style')) - if prop in sdict: - sdict[prop] = float(sdict[prop]) * descrim - element.set('style', simplestyle.formatStyle(sdict)) - # inner tspans - for child in element.iterdescendants(): - if child.tag == inkex.addNS('tspan', 'svg'): - sdict = simplestyle.parseStyle(child.get('style')) - if prop in sdict: - sdict[prop] = float(sdict[prop]) * descrim - child.set('style', simplestyle.formatStyle(sdict)) - return skip - - -def check_use(svg, element, scale_x, scale_y): - """Check whether to skip scaling an instantiated element (<use>).""" - skip = False - path = get_linked(svg, element) - if not is_in_defs(svg, path): - if is_sibling(element, path): - skip = True - # scale offset - if 'transform' in element.attrib: - mat = simpletransform.parseTransform(element.get('transform')) - mat[0][2] *= scale_x - mat[1][2] *= scale_y - element.set('transform', simpletransform.formatTransform(mat)) - return skip - - -class DPISwitcher(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--switcher", action="store", - type="string", dest="switcher", default="0", - help="Select the DPI switch you want") - self.OptionParser.add_option("--action", action="store", - type="string", dest="action", - default=None, help="") - self.factor_a = 90.0/96.0 - self.factor_b = 96.0/90.0 - self.units = "px" - self.unitExponent = 1.0 - - # dictionaries of unit to user unit conversion factors - __uuconvLegacy = { - 'in': 90.0, - 'pt': 1.25, - 'px': 1.0, - 'mm': 3.5433070866, - 'cm': 35.433070866, - 'm': 3543.3070866, - 'km': 3543307.0866, - 'pc': 15.0, - 'yd': 3240.0, - 'ft': 1080.0, - } - __uuconv = { - 'in': 96.0, - 'pt': 1.33333333333, - 'px': 1.0, - 'mm': 3.77952755913, - 'cm': 37.7952755913, - 'm': 3779.52755913, - 'km': 3779527.55913, - 'pc': 16.0, - 'yd': 3456.0, - 'ft': 1152.0, - } - - def parse_length(self, length, percent=False): - """Parse SVG length.""" - if self.options.switcher == "0": # dpi90to96 - known_units = self.__uuconvLegacy.keys() - else: # dpi96to90 - known_units = self.__uuconv.keys() - if percent: - unitmatch = re.compile('(%s)$' % '|'.join(known_units + ['%'])) - else: - unitmatch = re.compile('(%s)$' % '|'.join(known_units)) - param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - p = param.match(length) - u = unitmatch.search(length) - val = 100 # fallback: assume default length of 100 - unit = 'px' # fallback: assume 'px' unit - if p: - val = float(p.string[p.start():p.end()]) - if u: - unit = u.string[u.start():u.end()] - return (val, unit) - - def convert_length(self, val, unit): - """Convert length to self.units if unit differs.""" - doc_unit = self.units or 'px' - if unit != doc_unit: - if self.options.switcher == "0": # dpi90to96 - val_px = val * self.__uuconvLegacy[unit] - val = val_px / (self.__uuconvLegacy[doc_unit] / self.__uuconvLegacy['px']) - unit = doc_unit - else: # dpi96to90 - val_px = val * self.__uuconv[unit] - val = val_px / (self.__uuconv[doc_unit] / self.__uuconv['px']) - unit = doc_unit - return (val, unit) - - def check_attr_unit(self, element, attr, unit_list): - """Check unit of attribute value, match to units in *unit_list*.""" - if attr in element.attrib: - unit = self.parse_length(element.get(attr), percent=True)[1] - return unit in unit_list - - def scale_attr_val(self, element, attr, unit_list, factor): - """Scale attribute value if unit matches one in *unit_list*.""" - if attr in element.attrib: - val, unit = self.parse_length(element.get(attr), percent=True) - if unit in unit_list: - element.set(attr, '{}{}'.format(val * factor, unit)) - - def scaleRoot(self, svg): - """Scale all top-level elements in SVG root.""" - - # update viewport - widthNumber = self.parse_length(svg.get('width'))[0] - heightNumber = self.convert_length(*self.parse_length(svg.get('height')))[0] - widthDoc = widthNumber * self.factor_a * self.unitExponent - heightDoc = heightNumber * self.factor_a * self.unitExponent - - if svg.get('height'): - svg.set('height', str(heightDoc)) - if svg.get('width'): - svg.set('width', str(widthDoc)) - - # update viewBox - if svg.get('viewBox'): - viewboxstring = re.sub(' +|, +|,',' ', svg.get('viewBox')) - viewboxlist = [float(i) for i in viewboxstring.strip().split(' ', 4)] - svg.set('viewBox','{} {} {} {}'.format(*[(val * self.factor_a) for val in viewboxlist])) - - # update guides, grids - if self.options.switcher == "1": - # FIXME: dpi96to90 only? - self.scaleGuides(svg) - self.scaleGrid(svg) - - for element in svg: # iterate all top-level elements of SVGRoot - - # init variables - tag = etree.QName(element).localname - width_scale = self.factor_a - height_scale = self.factor_a - - if tag in GRAPHICS_ELEMENTS or tag in CONTAINER_ELEMENTS: - - # test for specific elements to skip from scaling - if is_3dbox(element): - if check_3dbox(svg, element, width_scale, height_scale): - continue - if is_text_on_path(element): - if check_text_on_path(svg, element, width_scale, height_scale): - continue - if is_use(element): - if check_use(svg, element, width_scale, height_scale): - continue - - # relative units ('%') in presentation attributes - for attr in ['width', 'height']: - self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) - for attr in ['x', 'y']: - self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) - - # set preserved transforms on top-level elements - if width_scale != 1.0 and height_scale != 1.0: - mat = simpletransform.parseTransform( - 'scale({},{})'.format(width_scale, height_scale)) - simpletransform.applyTransformToNode(mat, element) - - def scaleElement(self, m): - pass # TODO: optionally scale graphics elements only? - - def scaleGuides(self, svg): - xpathStr = '//sodipodi:guide' - guides = svg.xpath(xpathStr, namespaces=inkex.NSS) - for guide in guides: - point = string.split(guide.get("position"), ",") - guide.set("position", str(float(point[0].strip()) * self.factor_a ) + "," + str(float(point[1].strip()) * self.factor_a )) - - def scaleGrid(self, svg): - xpathStr = '//inkscape:grid' - grids = svg.xpath(xpathStr, namespaces=inkex.NSS) - for grid in grids: - grid.set("units", "px") - if grid.get("spacingx"): - spacingx = str(float(re.sub("[a-zA-Z]", "", grid.get("spacingx"))) * self.factor_a) + "px" - grid.set("spacingx", str(spacingx)) - if grid.get("spacingy"): - spacingy = str(float(re.sub("[a-zA-Z]", "", grid.get("spacingy"))) * self.factor_a) + "px" - grid.set("spacingy", str(spacingy)) - if grid.get("originx"): - originx = str(float(re.sub("[a-zA-Z]", "", grid.get("originx"))) * self.factor_a) + "px" - grid.set("originx", str(originx)) - if grid.get("originy"): - originy = str(float(re.sub("[a-zA-Z]", "", grid.get("originy"))) * self.factor_a) + "px" - grid.set("originy", str(originy)) - - def effect(self): - saveout = sys.stdout - sys.stdout = sys.stderr - svg = self.document.getroot() - if self.options.action == '"page_info"': - print ":::SVG document related info:::" - print "version: " + str(svg.get(inkex.addNS('version',u'inkscape'))) - width = svg.get('width') - if width: - print "width: " + width - height = svg.get('height') - if height: - print "height: " + height - viewBox = svg.get('viewBox') - if viewBox: - print "viewBox: " + viewBox - namedview = svg.find(inkex.addNS('namedview', 'sodipodi')) - docunits= namedview.get(inkex.addNS('document-units', 'inkscape')) - if docunits: - print "document-units: " + docunits - units = namedview.get('units') - if units: - print "units: " + units - xpathStr = '//sodipodi:guide' - guides = svg.xpath(xpathStr, namespaces=inkex.NSS) - xpathStr = '//inkscape:grid' - if guides: - numberGuides = len(guides) - print "Document has " + str(numberGuides) + " guides" - grids = svg.xpath(xpathStr, namespaces=inkex.NSS) - i = 1 - for grid in grids: - print "Grid number " + str(i) + ": Units: " + grid.get("units") - i = i+1 - else: - if self.options.switcher == "0": - self.factor_a = 96.0/90.0 - self.factor_b = 90.0/96.0 - namedview = svg.find(inkex.addNS('namedview', 'sodipodi')) - namedview.set(inkex.addNS('document-units', 'inkscape'), "px") - self.units = self.parse_length(svg.get('width'))[1] - if self.units and self.units <> "px" and self.units <> "" and self.units <> "%": - if self.options.switcher == "0": - self.unitExponent = 1.0/(self.factor_a/self.__uuconv[self.units]) - else: - self.unitExponent = 1.0/(self.factor_a/self.__uuconvLegacy[self.units]) - self.scaleRoot(svg); - sys.stdout = saveout - - -if __name__ == '__main__': - effect = DPISwitcher() - effect.affect() - -# 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 deleted file mode 100644 index 5c645bf26..000000000 --- a/share/extensions/draw_from_triangle.inx +++ /dev/null @@ -1,78 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Draw From Triangle</_name> - <id>il.fromtriangle</id> - <dependency type="executable" location="extensions">draw_from_triangle.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="common1" _gui-text="Common Objects"> - <param name="circumcircle" type="boolean" _gui-text="Circumcircle"></param> - <param name="circumcentre" type="boolean" _gui-text="Circumcentre"></param> - <param name="incircle" type="boolean" _gui-text="Incircle"></param> - <param name="incentre" type="boolean" _gui-text="Incentre"></param> - <param name="contact_tri" type="boolean" _gui-text="Contact Triangle"></param> - <param name="excircles" type="boolean" _gui-text="Excircles"></param> - <param name="excentres" type="boolean" _gui-text="Excentres"></param> - <param name="extouch_tri" type="boolean" _gui-text="Extouch Triangle"></param> - <param name="excentral_tri" type="boolean" _gui-text="Excentral Triangle"></param> - <param name="orthocentre" type="boolean" _gui-text="Orthocentre"></param> - <param name="orthic_tri" type="boolean" _gui-text="Orthic Triangle"></param> - <param name="altitudes" type="boolean" _gui-text="Altitudes"></param> - <param name="anglebisectors" type="boolean" _gui-text="Angle Bisectors"></param> - <param name="centroid" type="boolean" _gui-text="Centroid"></param> - <param name="ninepointcentre" type="boolean" _gui-text="Nine-Point Centre"></param> - <param name="ninepointcircle" type="boolean" _gui-text="Nine-Point Circle"></param> - <param name="symmedians" type="boolean" _gui-text="Symmedians"></param> - <param name="sym_point" type="boolean" _gui-text="Symmedian Point"></param> - <param name="sym_tri" type="boolean" _gui-text="Symmedial Triangle"></param> - <param name="gergonne_pt" type="boolean" _gui-text="Gergonne Point"></param> - <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="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_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="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> - </page> - <page name="Help" _gui-text="Help"> - <_param name="instructions" type="description" xml:space="preserve">This extension draws constructions about a triangle defined by the first 3 nodes of a selected path. You may select one of preset objects or create your own ones. - -All units are the Inkscape's pixel unit. Angles are all in radians. -You can specify a point by trilinear coordinates or by a triangle centre function. -Enter as functions of the side length or angles. -Trilinear elements should be separated by a colon: ':'. -Side lengths are represented as 's_a', 's_b' and 's_c'. -Angles corresponding to these are 'a_a', 'a_b', and 'a_c'. -You can also use the semi-perimeter and area of the triangle as constants. Write 'area' or 'semiperim' for these. - -You can use any standard Python math function: -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); -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) - -Also available are the inverse trigonometric functions: -sec(x); csc(x); cot(x) - -You can specify the radius of a circle around a custom point using a formula, which may also contain the side lengths, angles, etc. You can also plot the isogonal and isotomic conjugate of the point. Be aware that this may cause a divide-by-zero error for certain points. - </_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">draw_from_triangle.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/draw_from_triangle.py b/share/extensions/draw_from_triangle.py deleted file mode 100755 index fd966b1d1..000000000 --- a/share/extensions/draw_from_triangle.py +++ /dev/null @@ -1,479 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Beard john.j.beard@gmail.com - -##This extension allows you to draw various triangle constructions -##It requires a path to be selected -##It will use the first three nodes of this path - -## Dimensions of a triangle__ -# -# /`__ -# / a_c``--__ -# / ``--__ s_a -# s_b / ``--__ -# /a_a a_b`--__ -# /--------------------------------``B -# A s_b - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import sys -from math import * -# local library -import inkex -import simplestyle -import simplepath - - -#DRAWING ROUTINES - -#draw an SVG triangle given in trilinar coords -def draw_SVG_circle(rad, centre, params, style, name, parent):#draw an SVG circle with a given radius as trilinear coordinates - if rad == 0: #we want a dot - r = style.d_rad #get the dot width from the style - circ_style = { 'stroke':style.d_col, 'stroke-width':str(style.d_th), 'fill':style.d_fill } - else: - r = rad #use given value - circ_style = { 'stroke':style.c_col, 'stroke-width':str(style.c_th), 'fill':style.c_fill } - - cx,cy = get_cartesian_pt(centre, params) - circ_attribs = {'style':simplestyle.formatStyle(circ_style), - inkex.addNS('label','inkscape'):name, - 'cx':str(cx), 'cy':str(cy), - 'r':str(r)} - inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs ) - -#draw an SVG triangle given in trilinar coords -def draw_SVG_tri(vert_mat, params, style, name, parent): - p1,p2,p3 = get_cartesian_tri(vert_mat, params) #get the vertex matrix in cartesian points - tri_style = { 'stroke': style.l_col, 'stroke-width':str(style.l_th), 'fill': style.l_fill } - tri_attribs = {'style':simplestyle.formatStyle(tri_style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(p1[0])+','+str(p1[1])+ - ' L '+str(p2[0])+','+str(p2[1])+ - ' L '+str(p3[0])+','+str(p3[1])+ - ' L '+str(p1[0])+','+str(p1[1])+' z'} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs ) - -#draw an SVG line segment between the given (raw) points -def draw_SVG_line( (x1, y1), (x2, y2), style, name, parent): - line_style = { 'stroke': style.l_col, 'stroke-width':str(style.l_th), 'fill': style.l_fill } - line_attribs = {'style':simplestyle.formatStyle(line_style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -#lines from each vertex to a corresponding point in trilinears -def draw_vertex_lines( vert_mat, params, width, name, parent): - for i in range(3): - oppositepoint = get_cartesian_pt( vert_mat[i], params) - draw_SVG_line(params[3][-i%3], oppositepoint, width, name+':'+str(i), parent) - -#MATHEMATICAL ROUTINES - -def distance( (x0,y0),(x1,y1)):#find the pythagorean distance - return sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ) - -def vector_from_to( (x0,y0),(x1,y1) ):#get the vector from (x0,y0) to (x1,y1) - return (x1-x0, y1-y0) - -def get_cartesian_pt( t, p):#get the cartesian coordinates from a trilinear set - denom = p[0][0]*t[0] + p[0][1]*t[1] + p[0][2]*t[2] - c1 = p[0][1]*t[1]/denom - c2 = p[0][2]*t[2]/denom - return ( c1*p[2][1][0]+c2*p[2][0][0], c1*p[2][1][1]+c2*p[2][0][1] ) - -def get_cartesian_tri( ((t11,t12,t13),(t21,t22,t23),(t31,t32,t33)), params):#get the cartesian points from a trilinear vertex matrix - p1=get_cartesian_pt( (t11,t12,t13), params ) - p2=get_cartesian_pt( (t21,t22,t23), params ) - p3=get_cartesian_pt( (t31,t32,t33), params ) - return (p1,p2,p3) - -def angle_from_3_sides(a, b, c): #return the angle opposite side c - cosx = (a*a + b*b - c*c)/(2*a*b) #use the cosine rule - return acos(cosx) - -def translate_string(string, os): #translates s_a, a_a, etc to params[x][y], with cyclic offset - string = string.replace('s_a', 'params[0]['+str((os+0)%3)+']') #replace with ref. to the relvant values, - string = string.replace('s_b', 'params[0]['+str((os+1)%3)+']') #cycled by i - string = string.replace('s_c', 'params[0]['+str((os+2)%3)+']') - string = string.replace('a_a', 'params[1]['+str((os+0)%3)+']') - string = string.replace('a_b', 'params[1]['+str((os+1)%3)+']') - string = string.replace('a_c', 'params[1]['+str((os+2)%3)+']') - string = string.replace('area','params[4][0]') - string = string.replace('semiperim','params[4][1]') - return string - -def pt_from_tcf( tcf , params):#returns a trilinear triplet from a triangle centre function - trilin_pts=[]#will hold the final points - for i in range(3): - temp = tcf #read in the tcf - temp = translate_string(temp, i) - func = eval('lambda params: ' + temp.strip('"')) #the function leading to the trilinar element - trilin_pts.append(func(params))#evaluate the function for the first trilinear element - return trilin_pts - -#SVG DATA PROCESSING - -def get_n_points_from_path( node, n):#returns a list of first n points (x,y) in an SVG path-representing node - - p = simplepath.parsePath(node.get('d')) #parse the path - - xi = [] #temporary storage for x and y (will combine at end) - yi = [] - - for cmd,params in p: #a parsed path is made up of (cmd, params) pairs - defs = simplepath.pathdefs[cmd] - for i in range(defs[1]): - if defs[3][i] == 'x' and len(xi) < n:#only collect the first three - xi.append(params[i]) - elif defs[3][i] == 'y' and len(yi) < n:#only collect the first three - yi.append(params[i]) - - if len(xi) == n and len(yi) == n: - points = [] # returned pairs of points - for i in range(n): - points.append( [ xi[i], yi[i] ] ) - else: - #inkex.errormsg(_('Error: Not enough nodes to gather coordinates.')) #fail silently and exit, rather than invoke an error console - return [] #return a blank - - return points - -#EXTRA MATHS FUNCTIONS -def sec(x):#secant(x) - if x == pi/2 or x==-pi/2 or x == 3*pi/2 or x == -3*pi/2: #sec(x) is undefined - return 100000000000 - else: - return 1/cos(x) - -def csc(x):#cosecant(x) - if x == 0 or x==pi or x==2*pi or x==-2*pi: #csc(x) is undefined - return 100000000000 - else: - return 1/sin(x) - -def cot(x):#cotangent(x) - if x == 0 or x==pi or x==2*pi or x==-2*pi: #cot(x) is undefined - return 100000000000 - else: - return 1/tan(x) - -def report_properties( params ):#report to the Inkscape console using errormsg - # TODO: unit identifier needs solution for arbitrary document scale - unit = Draw_From_Triangle.getDocumentUnit(e) - - inkex.errormsg(_("Side Length 'a' ({0}): {1}").format(unit, str(params[0][0])) ) - inkex.errormsg(_("Side Length 'b' ({0}): {1}").format(unit, str(params[0][1])) ) - inkex.errormsg(_("Side Length 'c' ({0}): {1}").format(unit, str(params[0][2])) ) - inkex.errormsg(_("Angle 'A' (radians): {}").format(str(params[1][0])) ) - inkex.errormsg(_("Angle 'B' (radians): {}").format(str(params[1][1])) ) - inkex.errormsg(_("Angle 'C' (radians): {}").format(params[1][2]) ) - inkex.errormsg(_("Semiperimeter (px): {}").format(params[4][1]) ) - inkex.errormsg(_("Area ({0}^2): {1}").format(unit, str(params[4][0])) ) - return - - -class Style(object): #container for style information - def __init__(self, options): - #dot markers - self.d_rad = Draw_From_Triangle.unittouu(e, '4px') #dot marker radius - self.d_th = Draw_From_Triangle.unittouu(e, '2px') #stroke width - self.d_fill= '#aaaaaa' #fill colour - self.d_col = '#000000' #stroke colour - - #lines - self.l_th = Draw_From_Triangle.unittouu(e, '2px') - self.l_fill= 'none' - self.l_col = '#000000' - - #circles - self.c_th = Draw_From_Triangle.unittouu(e, '2px') - self.c_fill= 'none' - self.c_col = '#000000' - -class Draw_From_Triangle(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", default="sampling", - help="The selected UI-tab when OK was pressed") -#PRESET POINT OPTIONS - self.OptionParser.add_option("--circumcircle", - action="store", type="inkbool", - dest="do_circumcircle", default=False) - self.OptionParser.add_option("--circumcentre", - action="store", type="inkbool", - dest="do_circumcentre", default=False) - self.OptionParser.add_option("--incircle", - action="store", type="inkbool", - dest="do_incircle", default=False) - self.OptionParser.add_option("--incentre", - action="store", type="inkbool", - dest="do_incentre", default=False) - self.OptionParser.add_option("--contact_tri", - action="store", type="inkbool", - dest="do_contact_tri", default=False) - self.OptionParser.add_option("--excircles", - action="store", type="inkbool", - dest="do_excircles", default=False) - self.OptionParser.add_option("--excentres", - action="store", type="inkbool", - dest="do_excentres", default=False) - self.OptionParser.add_option("--extouch_tri", - action="store", type="inkbool", - dest="do_extouch_tri", default=False) - self.OptionParser.add_option("--excentral_tri", - action="store", type="inkbool", - dest="do_excentral_tri", default=False) - self.OptionParser.add_option("--orthocentre", - action="store", type="inkbool", - dest="do_orthocentre", default=False) - self.OptionParser.add_option("--orthic_tri", - action="store", type="inkbool", - dest="do_orthic_tri", default=False) - self.OptionParser.add_option("--altitudes", - action="store", type="inkbool", - dest="do_altitudes", default=False) - self.OptionParser.add_option("--anglebisectors", - action="store", type="inkbool", - dest="do_anglebisectors", default=False) - self.OptionParser.add_option("--centroid", - action="store", type="inkbool", - dest="do_centroid", default=False) - self.OptionParser.add_option("--ninepointcentre", - action="store", type="inkbool", - dest="do_ninepointcentre", default=False) - self.OptionParser.add_option("--ninepointcircle", - action="store", type="inkbool", - dest="do_ninepointcircle", default=False) - self.OptionParser.add_option("--symmedians", - action="store", type="inkbool", - dest="do_symmedians", default=False) - self.OptionParser.add_option("--sym_point", - action="store", type="inkbool", - dest="do_sym_pt", default=False) - self.OptionParser.add_option("--sym_tri", - action="store", type="inkbool", - dest="do_sym_tri", default=False) - self.OptionParser.add_option("--gergonne_pt", - action="store", type="inkbool", - dest="do_gergonne_pt", default=False) - self.OptionParser.add_option("--nagel_pt", - action="store", type="inkbool", - dest="do_nagel_pt", default=False) -#CUSTOM POINT OPTIONS - self.OptionParser.add_option("--mode", - action="store", type="string", - dest="mode", default='trilin') - self.OptionParser.add_option("--cust_str", - action="store", type="string", - dest="cust_str", default='s_a') - self.OptionParser.add_option("--cust_pt", - action="store", type="inkbool", - dest="do_cust_pt", default=False) - self.OptionParser.add_option("--cust_radius", - action="store", type="inkbool", - dest="do_cust_radius", default=False) - self.OptionParser.add_option("--radius", - action="store", type="string", - dest="radius", default='s_a') - self.OptionParser.add_option("--isogonal_conj", - action="store", type="inkbool", - dest="do_isogonal_conj", default=False) - self.OptionParser.add_option("--isotomic_conj", - action="store", type="inkbool", - dest="do_isotomic_conj", default=False) - self.OptionParser.add_option("--report", - action="store", type="inkbool", - dest="report", default=False) - - - def effect(self): - - so = self.options #shorthand - - pts = [] #initialise in case nothing is selected and following loop is not executed - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - pts = get_n_points_from_path( node, 3 ) #find the (x,y) coordinates of the first 3 points of the path - - - if len(pts) == 3: #if we have right number of nodes, else skip and end program - st = Style(so)#style for dots, lines and circles - - #CREATE A GROUP TO HOLD ALL GENERATED ELEMENTS IN - #Hold relative to point A (pt[0]) - group_translation = 'translate(' + str( pts[0][0] ) + ','+ str( pts[0][1] ) + ')' - group_attribs = {inkex.addNS('label','inkscape'):'TriangleElements', - 'transform':group_translation } - layer = inkex.etree.SubElement(self.current_layer, 'g', group_attribs) - - #GET METRICS OF THE TRIANGLE - #vertices in the local coordinates (set pt[0] to be the origin) - vtx = [[0,0], - [pts[1][0]-pts[0][0],pts[1][1]-pts[0][1]], - [pts[2][0]-pts[0][0],pts[2][1]-pts[0][1]]] - - s_a = distance(vtx[1],vtx[2])#get the scalar side lengths - s_b = distance(vtx[0],vtx[1]) - s_c = distance(vtx[0],vtx[2]) - sides=(s_a,s_b,s_c)#side list for passing to functions easily and for indexing - - a_a = angle_from_3_sides(s_b, s_c, s_a)#angles in radians - a_b = angle_from_3_sides(s_a, s_c, s_b) - a_c = angle_from_3_sides(s_a, s_b, s_c) - angles=(a_a,a_b,a_c) - - ab = vector_from_to(vtx[0], vtx[1]) #vector from a to b - ac = vector_from_to(vtx[0], vtx[2]) #vector from a to c - bc = vector_from_to(vtx[1], vtx[2]) #vector from b to c - vecs= (ab,ac) # vectors for finding cartesian point from trilinears - - semiperim = (s_a+s_b+s_c)/2.0 #semiperimeter - area = sqrt( semiperim*(semiperim-s_a)*(semiperim-s_b)*(semiperim-s_c) ) #area of the triangle by heron's formula - uvals = (area, semiperim) #useful values - - params = (sides, angles, vecs, vtx, uvals) #all useful triangle parameters in one object - - if so.report: - report_properties( params ) - - #BEGIN DRAWING - if so.do_circumcentre or so.do_circumcircle: - r = s_a*s_b*s_c/(4*area) - pt = (cos(a_a),cos(a_b),cos(a_c)) - if so.do_circumcentre: - draw_SVG_circle(0, pt, params, st, 'Circumcentre', layer) - if so.do_circumcircle: - draw_SVG_circle(r, pt, params, st, 'Circumcircle', layer) - - if so.do_incentre or so.do_incircle: - pt = [1,1,1] - if so.do_incentre: - draw_SVG_circle(0, pt, params, st, 'Incentre', layer) - if so.do_incircle: - r = area/semiperim - draw_SVG_circle(r, pt, params, st, 'Incircle', layer) - - if so.do_contact_tri: - t1 = s_b*s_c/(-s_a+s_b+s_c) - t2 = s_a*s_c/( s_a-s_b+s_c) - t3 = s_a*s_b/( s_a+s_b-s_c) - v_mat = ( (0,t2,t3),(t1,0,t3),(t1,t2,0)) - draw_SVG_tri(v_mat, params, st,'ContactTriangle',layer) - - if so.do_extouch_tri: - t1 = (-s_a+s_b+s_c)/s_a - t2 = ( s_a-s_b+s_c)/s_b - t3 = ( s_a+s_b-s_c)/s_c - v_mat = ( (0,t2,t3),(t1,0,t3),(t1,t2,0)) - draw_SVG_tri(v_mat, params, st,'ExtouchTriangle',layer) - - if so.do_orthocentre: - pt = pt_from_tcf('cos(a_b)*cos(a_c)', params) - draw_SVG_circle(0, pt, params, st, 'Orthocentre', layer) - - if so.do_orthic_tri: - v_mat = [[0,sec(a_b),sec(a_c)],[sec(a_a),0,sec(a_c)],[sec(a_a),sec(a_b),0]] - draw_SVG_tri(v_mat, params, st,'OrthicTriangle',layer) - - if so.do_centroid: - pt = [1/s_a,1/s_b,1/s_c] - draw_SVG_circle(0, pt, params, st, 'Centroid', layer) - - if so.do_ninepointcentre or so.do_ninepointcircle: - pt = [cos(a_b-a_c),cos(a_c-a_a),cos(a_a-a_b)] - if so.do_ninepointcentre: - draw_SVG_circle(0, pt, params, st, 'NinePointCentre', layer) - if so.do_ninepointcircle: - r = s_a*s_b*s_c/(8*area) - draw_SVG_circle(r, pt, params, st, 'NinePointCircle', layer) - - if so.do_altitudes: - v_mat = [[0,sec(a_b),sec(a_c)],[sec(a_a),0,sec(a_c)],[sec(a_a),sec(a_b),0]] - draw_vertex_lines( v_mat, params, st, 'Altitude', layer) - - if so.do_anglebisectors: - v_mat = ((0,1,1),(1,0,1),(1,1,0)) - draw_vertex_lines(v_mat,params, st, 'AngleBisectors', layer) - - if so.do_excircles or so.do_excentres or so.do_excentral_tri: - v_mat = ((-1,1,1),(1,-1,1),(1,1,-1)) - if so.do_excentral_tri: - draw_SVG_tri(v_mat, params, st,'ExcentralTriangle',layer) - for i in range(3): - if so.do_excircles: - r = area/(semiperim-sides[i]) - draw_SVG_circle(r, v_mat[i], params, st, 'Excircle:'+str(i), layer) - if so.do_excentres: - draw_SVG_circle(0, v_mat[i], params, st, 'Excentre:'+str(i), layer) - - if so.do_sym_tri or so.do_symmedians: - v_mat = ((0,s_b,s_c), (s_a, 0, s_c), (s_a, s_b, 0)) - if so.do_sym_tri: - draw_SVG_tri(v_mat, params, st,'SymmedialTriangle',layer) - if so.do_symmedians: - draw_vertex_lines(v_mat,params, st, 'Symmedian', layer) - - if so.do_sym_pt: - pt = (s_a,s_b,s_c) - draw_SVG_circle(0, pt, params, st, 'SymmmedianPoint', layer) - - if so.do_gergonne_pt: - pt = pt_from_tcf('1/(s_a*(s_b+s_c-s_a))', params) - draw_SVG_circle(0, pt, params, st, 'GergonnePoint', layer) - - if so.do_nagel_pt: - pt = pt_from_tcf('(s_b+s_c-s_a)/s_a', params) - draw_SVG_circle(0, pt, params, st, 'NagelPoint', layer) - - if so.do_cust_pt or so.do_cust_radius or so.do_isogonal_conj or so.do_isotomic_conj: - pt = []#where we will store the point in trilinears - if so.mode == 'trilin':#if we are receiving from trilinears - for i in range(3): - strings = so.cust_str.split(':')#get split string - strings[i] = translate_string(strings[i],0) - func = eval('lambda params: ' + strings[i].strip('"')) #the function leading to the trilinar element - pt.append(func(params)) #evaluate the function for the trilinear element - else:#we need a triangle function - string = so.cust_str #don't need to translate, as the pt_from_tcf function does that for us - pt = pt_from_tcf(string, params)#get the point from the tcf directly - - if so.do_cust_pt:#draw the point - draw_SVG_circle(0, pt, params, st, 'CustomTrilinearPoint', layer) - if so.do_cust_radius:#draw the circle with given radius - strings = translate_string(so.radius,0) - func = eval('lambda params: ' + strings.strip('"')) #the function leading to the radius - r = func(params) - draw_SVG_circle(r, pt, params, st, 'CustomTrilinearCircle', layer) - if so.do_isogonal_conj: - isogonal=[0,0,0] - for i in range (3): - isogonal[i] = 1/pt[i] - draw_SVG_circle(0, isogonal, params, st, 'CustomIsogonalConjugate', layer) - if so.do_isotomic_conj: - isotomic=[0,0,0] - for i in range (3): - isotomic[i] = 1/( params[0][i]*params[0][i]*pt[i] ) - draw_SVG_circle(0, isotomic, params, st, 'CustomIsotomicConjugate', layer) - - -if __name__ == '__main__': #pragma: no cover - e = Draw_From_Triangle() - e.affect() diff --git a/share/extensions/dxf12_outlines.inx b/share/extensions/dxf12_outlines.inx deleted file mode 100644 index 4b396264c..000000000 --- a/share/extensions/dxf12_outlines.inx +++ /dev/null @@ -1,20 +0,0 @@ -<inkscape-extension> - <_name>Desktop Cutting Plotter R12</_name> - <id>org.ekips.output.dxf12_outlines</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">simpletransform.py</dependency> - <dependency type="executable" location="extensions">cubicsuperpath.py</dependency> - <dependency type="executable" location="extensions">cspsubdiv.py</dependency> - <output> - <extension>.dxf</extension> - <mimetype>image/dxf</mimetype> - <_filetypename>Desktop Cutting Plotter (AutoCAD DXF R12) (*.dxf)</_filetypename> - <_filetypetooltip>DXF R12 Output</_filetypetooltip> - <dataloss>TRUE</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">dxf12_outlines.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/dxf12_outlines.py b/share/extensions/dxf12_outlines.py deleted file mode 100644 index 89d6c3a25..000000000 --- a/share/extensions/dxf12_outlines.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2005,2007 Aaron Spike, aaron@ekips.org -# - template dxf_outlines.dxf added Feb 2008 by Alvin Penner, penner@vaxxine.com -# - layers, transformation, flattening added April 2008 by Bob Cook, bob@bobcookdev.com -# - added support for dxf R12, Nov. 2008 by Switcher -# - brought together to replace ps2edit version 2018 by Martin Owens -# -# 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 inkex, simplepath, cubicsuperpath, cspsubdiv, re - -import simpletransform - -r12_header = ''' 0 -SECTION - 2 -HEADER - 9 -$ACADVER - 1 -AC1009 - 9 -$EXTMIN - 10 - 0 - 20 - 0 - 9 -$EXTMAX - 10 - 8.5 - 20 - 11 - 0 -ENDSEC - 0 -SECTION - 2 -ENTITIES -''' - -r12_footer = ''' 0 -ENDSEC - 0 -EOF''' - -class MyEffect(inkex.Effect): - - def __init__(self): - - inkex.Effect.__init__(self) - self.dxf = '' - self.handle = 255 - self.flatness = 0.1 - - def output(self): - print self.dxf - - def dxf_add(self, str): - self.dxf += str - - def dxf_insert_code(self, code, value): - self.dxf += code + "\n" + value + "\n" - - def dxf_line(self,layer,csp): - self.dxf_insert_code( '0', 'LINE' ) - self.dxf_insert_code( '8', layer ) - ######self.dxf_insert_code( '62', '1' ) #Change the Line Color - self.dxf_insert_code( '10', '%f' % csp[0][0] ) - self.dxf_insert_code( '20', '%f' % csp[0][1] ) - self.dxf_insert_code( '11', '%f' % csp[1][0] ) - self.dxf_insert_code( '21', '%f' % csp[1][1] ) - - def dxf_path_to_lines(self,layer,p): - f = self.flatness - is_flat = 0 - while is_flat < 1: - try: - cspsubdiv.cspsubdiv(p, self.flatness) - is_flat = 1 - except: - f += 0.1 - - for sub in p: - for i in range(len(sub)-1): - self.handle += 1 - s = sub[i] - e = sub[i+1] - self.dxf_line(layer,[s[1],e[1]]) - - def dxf_path_to_point(self,layer,p): - bbox = simpletransform.roughBBox(p) - x = (bbox[0] + bbox[1]) / 2 - y = (bbox[2] + bbox[3]) / 2 - self.dxf_point(layer,x,y) - - def effect(self): - self.dxf_insert_code( '999', '"DXF R12 Output" (www.mydxf.blogspot.com)' ) - self.dxf_add( r12_header ) - - scale = 25.4/90.0 - h = self.unittouu(self.getDocumentHeight()) - - path = '//svg:path' - for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): - - layer = node.getparent().get(inkex.addNS('label','inkscape')) - if layer == None: - layer = 'Layer 1' - - d = node.get('d') - p = cubicsuperpath.parsePath(d) - - t = node.get('transform') - if t != None: - m = simpletransform.parseTransform(t) - simpletransform.applyTransformToPath(m,p) - - m = [[scale,0,0],[0,-scale,h*scale]] - simpletransform.applyTransformToPath(m,p) - - if re.search('drill$',layer,re.I) == None: - #if layer == 'Brackets Drill': - self.dxf_path_to_lines(layer,p) - else: - self.dxf_path_to_point(layer,p) - - self.dxf_add( r12_footer ) - -e = MyEffect() -e.affect() diff --git a/share/extensions/dxf_input.inx b/share/extensions/dxf_input.inx deleted file mode 100644 index 4488774a3..000000000 --- a/share/extensions/dxf_input.inx +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>DXF Input</_name> - <id>org.inkscape.input.dxf</id> - <dependency type="executable" location="extensions">dxf_input.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="options" _gui-text="Options"> - <param name="scalemethod" type="optiongroup" _gui-text="Method of Scaling:"> - <option value="manual">Manual scale</option> - <option value="auto">Automatic scaling to size A4</option> - <option value="file">Read from file</option> - </param> - <param name="scale" type="string" _gui-text="Manual scale factor:">1.0</param> - <param name="xmin" type="string" _gui-text="Manual x-axis origin (mm):">0.0</param> - <param name="ymin" type="string" _gui-text="Manual y-axis origin (mm):">0.0</param> - <param name="gcodetoolspoints" type="boolean" _gui-text="Gcodetools compatible point import">false</param> - <param name="sep1" type="description">-------------------------------------------------------------------------</param> - <param name="encoding" type="enum" _gui-text="Character encoding:"> - <item value="latin_1">Latin 1</item> - <item value="cp1250">CP 1250</item> - <item value="cp1252">CP 1252</item> - <item value="utf_8">UTF 8</item> - </param> - <param name="font" type="string" _gui-text="Text Font:">Arial</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="inputhelp" type="description" xml:space="preserve">- AutoCAD Release 13 and newer. -- for manual scaling, assume dxf drawing is in mm. -- assume svg drawing is in pixels, at 96 dpi. -- scale factor and origin apply only to manual scaling. -- 'Automatic scaling' will fit the width of an A4 page. -- 'Read from file' uses the variable $MEASUREMENT. -- layers are preserved only on File->Open, not Import. -- limited support for BLOCKS, use AutoCAD Explode Blocks instead, if needed.</_param> - </page> - </param> - <input> - <extension>.dxf</extension> - <mimetype>image/x-svgz</mimetype> - <_filetypename>AutoCAD DXF R13 (*.dxf)</_filetypename> - <_filetypetooltip>Import AutoCAD's Document Exchange Format</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">dxf_input.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/dxf_input.py b/share/extensions/dxf_input.py deleted file mode 100755 index 4021ffe6b..000000000 --- a/share/extensions/dxf_input.py +++ /dev/null @@ -1,533 +0,0 @@ -#!/usr/bin/env python -''' -dxf_input.py - input a DXF file >= (AutoCAD Release 13 == AC1012) - -Copyright (C) 2008, 2009 Alvin Penner, penner@vaxxine.com -Copyright (C) 2009 Christian Mayer, inkscape@christianmayer.de -- thanks to Aaron Spike for inkex.py and simplestyle.py -- without which this would not have been possible - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex, simplestyle, math -from StringIO import StringIO -from urllib import quote - - -def export_MTEXT(): - # mandatory group codes : (1 or 3, 10, 20) (text, x, y) - if (vals[groups['1']] or vals[groups['3']]) and vals[groups['10']] and vals[groups['20']]: - x = vals[groups['10']][0] - y = vals[groups['20']][0] - # optional group codes : (21, 40, 50) (direction, text height mm, text angle) - size = 12 # default fontsize in px - if vals[groups['40']] and vals[groups['40']][0]: - size = scale*vals[groups['40']][0] - attribs = {'x': '%f' % x, 'y': '%f' % y, 'style': 'font-size: %.1fpx; fill: %s; font-family: %s' % (size, color, options.font)} - angle = 0 # default angle in degrees - if vals[groups['50']]: - angle = vals[groups['50']][0] - attribs.update({'transform': 'rotate (%f %f %f)' % (-angle, x, y)}) - elif vals[groups['21']]: - if vals[groups['21']][0] == 1.0: - attribs.update({'transform': 'rotate (%f %f %f)' % (-90, x, y)}) - elif vals[groups['21']][0] == -1.0: - attribs.update({'transform': 'rotate (%f %f %f)' % (90, x, y)}) - attribs.update({inkex.addNS('linespacing','sodipodi'): '125%'}) - node = inkex.etree.SubElement(layer, 'text', attribs) - text = '' - if vals[groups['3']]: - for i in range (0, len(vals[groups['3']])): - text += vals[groups['3']][i] - if vals[groups['1']]: - text += vals[groups['1']][0] - found = text.find('\P') # new line - while found > -1: - tspan = inkex.etree.SubElement(node , 'tspan', {inkex.addNS('role','sodipodi'): 'line'}) - tspan.text = text[:found] - text = text[(found+2):] - found = text.find('\P') - tspan = inkex.etree.SubElement(node , 'tspan', {inkex.addNS('role','sodipodi'): 'line'}) - tspan.text = text - -def export_POINT(): - # mandatory group codes : (10, 20) (x, y) - if vals[groups['10']] and vals[groups['20']]: - if options.gcodetoolspoints: - generate_gcodetools_point(vals[groups['10']][0], vals[groups['20']][0]) - else: - generate_ellipse(vals[groups['10']][0], vals[groups['20']][0], w/2, 0.0, 1.0, 0.0, 0.0) - -def export_LINE(): - # mandatory group codes : (10, 11, 20, 21) (x1, x2, y1, y2) - if vals[groups['10']] and vals[groups['11']] and vals[groups['20']] and vals[groups['21']]: - path = 'M %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], scale*(extrude*vals[groups['11']][0] - xmin), height - scale*(vals[groups['21']][0] - ymin)) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def export_SPLINE(): - # see : http://www.mactech.com/articles/develop/issue_25/schneider.html - # mandatory group codes : (10, 20, 40, 70) (x[], y[], knots[], flags) - if vals[groups['70']] and len(vals[groups['10']]) == len(vals[groups['20']]) and vals[groups['10']] and vals[groups['20']] and vals[groups['40']]: - knots = len(vals[groups['40']]) - ctrls = len(vals[groups['10']]) - if ctrls > 3 and knots == ctrls + 4: # cubic - if ctrls > 4: - for i in range (knots - 5, 3, -1): - if vals[groups['40']][i] != vals[groups['40']][i-1] and vals[groups['40']][i] != vals[groups['40']][i+1]: - a0 = (vals[groups['40']][i] - vals[groups['40']][i-2])/(vals[groups['40']][i+1] - vals[groups['40']][i-2]) - a1 = (vals[groups['40']][i] - vals[groups['40']][i-1])/(vals[groups['40']][i+2] - vals[groups['40']][i-1]) - vals[groups['10']].insert(i-1, (1.0 - a1)*vals[groups['10']][i-2] + a1*vals[groups['10']][i-1]) - vals[groups['20']].insert(i-1, (1.0 - a1)*vals[groups['20']][i-2] + a1*vals[groups['20']][i-1]) - vals[groups['10']][i-2] = (1.0 - a0)*vals[groups['10']][i-3] + a0*vals[groups['10']][i-2] - vals[groups['20']][i-2] = (1.0 - a0)*vals[groups['20']][i-3] + a0*vals[groups['20']][i-2] - vals[groups['40']].insert(i, vals[groups['40']][i]) - knots = len(vals[groups['40']]) - for i in range (knots - 6, 3, -2): - if vals[groups['40']][i] != vals[groups['40']][i+2] and vals[groups['40']][i-1] != vals[groups['40']][i+1] and vals[groups['40']][i-2] != vals[groups['40']][i]: - a1 = (vals[groups['40']][i] - vals[groups['40']][i-1])/(vals[groups['40']][i+2] - vals[groups['40']][i-1]) - vals[groups['10']].insert(i-1, (1.0 - a1)*vals[groups['10']][i-2] + a1*vals[groups['10']][i-1]) - vals[groups['20']].insert(i-1, (1.0 - a1)*vals[groups['20']][i-2] + a1*vals[groups['20']][i-1]) - ctrls = len(vals[groups['10']]) - path = 'M %f,%f' % (vals[groups['10']][0], vals[groups['20']][0]) - for i in range (0, (ctrls - 1)/3): - path += ' C %f,%f %f,%f %f,%f' % (vals[groups['10']][3*i + 1], vals[groups['20']][3*i + 1], vals[groups['10']][3*i + 2], vals[groups['20']][3*i + 2], vals[groups['10']][3*i + 3], vals[groups['20']][3*i + 3]) - if vals[groups['70']][0] & 1: # closed path - path += ' z' - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - if ctrls == 3 and knots == 6: # quadratic - path = 'M %f,%f Q %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['10']][1], vals[groups['20']][1], vals[groups['10']][2], vals[groups['20']][2]) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - if ctrls == 5 and knots == 8: # spliced quadratic - path = 'M %f,%f Q %f,%f %f,%f Q %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['10']][1], vals[groups['20']][1], vals[groups['10']][2], vals[groups['20']][2], vals[groups['10']][3], vals[groups['20']][3], vals[groups['10']][4], vals[groups['20']][4]) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def export_CIRCLE(): - # mandatory group codes : (10, 20, 40) (x, y, radius) - if vals[groups['10']] and vals[groups['20']] and vals[groups['40']]: - generate_ellipse(vals[groups['10']][0], vals[groups['20']][0], scale*vals[groups['40']][0], 0.0, 1.0, 0.0, 0.0) - -def export_ARC(): - # mandatory group codes : (10, 20, 40, 50, 51) (x, y, radius, angle1, angle2) - if vals[groups['10']] and vals[groups['20']] and vals[groups['40']] and vals[groups['50']] and vals[groups['51']]: - generate_ellipse(vals[groups['10']][0], vals[groups['20']][0], scale*vals[groups['40']][0], 0.0, 1.0, vals[groups['50']][0]*math.pi/180.0, vals[groups['51']][0]*math.pi/180.0) - -def export_ELLIPSE(): - # mandatory group codes : (10, 11, 20, 21, 40, 41, 42) (xc, xm, yc, ym, width ratio, angle1, angle2) - if vals[groups['10']] and vals[groups['11']] and vals[groups['20']] and vals[groups['21']] and vals[groups['40']] and vals[groups['41']] and vals[groups['42']]: - generate_ellipse(vals[groups['10']][0], vals[groups['20']][0], scale*vals[groups['11']][0], scale*vals[groups['21']][0], vals[groups['40']][0], vals[groups['41']][0], vals[groups['42']][0]) - -def export_LEADER(): - # mandatory group codes : (10, 20) (x, y) - if vals[groups['10']] and vals[groups['20']]: - if len(vals[groups['10']]) > 1 and len(vals[groups['20']]) == len(vals[groups['10']]): - path = 'M %f,%f' % (vals[groups['10']][0], vals[groups['20']][0]) - for i in range (1, len(vals[groups['10']])): - path += ' %f,%f' % (vals[groups['10']][i], vals[groups['20']][i]) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def export_LWPOLYLINE(): - # mandatory group codes : (10, 20, 70) (x, y, flags) - if vals[groups['10']] and vals[groups['20']] and vals[groups['70']]: - if len(vals[groups['10']]) > 1 and len(vals[groups['20']]) == len(vals[groups['10']]): - # optional group codes : (42) (bulge) - iseqs = 0 - ibulge = 0 - if vals[groups['70']][0] & 1: # closed path - seqs.append('20') - vals[groups['10']].append(vals[groups['10']][0]) - vals[groups['20']].append(vals[groups['20']][0]) - while seqs[iseqs] != '20': - iseqs += 1 - path = 'M %f,%f' % (vals[groups['10']][0], vals[groups['20']][0]) - xold = vals[groups['10']][0] - yold = vals[groups['20']][0] - for i in range (1, len(vals[groups['10']])): - bulge = 0 - iseqs += 1 - while seqs[iseqs] != '20': - if seqs[iseqs] == '42': - bulge = vals[groups['42']][ibulge] - ibulge += 1 - iseqs += 1 - if bulge: - sweep = 0 # sweep CCW - if bulge < 0: - sweep = 1 # sweep CW - bulge = -bulge - large = 0 # large-arc-flag - if bulge > 1: - large = 1 - r = math.sqrt((vals[groups['10']][i] - xold)**2 + (vals[groups['20']][i] - yold)**2) - r = 0.25*r*(bulge + 1.0/bulge) - path += ' A %f,%f 0.0 %d %d %f,%f' % (r, r, large, sweep, vals[groups['10']][i], vals[groups['20']][i]) - else: - 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 - path += ' z' - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def export_HATCH(): - # mandatory group codes : (10, 20, 70, 72, 92, 93) (x, y, fill, Edge Type, Path Type, Number of edges) - if vals[groups['10']] and vals[groups['20']] and vals[groups['70']] and vals[groups['72']] and vals[groups['92']] and vals[groups['93']]: - if len(vals[groups['10']]) > 1 and len(vals[groups['20']]) == len(vals[groups['10']]): - # optional group codes : (11, 21, 40, 50, 51, 73) (x, y, r, angle1, angle2, CCW) - i10 = 1 # count start points - i11 = 0 # count line end points - i40 = 0 # count circles - i72 = 0 # count edge type flags - path = '' - for i in range (0, len(vals[groups['93']])): - xc = vals[groups['10']][i10] - yc = vals[groups['20']][i10] - if vals[groups['72']][i72] == 2: # arc - rm = scale*vals[groups['40']][i40] - a1 = vals[groups['50']][i40] - path += 'M %f,%f ' % (xc + rm*math.cos(a1*math.pi/180.0), yc + rm*math.sin(a1*math.pi/180.0)) - else: - a1 = 0 - path += 'M %f,%f ' % (xc, yc) - for j in range(0, vals[groups['93']][i]): - if vals[groups['92']][i] & 2: # polyline - if j > 0: - path += 'L %f,%f ' % (vals[groups['10']][i10], vals[groups['20']][i10]) - if j == vals[groups['93']][i] - 1: - i72 += 1 - elif vals[groups['72']][i72] == 2: # arc - xc = vals[groups['10']][i10] - yc = vals[groups['20']][i10] - rm = scale*vals[groups['40']][i40] - a2 = vals[groups['51']][i40] - diff = (a2 - a1 + 360) % (360) - sweep = 1 - vals[groups['73']][i40] # sweep CCW - large = 0 # large-arc-flag - if diff: - path += 'A %f,%f 0.0 %d %d %f,%f ' % (rm, rm, large, sweep, xc + rm*math.cos(a2*math.pi/180.0), yc + rm*math.sin(a2*math.pi/180.0)) - else: - path += 'A %f,%f 0.0 %d %d %f,%f ' % (rm, rm, large, sweep, xc + rm*math.cos((a1+180.0)*math.pi/180.0), yc + rm*math.sin((a1+180.0)*math.pi/180.0)) - path += 'A %f,%f 0.0 %d %d %f,%f ' % (rm, rm, large, sweep, xc + rm*math.cos(a1*math.pi/180.0), yc + rm*math.sin(a1*math.pi/180.0)) - i40 += 1 - i72 += 1 - elif vals[groups['72']][i72] == 1: # line - path += 'L %f,%f ' % (scale*(extrude*vals[groups['11']][i11] - xmin), height - scale*(vals[groups['21']][i11] - ymin)) - i11 += 1 - i72 += 1 - i10 += 1 - path += "z " - if vals[groups['70']][0]: - style = simplestyle.formatStyle({'fill': '%s' % color}) - else: - style = simplestyle.formatStyle({'fill': 'url(#Hatch)', 'fill-opacity': '1.0'}) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def export_DIMENSION(): - # mandatory group codes : (10, 11, 13, 14, 20, 21, 23, 24) (x1..4, y1..4) - if vals[groups['10']] and vals[groups['11']] and vals[groups['13']] and vals[groups['14']] and vals[groups['20']] and vals[groups['21']] and vals[groups['23']] and vals[groups['24']]: - dx = abs(vals[groups['10']][0] - vals[groups['13']][0]) - dy = abs(vals[groups['20']][0] - vals[groups['23']][0]) - if (vals[groups['10']][0] == vals[groups['14']][0]) and dx > 0.00001: - d = dx/scale - dy = 0 - path = 'M %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['13']][0], vals[groups['20']][0]) - elif (vals[groups['20']][0] == vals[groups['24']][0]) and dy > 0.00001: - d = dy/scale - dx = 0 - path = 'M %f,%f %f,%f' % (vals[groups['10']][0], vals[groups['20']][0], vals[groups['10']][0], vals[groups['23']][0]) - else: - return - attribs = {'d': path, 'style': style + '; marker-start: url(#DistanceX); marker-end: url(#DistanceX); stroke-width: 0.25px'} - inkex.etree.SubElement(layer, 'path', attribs) - x = scale*(extrude*vals[groups['11']][0] - xmin) - y = height - scale*(vals[groups['21']][0] - ymin) - size = 12 # default fontsize in px - if vals[groups['3']]: - if DIMTXT.has_key(vals[groups['3']][0]): - size = scale*DIMTXT[vals[groups['3']][0]] - if size < 2: - size = 2 - attribs = {'x': '%f' % x, 'y': '%f' % y, 'style': 'font-size: %.1fpx; fill: %s; font-family: %s; text-anchor: middle; text-align: center' % (size, color, options.font)} - if dx == 0: - attribs.update({'transform': 'rotate (%f %f %f)' % (-90, x, y)}) - node = inkex.etree.SubElement(layer, 'text', attribs) - tspan = inkex.etree.SubElement(node , 'tspan', {inkex.addNS('role','sodipodi'): 'line'}) - tspan.text = str(float('%.2f' % d)) - -def export_INSERT(): - # mandatory group codes : (2, 10, 20) (block name, x, y) - if vals[groups['2']] and vals[groups['10']] and vals[groups['20']]: - x = vals[groups['10']][0] + scale*xmin - y = vals[groups['20']][0] - scale*ymin - height - attribs = {inkex.addNS('href','xlink'): '#' + quote(vals[groups['2']][0].replace(" ", "_").encode("utf-8"))} - tform = 'translate(%f, %f)' % (x, y) - if vals[groups['41']] and vals[groups['42']]: - tform += ' scale(%f, %f)' % (vals[groups['41']][0], vals[groups['42']][0]) - attribs.update({'transform': tform}) - inkex.etree.SubElement(layer, 'use', attribs) - -def export_BLOCK(): - # mandatory group codes : (2) (block name) - if vals[groups['2']]: - global block - block = inkex.etree.SubElement(defs, 'symbol', {'id': vals[groups['2']][0].replace(" ", "_")}) - -def export_ENDBLK(): - global block - block = defs # initiallize with dummy - -def export_ATTDEF(): - # mandatory group codes : (1, 2) (default, tag) - if vals[groups['1']] and vals[groups['2']]: - vals[groups['1']][0] = vals[groups['2']][0] - export_MTEXT() - -def generate_ellipse(xc, yc, xm, ym, w, a1, a2): - rm = math.sqrt(xm*xm + ym*ym) - a = math.atan2(ym, xm) - diff = (a2 - a1 + 2*math.pi) % (2*math.pi) - if abs(diff) > 0.0000001 and abs(diff - 2*math.pi) > 0.0000001: # open arc - large = 0 # large-arc-flag - if diff > math.pi: - large = 1 - xt = rm*math.cos(a1) - yt = w*rm*math.sin(a1) - x1 = xt*math.cos(a) - yt*math.sin(a) - y1 = xt*math.sin(a) + yt*math.cos(a) - xt = rm*math.cos(a2) - yt = w*rm*math.sin(a2) - x2 = xt*math.cos(a) - yt*math.sin(a) - y2 = xt*math.sin(a) + yt*math.cos(a) - path = 'M %f,%f A %f,%f %f %d 0 %f,%f' % (xc+x1, yc-y1, rm, w*rm, -180.0*a/math.pi, large, xc+x2, yc-y2) - else: # closed arc - path = 'M %f,%f A %f,%f %f 1 0 %f,%f %f,%f %f 1 0 %f,%f z' % (xc+xm, yc-ym, rm, w*rm, -180.0*a/math.pi, xc-xm, yc+ym, rm, w*rm, -180.0*a/math.pi, xc+xm, yc-ym) - attribs = {'d': path, 'style': style} - inkex.etree.SubElement(layer, 'path', attribs) - -def generate_gcodetools_point(xc, yc): - path= 'm %s,%s 2.9375,-6.34375 0.8125,1.90625 6.84375,-6.84375 0,0 0.6875,0.6875 -6.84375,6.84375 1.90625,0.8125 z' % (xc,yc) - attribs = {'d': path, inkex.addNS('dxfpoint','inkscape'):'1', 'style': 'stroke:none;fill:#ff0000'} - inkex.etree.SubElement(layer, 'path', attribs) - -def get_line(): - return (stream.readline().strip(), stream.readline().strip()) - -def get_group(group): - line = get_line() - if line[0] == group: - return float(line[1]) - else: - return 0.0 - -# 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, 'VIEWPORT': False, 'ENDSEC': 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, '230': 24, '370': 25} -colors = { 1: '#FF0000', 2: '#FFFF00', 3: '#00FF00', 4: '#00FFFF', 5: '#0000FF', - 6: '#FF00FF', 8: '#414141', 9: '#808080', 12: '#BD0000', 30: '#FF7F00', - 250: '#333333', 251: '#505050', 252: '#696969', 253: '#828282', 254: '#BEBEBE', 255: '#FFFFFF'} - -parser = inkex.optparse.OptionParser(usage="usage: %prog [options] SVGfile", option_class=inkex.InkOption) -parser.add_option("--scalemethod", action="store", type="string", dest="scalemethod", default="manual") -parser.add_option("--scale", action="store", type="string", dest="scale", default="1.0") -parser.add_option("--xmin", action="store", type="string", dest="xmin", default="0.0") -parser.add_option("--ymin", action="store", type="string", dest="ymin", default="0.0") -parser.add_option("--gcodetoolspoints", action="store", type="inkbool", dest="gcodetoolspoints", default=True) -parser.add_option("--encoding", action="store", type="string", dest="input_encode", default="latin_1") -parser.add_option("--font", action="store", type="string", dest="font", default="Arial") -parser.add_option("--tab", action="store", type="string", dest="tab", default="Options") -parser.add_option("--inputhelp", action="store", type="string", dest="inputhelp", default="") -(options, args) = parser.parse_args(inkex.sys.argv[1:]) -doc = inkex.etree.parse(StringIO('<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" width="%s" height="%s"></svg>' % (210*96/25.4, 297*96/25.4))) -desc = inkex.etree.SubElement(doc.getroot(), 'desc', {}) -defs = inkex.etree.SubElement(doc.getroot(), 'defs', {}) -marker = inkex.etree.SubElement(defs, 'marker', {'id': 'DistanceX', 'orient': 'auto', 'refX': '0.0', 'refY': '0.0', 'style': 'overflow:visible'}) -inkex.etree.SubElement(marker, 'path', {'d': 'M 3,-3 L -3,3 M 0,-5 L 0,5', 'style': 'stroke:#000000; stroke-width:0.5'}) -pattern = inkex.etree.SubElement(defs, 'pattern', {'id': 'Hatch', 'patternUnits': 'userSpaceOnUse', 'width': '8', 'height': '8', 'x': '0', 'y': '0'}) -inkex.etree.SubElement(pattern, 'path', {'d': 'M8 4 l-4,4', 'stroke': '#000000', 'stroke-width': '0.25', 'linecap': 'square'}) -inkex.etree.SubElement(pattern, 'path', {'d': 'M6 2 l-4,4', 'stroke': '#000000', 'stroke-width': '0.25', 'linecap': 'square'}) -inkex.etree.SubElement(pattern, 'path', {'d': 'M4 0 l-4,4', 'stroke': '#000000', 'stroke-width': '0.25', 'linecap': 'square'}) -stream = open(args[0], 'r') -xmax = xmin = ymin = 0.0 -height = 297.0*96.0/25.4 # default A4 height in pixels -measurement = 0 # default inches -line = get_line() -polylines = 0 -flag = 0 # (0, 1, 2, 3) = (none, LAYER, LTYPE, DIMTXT) -layer_colors = {} # store colors by layer -layer_nodes = {} # store nodes by layer -linetypes = {} # store linetypes by name -DIMTXT = {} # store DIMENSION text sizes - -while line[0] and line[1] != 'BLOCKS': - line = get_line() - if options.scalemethod == 'file': - if line[1] == '$MEASUREMENT': - measurement = get_group('70') - elif options.scalemethod == 'auto': - if line[1] == '$EXTMIN': - xmin = get_group('10') - ymin = get_group('20') - if line[1] == '$EXTMAX': - xmax = get_group('10') - if flag == 1 and line[0] == '2': - layername = unicode(line[1], options.input_encode) - attribs = {inkex.addNS('groupmode','inkscape'): 'layer', inkex.addNS('label','inkscape'): '%s' % layername} - layer_nodes[layername] = inkex.etree.SubElement(doc.getroot(), 'g', attribs) - if flag == 2 and line[0] == '2': - linename = unicode(line[1], options.input_encode) - linetypes[linename] = [] - if flag == 3 and line[0] == '2': - stylename = unicode(line[1], options.input_encode) - if line[0] == '2' and line[1] == 'LAYER': - flag = 1 - if line[0] == '2' and line[1] == 'LTYPE': - flag = 2 - if line[0] == '2' and line[1] == 'DIMSTYLE': - flag = 3 - if flag == 1 and line[0] == '62': - layer_colors[layername] = int(line[1]) - if flag == 2 and line[0] == '49': - linetypes[linename].append(float(line[1])) - if flag == 3 and line[0] == '140': - DIMTXT[stylename] = float(line[1]) - if line[0] == '0' and line[1] == 'ENDTAB': - flag = 0 - -if options.scalemethod == 'file': - scale = 25.4 # default inches - if measurement == 1.0: - scale = 1.0 # use mm -elif options.scalemethod == 'auto': - scale = 1.0 - if xmax > xmin: - scale = 210.0/(xmax - xmin) # scale to A4 width -else: - scale = float(options.scale) # manual scale factor - xmin = float(options.xmin) - ymin = float(options.ymin) -desc.text = '%s - scale = %f, origin = (%f, %f), method = %s' % (unicode(args[0], options.input_encode), scale, xmin, ymin, options.scalemethod) -scale *= 96.0/25.4 # convert from mm to pixels - -if not layer_nodes.has_key('0'): - attribs = {inkex.addNS('groupmode','inkscape'): 'layer', inkex.addNS('label','inkscape'): '0'} - layer_nodes['0'] = inkex.etree.SubElement(doc.getroot(), 'g', attribs) - layer_colors['0'] = 7 - -for linename in linetypes.keys(): # scale the dashed lines - linetype = '' - for length in linetypes[linename]: - if length == 0: # test for dot - linetype += ' 0.5,' - else: - linetype += '%.4f,' % math.fabs(length*scale) - if linetype == '': - linetypes[linename] = 'stroke-linecap: round' - else: - linetypes[linename] = 'stroke-dasharray:' + linetype - -entity = '' -inENTITIES = False -block = defs # initiallize with dummy -while line[0] and (line[1] != 'ENDSEC' or not inENTITIES): - line = get_line() - if line[1] == 'ENTITIES': - inENTITIES = True - elif line[1] == 'POLYLINE': - polylines += 1 - if entity and groups.has_key(line[0]): - seqs.append(line[0]) # list of group codes - if line[0] == '1' or line[0] == '2' or line[0] == '3' or line[0] == '6' or line[0] == '8': # text value - val = line[1].replace('\~', ' ') - val = inkex.re.sub( '\\\\A.*;', '', val) - val = inkex.re.sub( '\\\\H.*;', '', val) - val = inkex.re.sub( '\\^I', '', val) - val = inkex.re.sub( '{\\\\L', '', val) - val = inkex.re.sub( '}', '', val) - val = inkex.re.sub( '\\\\S.*;', '', val) - val = inkex.re.sub( '\\\\W.*;', '', val) - val = unicode(val, options.input_encode) - val = val.encode('unicode_escape') - val = inkex.re.sub( '\\\\\\\\U\+([0-9A-Fa-f]{4})', '\\u\\1', val) - val = val.decode('unicode_escape') - elif line[0] == '62' or line[0] == '70' or line[0] == '92' or line[0] == '93': - val = int(line[1]) - else: # unscaled float value - val = float(line[1]) - vals[groups[line[0]]].append(val) - elif entities.has_key(line[1]): - if entities.has_key(entity): - if block != defs: # in a BLOCK - layer = block - elif vals[groups['8']]: # use Common Layer Name - if not vals[groups['8']][0]: - vals[groups['8']][0] = '0' # use default name - if not layer_nodes.has_key(vals[groups['8']][0]): - attribs = {inkex.addNS('groupmode','inkscape'): 'layer', inkex.addNS('label','inkscape'): '%s' % vals[groups['8']][0]} - layer_nodes[vals[groups['8']][0]] = inkex.etree.SubElement(doc.getroot(), 'g', attribs) - layer = layer_nodes[vals[groups['8']][0]] - color = '#000000' # default color - if vals[groups['8']]: - if layer_colors.has_key(vals[groups['8']][0]): - if colors.has_key(layer_colors[vals[groups['8']][0]]): - color = colors[layer_colors[vals[groups['8']][0]]] - if vals[groups['62']]: # Common Color Number - if colors.has_key(vals[groups['62']][0]): - color = colors[vals[groups['62']][0]] - style = simplestyle.formatStyle({'stroke': '%s' % color, 'fill': 'none'}) - w = 0.5 # default lineweight for POINT - if vals[groups['370']]: # Common Lineweight - if vals[groups['370']][0] > 0: - w = 96.0/25.4*vals[groups['370']][0]/100.0 - if w < 0.5: - w = 0.5 - style = simplestyle.formatStyle({'stroke': '%s' % color, 'fill': 'none', 'stroke-width': '%.1f' % w}) - if vals[groups['6']]: # Common Linetype - if linetypes.has_key(vals[groups['6']][0]): - style += ';' + linetypes[vals[groups['6']][0]] - extrude = 1.0 - if vals[groups['230']]: - extrude = float(vals[groups['230']][0]) - for xgrp in ['10', '13', '14']: # scale/reflect x values - if vals[groups[xgrp]]: - for i in range (0, len(vals[groups[xgrp]])): - vals[groups[xgrp]][i] = scale*(extrude*vals[groups[xgrp]][i] - xmin) - for ygrp in ['20', '23', '24']: # scale y values - if vals[groups[ygrp]]: - for i in range (0, len(vals[groups[ygrp]])): - vals[groups[ygrp]][i] = height - scale*(vals[groups[ygrp]][i] - ymin) - if (extrude == -1.0): # reflect angles - if vals[groups['50']] and vals[groups['51']]: - temp = vals[groups['51']][0] - vals[groups['51']][0] = 180.0 - vals[groups['50']][0] - vals[groups['50']][0] = 180.0 - temp - if entities[entity]: - entities[entity]() - entity = line[1] - vals = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]] - seqs = [] - -if polylines: - inkex.errormsg(_('%d ENTITIES of type POLYLINE encountered and ignored. Please try to convert to Release 13 format using QCad.') % polylines) -doc.write(inkex.sys.stdout) - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/dxf_outlines.inx b/share/extensions/dxf_outlines.inx deleted file mode 100644 index 1b764130d..000000000 --- a/share/extensions/dxf_outlines.inx +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Desktop Cutting Plotter R14</_name> - <id>org.ekips.output.dxf_outlines</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">dxf_outlines.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="options" _gui-text="Options"> - <param name="ROBO" type="boolean" _gui-text="use ROBO-Master type of spline output">false</param> - <param name="POLY" type="boolean" _gui-text="use LWPOLYLINE type of line output">true</param> - <param name="units" type="enum" _gui-text="Base unit:"> - <_item value="72./96">pt</_item> - <_item value="1./16">pc</_item> - <_item value="1.">px</_item> - <_item value="25.4/96">mm</_item> - <_item value="2.54/96">cm</_item> - <_item value=".0254/96">m</_item> - <_item value="1./96">in</_item> - <_item value="1./1152">ft</_item> - </param> - <param name="encoding" type="enum" _gui-text="Character Encoding:"> - <_item value="latin_1">Latin 1</_item> - <_item value="cp1250">CP 1250</_item> - <_item value="cp1252">CP 1252</_item> - <_item value="utf_8">UTF 8</_item> - </param> - <param name="layer_option" type="enum" _gui-text="Layer export selection:"> - <_item value="all">All (default)</_item> - <_item value="visible">Visible only</_item> - <_item value="name">By name match</_item> - </param> - <param name="layer_name" type="string" _gui-text="Layer match name:"></param> - </page> - <page name="help" _gui-text="Help"> - <_param name="inputhelp" type="description" xml:space="preserve">- AutoCAD Release 14 DXF format. -- The base unit parameter specifies in what unit the coordinates are output (96 px = 1 in). -- Supported element types - - paths (lines and splines) - - rectangles - - clones (the crossreference to the original is lost) -- ROBO-Master spline output is a specialized spline readable only by ROBO-Master and AutoDesk viewers, not Inkscape. -- LWPOLYLINE output is a multiply-connected polyline, disable it to use a legacy version of the LINE output. -- You can choose to export all layers, only visible ones or by name match (case insensitive and use comma ',' as separator)</_param> - </page> - </param> - <output> - <extension>.dxf</extension> - <mimetype>image/dxf</mimetype> - <_filetypename>Desktop Cutting Plotter (AutoCAD DXF R14) (*.dxf)</_filetypename> - <_filetypetooltip>Desktop Cutting Plotter</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">dxf_outlines.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/dxf_outlines.py b/share/extensions/dxf_outlines.py deleted file mode 100755 index 53de1066d..000000000 --- a/share/extensions/dxf_outlines.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2005,2007,2008 Aaron Spike, aaron@ekips.org -Copyright (C) 2008,2010 Alvin Penner, penner@vaxxine.com - -This file output script for Inkscape creates a AutoCAD R14 DXF file. -The spec can be found here: http://www.autodesk.com/techpubs/autocad/acadr14/dxf/index.htm. - -File history: -- template dxf_outlines.dxf added Feb 2008 by Alvin Penner -- ROBO-Master output option added Aug 2008 -- ROBO-Master multispline output added Sept 2008 -- LWPOLYLINE output modification added Dec 2008 -- toggle between LINE/LWPOLYLINE added Jan 2010 -- support for transform elements added July 2010 -- support for layers added July 2010 -- support for rectangle added Dec 2010 - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import math -# local library -import inkex -import simplestyle -import simpletransform -import cubicsuperpath -import coloreffect -import dxf_templates - -try: - from numpy import * - from numpy.linalg import solve -except: - # Initialize gettext for messages outside an inkex derived class - inkex.localize() - inkex.errormsg(_("Failed to import the numpy or numpy.linalg modules. These modules are required by this extension. Please install them and try again.")) - inkex.sys.exit() - -def pointdistance((x1,y1),(x2,y2)): - return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2)) - -def get_fit(u, csp, col): - return (1-u)**3*csp[0][col] + 3*(1-u)**2*u*csp[1][col] + 3*(1-u)*u**2*csp[2][col] + u**3*csp[3][col] - -def get_matrix(u, i, j): - if j == i + 2: - return (u[i]-u[i-1])*(u[i]-u[i-1])/(u[i+2]-u[i-1])/(u[i+1]-u[i-1]) - elif j == i + 1: - return ((u[i]-u[i-1])*(u[i+2]-u[i])/(u[i+2]-u[i-1]) + (u[i+1]-u[i])*(u[i]-u[i-2])/(u[i+1]-u[i-2]))/(u[i+1]-u[i-1]) - elif j == i: - return (u[i+1]-u[i])*(u[i+1]-u[i])/(u[i+1]-u[i-2])/(u[i+1]-u[i-1]) - else: - return 0 - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-R", "--ROBO", action="store", - type="string", dest="ROBO", - default=False) - self.OptionParser.add_option("-P", "--POLY", action="store", - type="string", dest="POLY", - default=True) - self.OptionParser.add_option("--units", action="store", - type="string", dest="units", - default="72./96") # Points - self.OptionParser.add_option("--encoding", action="store", - type="string", dest="char_encode", - default="latin_1") - self.OptionParser.add_option("--tab", action="store", - type="string", dest="tab") - self.OptionParser.add_option("--inputhelp", action="store", - type="string", dest="inputhelp") - self.OptionParser.add_option("--layer_option", action="store", - type="string", dest="layer_option", - default="all") - self.OptionParser.add_option("--layer_name", action="store", - type="string", dest="layer_name") - - self.dxf = [] - self.handle = 255 # handle for DXF ENTITY - self.layers = ['0'] - self.layer = '0' # mandatory layer - self.layernames = [] - self.csp_old = [[0.0,0.0]]*4 # previous spline - self.d = array([0], float) # knot vector - self.poly = [[0.0,0.0]] # LWPOLYLINE data - def output(self): - print ''.join(self.dxf) - def dxf_add(self, str): - self.dxf.append(str.encode(self.options.char_encode)) - def dxf_line(self,csp): - self.handle += 1 - self.dxf_add(" 0\nLINE\n 5\n%x\n100\nAcDbEntity\n 8\n%s\n 62\n%d\n100\nAcDbLine\n" % (self.handle, self.layer, self.color)) - self.dxf_add(" 10\n%f\n 20\n%f\n 30\n0.0\n 11\n%f\n 21\n%f\n 31\n0.0\n" % (csp[0][0],csp[0][1],csp[1][0],csp[1][1])) - def LWPOLY_line(self,csp): - if (abs(csp[0][0] - self.poly[-1][0]) > .0001 - or abs(csp[0][1] - self.poly[-1][1]) > .0001): - self.LWPOLY_output() # terminate current polyline - self.poly = [csp[0]] # initiallize new polyline - self.color_LWPOLY = self.color - self.layer_LWPOLY = self.layer - self.poly.append(csp[1]) - def LWPOLY_output(self): - if len(self.poly) == 1: - return - self.handle += 1 - closed = 1 - if (abs(self.poly[0][0] - self.poly[-1][0]) > .0001 - or abs(self.poly[0][1] - self.poly[-1][1]) > .0001): - closed = 0 - self.dxf_add(" 0\nLWPOLYLINE\n 5\n%x\n100\nAcDbEntity\n 8\n%s\n 62\n%d\n100\nAcDbPolyline\n 90\n%d\n 70\n%d\n" % (self.handle, self.layer_LWPOLY, self.color_LWPOLY, len(self.poly) - closed, closed)) - for i in range(len(self.poly) - closed): - self.dxf_add(" 10\n%f\n 20\n%f\n 30\n0.0\n" % (self.poly[i][0],self.poly[i][1])) - def dxf_spline(self,csp): - knots = 8 - ctrls = 4 - self.handle += 1 - self.dxf_add(" 0\nSPLINE\n 5\n%x\n100\nAcDbEntity\n 8\n%s\n 62\n%d\n100\nAcDbSpline\n" % (self.handle, self.layer, self.color)) - self.dxf_add(" 70\n8\n 71\n3\n 72\n%d\n 73\n%d\n 74\n0\n" % (knots, ctrls)) - for i in range(2): - for j in range(4): - self.dxf_add(" 40\n%d\n" % i) - for i in csp: - self.dxf_add(" 10\n%f\n 20\n%f\n 30\n0.0\n" % (i[0],i[1])) - def ROBO_spline(self,csp): - # this spline has zero curvature at the endpoints, as in ROBO-Master - if (abs(csp[0][0] - self.csp_old[3][0]) > .0001 - or abs(csp[0][1] - self.csp_old[3][1]) > .0001 - or abs((csp[1][1]-csp[0][1])*(self.csp_old[3][0]-self.csp_old[2][0]) - (csp[1][0]-csp[0][0])*(self.csp_old[3][1]-self.csp_old[2][1])) > .001): - self.ROBO_output() # terminate current spline - self.xfit = array([csp[0][0]], float) # initiallize new spline - self.yfit = array([csp[0][1]], float) - self.d = array([0], float) - self.color_ROBO = self.color - self.layer_ROBO = self.layer - self.xfit = concatenate((self.xfit, zeros((3)))) # append to current spline - self.yfit = concatenate((self.yfit, zeros((3)))) - self.d = concatenate((self.d, zeros((3)))) - for i in range(1, 4): - j = len(self.d) + i - 4 - self.xfit[j] = get_fit(i/3.0, csp, 0) - self.yfit[j] = get_fit(i/3.0, csp, 1) - self.d[j] = self.d[j-1] + pointdistance((self.xfit[j-1],self.yfit[j-1]),(self.xfit[j],self.yfit[j])) - self.csp_old = csp - def ROBO_output(self): - if len(self.d) == 1: - return - fits = len(self.d) - ctrls = fits + 2 - knots = ctrls + 4 - self.xfit = concatenate((self.xfit, zeros((2)))) # pad with 2 endpoint constraints - self.yfit = concatenate((self.yfit, zeros((2)))) # pad with 2 endpoint constraints - self.d = concatenate((self.d, zeros((6)))) # pad with 3 duplicates at each end - self.d[fits+2] = self.d[fits+1] = self.d[fits] = self.d[fits-1] - solmatrix = zeros((ctrls,ctrls), dtype=float) - for i in range(fits): - solmatrix[i,i] = get_matrix(self.d, i, i) - solmatrix[i,i+1] = get_matrix(self.d, i, i+1) - solmatrix[i,i+2] = get_matrix(self.d, i, i+2) - solmatrix[fits, 0] = self.d[2]/self.d[fits-1] # curvature at start = 0 - solmatrix[fits, 1] = -(self.d[1] + self.d[2])/self.d[fits-1] - solmatrix[fits, 2] = self.d[1]/self.d[fits-1] - solmatrix[fits+1, fits-1] = (self.d[fits-1] - self.d[fits-2])/self.d[fits-1] # curvature at end = 0 - solmatrix[fits+1, fits] = (self.d[fits-3] + self.d[fits-2] - 2*self.d[fits-1])/self.d[fits-1] - solmatrix[fits+1, fits+1] = (self.d[fits-1] - self.d[fits-3])/self.d[fits-1] - xctrl = solve(solmatrix, self.xfit) - yctrl = solve(solmatrix, self.yfit) - self.handle += 1 - self.dxf_add(" 0\nSPLINE\n 5\n%x\n100\nAcDbEntity\n 8\n%s\n 62\n%d\n100\nAcDbSpline\n" % (self.handle, self.layer_ROBO, self.color_ROBO)) - self.dxf_add(" 70\n0\n 71\n3\n 72\n%d\n 73\n%d\n 74\n%d\n" % (knots, ctrls, fits)) - for i in range(knots): - self.dxf_add(" 40\n%f\n" % self.d[i-3]) - for i in range(ctrls): - self.dxf_add(" 10\n%f\n 20\n%f\n 30\n0.0\n" % (xctrl[i],yctrl[i])) - for i in range(fits): - self.dxf_add(" 11\n%f\n 21\n%f\n 31\n0.0\n" % (self.xfit[i],self.yfit[i])) - - def process_shape(self, node, mat): - rgb = (0,0,0) - style = node.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('stroke'): - if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': - rgb = simplestyle.parseColor(style['stroke']) - hsl = coloreffect.ColorEffect.rgb_to_hsl(coloreffect.ColorEffect(),rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0) - self.color = 7 # default is black - if hsl[2]: - self.color = 1 + (int(6*hsl[0] + 0.5) % 6) # use 6 hues - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - if not d: - return - p = cubicsuperpath.parsePath(d) - elif node.tag == inkex.addNS('rect','svg'): - x = float(node.get('x', 0)) - y = float(node.get('y', 0)) - width = float(node.get('width')) - height = float(node.get('height')) - d = "m %s,%s %s,%s %s,%s %s,%s z" % (x, y, width, 0, 0, height, -width, 0) - p = cubicsuperpath.parsePath(d) - elif node.tag == inkex.addNS('line','svg'): - x1 = float(node.get('x1', 0)) - x2 = float(node.get('x2', 0)) - y1 = float(node.get('y1', 0)) - y2 = float(node.get('y2', 0)) - d = "M %s,%s L %s,%s" % (x1, y1, x2, y2) - p = cubicsuperpath.parsePath(d) - elif node.tag == inkex.addNS('circle','svg'): - cx = float(node.get('cx', 0)) - cy = float(node.get('cy', 0)) - r = float(node.get('r')) - d = "m %s,%s a %s,%s 0 0 1 %s,%s %s,%s 0 0 1 %s,%s z" % (cx + r, cy, r, r, -2*r, 0, r, r, 2*r, 0) - p = cubicsuperpath.parsePath(d) - elif node.tag == inkex.addNS('ellipse','svg'): - cx = float(node.get('cx', 0)) - cy = float(node.get('cy', 0)) - rx = float(node.get('rx')) - ry = float(node.get('ry')) - d = "m %s,%s a %s,%s 0 0 1 %s,%s %s,%s 0 0 1 %s,%s z" % (cx + rx, cy, rx, ry, -2*rx, 0, rx, ry, 2*rx, 0) - p = cubicsuperpath.parsePath(d) - else: - return - trans = node.get('transform') - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - simpletransform.applyTransformToPath(mat, p) - for sub in p: - for i in range(len(sub)-1): - s = sub[i] - e = sub[i+1] - if s[1] == s[2] and e[0] == e[1]: - if (self.options.POLY == 'true'): - self.LWPOLY_line([s[1],e[1]]) - else: - self.dxf_line([s[1],e[1]]) - elif (self.options.ROBO == 'true'): - self.ROBO_spline([s[1],s[2],e[0],e[1]]) - else: - self.dxf_spline([s[1],s[2],e[0],e[1]]) - - def process_clone(self, node): - trans = node.get('transform') - x = node.get('x') - y = node.get('y') - mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - if x: - mat = simpletransform.composeTransform(mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) - if y: - mat = simpletransform.composeTransform(mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) - # push transform - if trans or x or y: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], mat)) - # get referenced node - refid = node.get(inkex.addNS('href','xlink')) - refnode = self.getElementById(refid[1:]) - if refnode is not None: - if refnode.tag == inkex.addNS('g','svg'): - self.process_group(refnode) - elif refnode.tag == inkex.addNS('use', 'svg'): - self.process_clone(refnode) - else: - self.process_shape(refnode, self.groupmat[-1]) - # pop transform - if trans or x or y: - self.groupmat.pop() - - def process_group(self, group): - if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': - style = group.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('display'): - if style['display'] == 'none' and self.options.layer_option and self.options.layer_option=='visible': - return - layer = group.get(inkex.addNS('label', 'inkscape')) - if self.options.layer_name and self.options.layer_option and self.options.layer_option=='name' and not layer.lower() in self.options.layer_name: - return - - layer = layer.replace(' ', '_') - if layer in self.layers: - self.layer = layer - trans = group.get('transform') - if trans: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) - for node in group: - if node.tag == inkex.addNS('g','svg'): - self.process_group(node) - elif node.tag == inkex.addNS('use', 'svg'): - self.process_clone(node) - else: - self.process_shape(node, self.groupmat[-1]) - if trans: - self.groupmat.pop() - - def effect(self): - #Warn user if name match field is empty - if self.options.layer_option and self.options.layer_option=='name' and not self.options.layer_name: - inkex.errormsg(_("Error: Field 'Layer match name' must be filled when using 'By name match' option")) - inkex.sys.exit() - #Split user layer data into a list: "layerA,layerb,LAYERC" becomes ["layera", "layerb", "layerc"] - if self.options.layer_name: - self.options.layer_name = self.options.layer_name.lower().split(',') - - #References: Minimum Requirements for Creating a DXF File of a 3D Model By Paul Bourke - # NURB Curves: A Guide for the Uninitiated By Philip J. Schneider - # The NURBS Book By Les Piegl and Wayne Tiller (Springer, 1995) - # self.dxf_add("999\nDXF created by Inkscape\n") # Some programs do not take comments in DXF files (KLayout 0.21.12 for example) - self.dxf_add(dxf_templates.r14_header) - for node in self.document.getroot().xpath('//svg:g', namespaces=inkex.NSS): - if node.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': - layer = node.get(inkex.addNS('label', 'inkscape')) - self.layernames.append(layer.lower()) - if self.options.layer_name and self.options.layer_option and self.options.layer_option=='name' and not layer.lower() in self.options.layer_name: - continue - layer = layer.replace(' ', '_') - if layer and not layer in self.layers: - self.layers.append(layer) - self.dxf_add(" 2\nLAYER\n 5\n2\n100\nAcDbSymbolTable\n 70\n%s\n" % len(self.layers)) - for i in range(len(self.layers)): - self.dxf_add(" 0\nLAYER\n 5\n%x\n100\nAcDbSymbolTableRecord\n100\nAcDbLayerTableRecord\n 2\n%s\n 70\n0\n 6\nCONTINUOUS\n" % (i + 80, self.layers[i])) - self.dxf_add(dxf_templates.r14_style) - - scale = eval(self.options.units) - if not scale: - scale = 25.4/96 # if no scale is specified, assume inch as baseunit - scale /= self.unittouu('1px') - h = self.unittouu(self.getDocumentHeight()) - doc = self.document.getroot() - # process viewBox height attribute to correct page scaling - viewBox = doc.get('viewBox') - if viewBox: - viewBox2 = viewBox.split(',') - if len(viewBox2) < 4: - viewBox2 = viewBox.split(' ') - scale *= h / self.unittouu(self.addDocumentUnit(viewBox2[3])) - self.groupmat = [[[scale, 0.0, 0.0], [0.0, -scale, h*scale]]] - self.process_group(doc) - if self.options.ROBO == 'true': - self.ROBO_output() - if self.options.POLY == 'true': - self.LWPOLY_output() - self.dxf_add(dxf_templates.r14_footer) - #Warn user if layer data seems wrong - if self.options.layer_name and self.options.layer_option and self.options.layer_option=='name': - for layer in self.options.layer_name: - if not layer in self.layernames: - inkex.errormsg(_("Warning: Layer '%s' not found!") % (layer)) - -if __name__ == '__main__': - e = MyEffect() - e.affect() - - -# 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 deleted file mode 100755 index 11be0fc85..000000000 --- a/share/extensions/dxf_templates.py +++ /dev/null @@ -1,625 +0,0 @@ -#!/usr/bin/env python -r14_header = ''' 0 -SECTION - 2 -HEADER - 9 -$ACADVER - 1 -AC1014 - 9 -$HANDSEED - 5 -FFFF - 9 -$MEASUREMENT - 70 - 1 - 0 -ENDSEC - 0 -SECTION - 2 -TABLES - 0 -TABLE - 2 -VPORT - 5 -8 -330 -0 -100 -AcDbSymbolTable - 70 - 4 - 0 -VPORT - 5 -2E -330 -8 -100 -AcDbSymbolTableRecord -100 -AcDbViewportTableRecord - 2 -*ACTIVE - 70 - 0 - 10 -0.0 - 20 -0.0 - 11 -1.0 - 21 -1.0 - 12 -210.0 - 22 -148.5 - 13 -0.0 - 23 -0.0 - 14 -10.0 - 24 -10.0 - 15 -10.0 - 25 -10.0 - 16 -0.0 - 26 -0.0 - 36 -1.0 - 17 -0.0 - 27 -0.0 - 37 -0.0 - 40 -341.0 - 41 -1.24 - 42 -50.0 - 43 -0.0 - 44 -0.0 - 50 -0.0 - 51 -0.0 - 71 - 0 - 72 - 100 - 73 - 1 - 74 - 3 - 75 - 0 - 76 - 0 - 77 - 0 - 78 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -LTYPE - 5 -5 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -LTYPE - 5 -14 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BYBLOCK - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0.0 - 0 -LTYPE - 5 -15 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BYLAYER - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0.0 - 0 -LTYPE - 5 -16 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CONTINUOUS - 70 - 0 - 3 -Solid line - 72 - 65 - 73 - 0 - 40 -0.0 - 0 -ENDTAB - 0 -TABLE -''' - - -r14_style = ''' 0 -ENDTAB - 0 -TABLE - 2 -STYLE - 5 -3 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -STYLE - 5 -11 -330 -3 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -STANDARD - 70 - 0 - 40 -0.0 - 41 -1.0 - 50 -0.0 - 71 - 0 - 42 -2.5 - 3 -txt - 4 - - 0 -ENDTAB - 0 -TABLE - 2 -VIEW - 5 -6 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -UCS - 5 -7 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -APPID - 5 -9 -330 -0 -100 -AcDbSymbolTable - 70 - 2 - 0 -APPID - 5 -12 -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -ACAD - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -DIMSTYLE - 5 -A -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -DIMSTYLE -105 -27 -330 -A -100 -AcDbSymbolTableRecord -100 -AcDbDimStyleTableRecord - 2 -ISO-25 - 70 - 0 - 3 - - 4 - - 5 - - 6 - - 7 - - 40 -1.0 - 41 -2.5 - 42 -0.625 - 43 -3.75 - 44 -1.25 - 45 -0.0 - 46 -0.0 - 47 -0.0 - 48 -0.0 -140 -2.5 -141 -2.5 -142 -0.0 -143 -0.03937007874016 -144 -1.0 -145 -0.0 -146 -1.0 -147 -0.625 - 71 - 0 - 72 - 0 - 73 - 0 - 74 - 0 - 75 - 0 - 76 - 0 - 77 - 1 - 78 - 8 -170 - 0 -171 - 3 -172 - 1 -173 - 0 -174 - 0 -175 - 0 -176 - 0 -177 - 0 -178 - 0 -270 - 2 -271 - 2 -272 - 2 -273 - 2 -274 - 3 -340 -11 -275 - 0 -280 - 0 -281 - 0 -282 - 0 -283 - 0 -284 - 8 -285 - 0 -286 - 0 -287 - 3 -288 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -BLOCK_RECORD - 5 -1 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -BLOCK_RECORD - 5 -1F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*MODEL_SPACE - 0 -BLOCK_RECORD - 5 -1B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*PAPER_SPACE - 0 -ENDTAB - 0 -ENDSEC - 0 -SECTION - 2 -BLOCKS - 0 -BLOCK - 5 -20 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*MODEL_SPACE - 70 - 0 - 10 -0.0 - 20 -0.0 - 30 -0.0 - 3 -*MODEL_SPACE - 1 - - 0 -ENDBLK - 5 -21 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1C -330 -1B -100 -AcDbEntity - 67 - 1 - 8 -0 -100 -AcDbBlockBegin - 2 -*PAPER_SPACE - 1 - - 0 -ENDBLK - 5 -1D -330 -1B -100 -AcDbEntity - 67 - 1 - 8 -0 -100 -AcDbBlockEnd - 0 -ENDSEC - 0 -SECTION - 2 -ENTITIES -''' - - -r14_footer = ''' 0 -ENDSEC - 0 -SECTION - 2 -OBJECTS - 0 -DICTIONARY - 5 -C -330 -0 -100 -AcDbDictionary - 3 -ACAD_GROUP -350 -D - 3 -ACAD_MLINESTYLE -350 -17 - 0 -DICTIONARY - 5 -D -330 -C -100 -AcDbDictionary - 0 -DICTIONARY - 5 -1A -330 -C -100 -AcDbDictionary - 0 -DICTIONARY - 5 -17 -330 -C -100 -AcDbDictionary - 3 -STANDARD -350 -18 - 0 -DICTIONARY - 5 -19 -330 -C -100 -AcDbDictionary - 0 -ENDSEC - 0 -EOF''' diff --git a/share/extensions/edge3d.inx b/share/extensions/edge3d.inx deleted file mode 100644 index bc5f073ed..000000000 --- a/share/extensions/edge3d.inx +++ /dev/null @@ -1,23 +0,0 @@ -<?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> - <object-type>path</object-type> - <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 deleted file mode 100755 index 86df52908..000000000 --- a/share/extensions/edge3d.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 Terry Brown, terry_n_brown@yahoo.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplepath, sys, copy -from math import degrees, atan2 - -class Edge3d(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - opts = [('-a', '--angle', 'float', 'angle', 45.0, - 'angle of illumination, clockwise, 45 = upper right'), - ('-d', '--stddev', 'float', 'stddev', 5.0, - 'stdDeviation for Gaussian Blur'), - ('-H', '--blurheight', 'float', 'blurheight', 2.0, - 'height for Gaussian Blur'), - ('-W', '--blurwidth', 'float', 'blurwidth', 2.0, - 'width for Gaussian Blur'), - ('-s', '--shades', 'int', 'shades', 2, - 'shades, 2 = black and white, 3 = black, grey, white, etc.'), - ('-b', '--bw', 'inkbool', 'bw', False, - 'black and white, create only the fully black and white wedges'), - ('-p', '--thick', 'float', 'thick', 10., - 'stroke-width for path pieces'), - ] - for o in opts: - self.OptionParser.add_option(o[0], o[1], action="store", type=o[2], - dest=o[3], default=o[4], help=o[5]) - self.filtId = '' - - def angleBetween(self, start, end, angle): - """Return true if angle (degrees, clockwise, 0 = up/north) is between - angles start and end""" - def f(x): - """Maybe add 360 to x""" - if x < 0: return x + 360. - return x - # rotate all inputs by start, => start = 0 - a = f(f(angle) - f(start)) - e = f(f(end) - f(start)) - return a < e - - def effectX(self): - # size of a wedge for shade i, wedges come in pairs - delta = 360. / self.options.shades / 2. - - for shade in range(0, self.options.shades): - if self.options.bw and shade > 0 and shade < self.options.shades-1: - continue - self.start = [self.options.angle - delta * (shade+1)] - self.end = [self.options.angle - delta * (shade)] - self.start.append( self.options.angle + delta * (shade) ) - self.end.append( self.options.angle + delta * (shade+1) ) - self.makeShade(float(shade)/float(self.options.shades-1)) - - def effect(self): - """Check each internode to see if it's in one of the wedges - for the current shade. shade is a floating point 0-1 white-black""" - # size of a wedge for shade i, wedges come in pairs - delta = 360. / self.options.shades / 2. - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - p = simplepath.parsePath(d) - g = None - for shade in range(0, self.options.shades): - if (self.options.bw and shade > 0 and - shade < self.options.shades - 1): - continue - self.start = [self.options.angle - delta * (shade+1)] - self.end = [self.options.angle - delta * (shade)] - self.start.append( self.options.angle + delta * (shade) ) - self.end.append( self.options.angle + delta * (shade+1) ) - level=float(shade)/float(self.options.shades-1) - last = [] - result = [] - for cmd,params in p: - if cmd == 'Z': - last = [] - continue - if last: - a = degrees(atan2(params[-2:][0] - last[0], - params[-2:][1] - last[1])) - if (self.angleBetween(self.start[0], self.end[0], a) or - self.angleBetween(self.start[1], self.end[1], a)): - result.append(('M', last)) - result.append((cmd, params)) - last = params[-2:] - if result: - if g is None: - g = self.getGroup(node) - nn = copy.deepcopy(node) - nn.set('d',simplepath.formatPath(result)) - - col = 255 - int(255. * level) - a = 'fill:none;stroke:#%02x%02x%02x;stroke-opacity:1;stroke-width:10;%s' % ((col,)*3 + (self.filtId,)) - nn.set('style',a) - g.append(nn) - - def getGroup(self, node): - defs = self.document.getroot().xpath('//svg:defs', namespaces=inkex.NSS) - if defs: - defs = defs[0] - # make a clipped group, clip with clone of original, clipped group - # include original and group of paths - clip = inkex.etree.SubElement(defs,inkex.addNS('clipPath','svg')) - clip.append(copy.deepcopy(node)) - clipId = self.uniqueId('clipPath') - clip.set('id', clipId) - clipG = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg')) - g = inkex.etree.SubElement(clipG,inkex.addNS('g','svg')) - clipG.set('clip-path', 'url(#'+clipId+')') - # make a blur filter reference by the style of each path - filt = inkex.etree.SubElement(defs,inkex.addNS('filter','svg')) - filtId = self.uniqueId('filter') - self.filtId = 'filter:url(#%s);' % filtId - for k, v in [('id', filtId), ('height', str(self.options.blurheight)), - ('width', str(self.options.blurwidth)), - ('x', '-0.5'), ('y', '-0.5')]: - filt.set(k, v) - fe = inkex.etree.SubElement(filt,inkex.addNS('feGaussianBlur','svg')) - fe.set('stdDeviation', str(self.options.stddev)) - else: - # can't find defs, just group paths - g = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg')) - g.append(node) - - return g - -if __name__ == '__main__': - e = Edge3d() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/embed_raster_in_svg.pl b/share/extensions/embed_raster_in_svg.pl deleted file mode 100755 index ee3bf295e..000000000 --- a/share/extensions/embed_raster_in_svg.pl +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/perl - -#---------------------------------------------------------------------------------------------- -# embed_raster_in_svg -# B. Crowell, crowellXX at lightandmatter.com (replace XX with last two digits of current year) -# (c) 2004 B. Crowell -# This program is available under version 2 of the GPL License, http://www.gnu.org/copyleft/gpl.html, -# or, at your option, under the same license as Perl. -# For information about this program, scroll down in the source code, or invoke the program -# without any command-line arguments. -#---------------------------------------------------------------------------------------------- - -use strict; - -use MIME::Base64; -use Cwd; -use File::Basename; - -my $info = <<'INFO'; - usage: - embed_raster_in_svg foo.svg - Looks through the svg file for raster images that are given as links, rather than - being embedded, and embeds them in the file. The links must be local URIs, and if - they're relative, they must be relative to the directory where the svg file is located. - Starting with Inkscape 0.41, Inkscape can - handle embedded raster images as well as ones that are linked to (?). - Typical input looks like this: - <image - xlink:href="beer.jpg" - sodipodi:absref="/home/bcrowell/Documents/programming/embed_raster_in_svg/tests/beer.jpg" - width="202.50000" - height="537.00000" - id="image1084" - x="281.67480" - y="242.58502" /> - The output should look like this: - <image - width="202.50000" - height="537.00000" - id="image1084" - x="281.67480" - y="242.58502" - xlink:href="data:;base64,... - The SVG standard only allows the <image> tag to refer to data of type png, jpg, or svg, - and this script only handles png or jpg. -INFO - -undef $/; # slurp whole file - -my $svg = $ARGV[0]; - -if (!$svg) { - print $info; - exit; -} - -die "input file $svg not found" if ! -e $svg; -die "input file $svg not readable" if ! -r $svg; - -open(FILE,"<$svg") or die "error opening file $svg for input, $!"; -my $data = <FILE>; -close FILE; - -chdir dirname(Cwd::realpath($svg)); # so from now on, we can open raster files if they're relative to this directory - - -# The file is now in memory. -# First we go once through it and (1) find out if there are indeed any links to raster images, -# (2) rearrange things a little so that the (lengthy) base64 data will be the last attribute of the -# image tag. - -my $n = 0; -my @raster_files = (); -$data =~ - s@\<image\s+((?:(?:\w|\:)+\=\"[^"]*\"\s*)*)xlink\:href=\"([^"]+)\"\s*((?:(?:\w|:)+\=\"[^"]*\"\s*)*)\/>@<imageHOBBITSES $1 $3 ITHURTSUS\"$2\"MYPRECIOUSS />@g; -while ($data=~m@<imageHOBBITSES\s*(?:(?:(?:\w|\:)+\=\"[^"]*\"\s*)*)ITHURTSUS\"([^"]+)\"MYPRECIOUSS />@g) { - my $raster = $1; - die "error, raster filename $raster contains a double quote" if $raster=~m/\"/; - if (!($raster=~m/data\:\;/)) { - ++$n; - push @raster_files,$raster; - } -} - -if ($n==0) { - print "no embedded jpgs found in file $svg\n"; - exit; -} - - -# Eliminate sodipodi:absref attributes. If these are present, Inkscape looks for the linked -# file, and ignores the embedded data. Also, get rid of those nasty hobbitses. -$data=~s@(<image)HOBBITSES\s*((?:(?:\w|\:)+\=\"[^"]*\"\s*)*)sodipodi\:absref\=\"[^"]+\"\s*((:?(?:\w|\:)+\=\"[^"]*\"\s*)*ITHURTSUS)@$1 $2 $3@g; -$data=~s@(<image)HOBBITSES@$1@g; - - -# Now embed the data: - -foreach my $raster(@raster_files) { - die "file $raster not found relative to directory ".getcwd() if ! -e $raster; - die "file $raster is nor readable" if ! -r $raster; - open(RASTER,"<$raster") or die "error opening file $raster for input, $!"; - my $raster_data = <RASTER>; - close RASTER; - my $type = ''; - $type='image/png' if $raster_data=~m/^\x{89}PNG/; - $type='image/jpg' if $raster_data=~m/^\x{ff}\x{d8}/; - die "file $raster does not appear to be of type PNG or JPG" unless $type; - my $raster_data_base64 = encode_base64($raster_data); - ($data =~ s@ITHURTSUS\"$raster\"MYPRECIOUSS@\n xlink:href=\"data\:$type\;base64,$raster_data_base64\"@) or die "error embedding data for $raster"; - print "embedded raster file $raster, $type\n"; -} -my $bak = "$svg.bak"; -rename $svg,$bak or die "error renaming file $svg to $bak, $!"; -open(FILE,">$svg") or die "error creating new version of file $svg for output, $!"; -print FILE $data; -close FILE; - - - - - diff --git a/share/extensions/embedimage.inx b/share/extensions/embedimage.inx deleted file mode 100644 index c699e0446..000000000 --- a/share/extensions/embedimage.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Embed Images</_name> - <id>org.ekips.filter.embedimage</id> - <dependency type="executable" location="extensions">embedimage.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="selectedonly" type="boolean" _gui-text="Embed only selected images">false</param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Images"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">embedimage.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/embedimage.py b/share/extensions/embedimage.py deleted file mode 100755 index 33819a5b0..000000000 --- a/share/extensions/embedimage.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2005,2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import base64 -import os -import sys -import urllib -import urlparse -# local library -import inkex - - -class Embedder(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--selectedonly", - action="store", type="inkbool", - dest="selectedonly", default=False, - help="embed only selected images") - - def effect(self): - # if slectedonly is enabled and there is a selection only embed selected - # images. otherwise embed all images - if (self.options.selectedonly): - self.embedSelected(self.document, self.selected) - else: - self.embedAll(self.document) - - def embedSelected(self, document, selected): - self.document=document - self.selected=selected - if (self.options.ids): - for id, node in selected.iteritems(): - if node.tag == inkex.addNS('image','svg'): - self.embedImage(node) - - def embedAll(self, document): - self.document=document #not that nice... oh well - path = '//svg:image' - for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): - self.embedImage(node) - - def embedImage(self, node): - xlink = node.get(inkex.addNS('href','xlink')) - if xlink is None or xlink[:5] != 'data:': - absref=node.get(inkex.addNS('absref','sodipodi')) - url=urlparse.urlparse(xlink) - href=urllib.url2pathname(url.path) - - path='' - #path selection strategy: - # 1. href if absolute - # 2. realpath-ified href - # 3. absref, only if the above does not point to a file - if (href != None): - path=os.path.realpath(href) - if (not os.path.isfile(path)): - if (absref != None): - path=absref - - try: - path=unicode(path, "utf-8") - except TypeError: - path=path - - if (not os.path.isfile(path)): - inkex.errormsg(_('No xlink:href or sodipodi:absref attributes found, or they do not point to an existing file! Unable to embed image.')) - if path: - inkex.errormsg(_("Sorry we could not locate %s") % str(path)) - - if (os.path.isfile(path)): - file = open(path,"rb").read() - embed=True - if (file[:4]=='\x89PNG'): - type='image/png' - elif (file[:2]=='\xff\xd8'): - type='image/jpeg' - elif (file[:2]=='BM'): - type='image/bmp' - elif (file[:6]=='GIF87a' or file[:6]=='GIF89a'): - type='image/gif' - elif (file[:4]=='MM\x00\x2a' or file[:4]=='II\x2a\x00'): - type='image/tiff' - #ico files lack any magic... therefore we check the filename instead - elif(path.endswith('.ico')): - type='image/x-icon' #official IANA registered MIME is 'image/vnd.microsoft.icon' tho - elif(path.endswith('.svg')): - type='image/svg+xml' - else: - embed=False - if (embed): - node.set(inkex.addNS('href','xlink'), 'data:%s;base64,%s' % (type, base64.encodestring(file))) - if (absref != None): - del node.attrib[inkex.addNS('absref',u'sodipodi')] - else: - inkex.errormsg(_("%s is not of type image/svg, image/png, image/jpeg, image/bmp, image/gif, image/tiff, or image/x-icon") % path) - -if __name__ == '__main__': - e = Embedder() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/embedselectedimages.inx b/share/extensions/embedselectedimages.inx deleted file mode 100644 index aa159c6a9..000000000 --- a/share/extensions/embedselectedimages.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Embed Selected Images</_name> - <id>org.ekips.filter.embedselectedimages</id> - <dependency type="executable" location="extensions">embedimage.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="selectedonly" type="boolean" gui-hidden="true" _gui-text="Embed only selected images">true</param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <script> - <command reldir="extensions" interpreter="python">embedimage.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_business_card.inx b/share/extensions/empty_business_card.inx deleted file mode 100644 index e08cd9eef..000000000 --- a/share/extensions/empty_business_card.inx +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Business Card</_name> - <id>org.inkscape.render.empty_business_card</id> - <dependency type="executable" location="extensions">empty_business_card.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="size" _gui-text="Business card size:" type="enum"> - <item value="74mmx52mm">74mm x 52mm (A8)</item> - <item value="85mmx55mm">85mm x 55mm (Europe)</item> - <item value="90mmx55mm">90mm x 55mm (Australia, India, ...)</item> - <item value="91mmx55mm">91mm x 55mm (Japan)</item> - <item value="90mmx54mm">90mm x 54mm (China, ...)</item> - <item value="90mmx50mm">90mm x 50mm (India, Russia, ...)</item> - <item value="3.5inx2in">3.5in x 2in (United States, Canada)</item> - </param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Business Card...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Business card of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-09</inkscape:date> - <inkscape:_keywords>business card</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_business_card.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_business_card.py b/share/extensions/empty_business_card.py deleted file mode 100755 index 586c37abc..000000000 --- a/share/extensions/empty_business_card.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex -import re - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", action="store", type="string", dest="card_size", default="90mmx55mm", help="Business card size") - - def effect(self): - - size = self.options.card_size - - p = re.compile('([0-9.]*)([a-z][a-z])x([0-9.]*)([a-z][a-z])') - m = p.match( size ) - width = m.group(1) - width_unit = m.group(2) - height = m.group(3) - height_unit = m.group(4) - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", width + width_unit) - root.set("height", height + height_unit) - root.set("viewBox", "0 0 " + width + " " + height ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), width_unit) - - width_int = int(self.uutounit(float(width), 'px')) - height_int = int(self.uutounit(float(height), 'px')) - - namedview.set(inkex.addNS('zoom', 'inkscape'), str(2) ) - namedview.set(inkex.addNS('cx', 'inkscape'), str(width_int/2.0) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(height_int/2.0) ) - - -c = C() -c.affect() diff --git a/share/extensions/empty_desktop.inx b/share/extensions/empty_desktop.inx deleted file mode 100644 index 449f2ec66..000000000 --- a/share/extensions/empty_desktop.inx +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Desktop</_name> - <id>org.inkscape.render.empty_desktop</id> - <dependency type="executable" location="extensions">empty_desktop.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="size" _gui-text="Desktop size:" type="enum"> - <item value="Custom">Custom</item> - <item value="640x480">640x480 (VGA)</item> - <item value="800x600">800x600 (SVGA)</item> - <item value="1024x768">1024x768 (XGA)</item> - <item value="1366x768">1366x768 (HD)</item> - <item value="1600x900">1600x900 (HD+)</item> - <item value="1600x1200">1600x1200 (UXGA)</item> - <item value="1920x1080">1920x1080 (FHD)</item> - <item value="1920x1200">1920x1200 (WUXGA)</item> - <item value="2560x1600">2560x1600 (WQXGA)</item> - <item value="3840x2160">3840x2160 (4K)</item> - <item value="5120x2880">5120x2880 (5K)</item> - <item value="7680x4320">7680x4320 (8K)</item> - </param> - - <!-- Maximum size is '16k' --> - <param name="width" _gui-text="Custom Width:" type="int" min="240" max="15360">1920</param> - <param name="height" _gui-text="Custom Height:" type="int" min="160" max="8640">1080</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Desktop...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Empty desktop of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-09</inkscape:date> - <inkscape:_keywords>empty desktop</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_desktop.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_desktop.py b/share/extensions/empty_desktop.py deleted file mode 100755 index 31cb35f9d..000000000 --- a/share/extensions/empty_desktop.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex -import re - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", action="store", type="string", dest="desktop_size", default="16", help="Desktop size") - - self.OptionParser.add_option("-w", "--width", action="store", type="int", dest="desktop_width", default="1920", help="Custom width") - self.OptionParser.add_option("-z", "--height", action="store", type="int", dest="desktop_height", default="1080", help="Custom height") - - def effect(self): - - size = self.options.desktop_size - width = self.options.desktop_width - height = self.options.desktop_height - - if size != "Custom": - p = re.compile('([0-9]*)x([0-9]*)') - m = p.match( size ) - width = int(m.group(1)) - height = int(m.group(2)) - - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(width) + 'px') - root.set("height", str(height) + 'px') - root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), 'px') - - namedview.set(inkex.addNS('cx', 'inkscape'), str(width/2.0) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(height/2.0) ) - - -c = C() -c.affect() diff --git a/share/extensions/empty_dvd_cover.inx b/share/extensions/empty_dvd_cover.inx deleted file mode 100644 index facb523d1..000000000 --- a/share/extensions/empty_dvd_cover.inx +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>DVD Cover</_name> - <id>org.inkscape.render.empty_dvd_cover</id> - <dependency type="executable" location="extensions">empty_dvd_cover.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="spine" _gui-text="DVD spine width:" type="enum"> - <item value="14">Normal (14mm)</item> - <item value="9">Slim (9mm)</item> - <item value="7">Super Slim (7mm)</item> - <item value="5">Ultra Slim (5mm)</item> - </param> - - <param name="bleed" _gui-text="DVD cover bleed (mm):" type="float" min="0" max="25">3</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>DVD Cover...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>DVD cover of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-10</inkscape:date> - <inkscape:_keywords>dvd cover</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_dvd_cover.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_dvd_cover.py b/share/extensions/empty_dvd_cover.py deleted file mode 100755 index 1456de51d..000000000 --- a/share/extensions/empty_dvd_cover.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--spine", action="store", type="string", dest="dvd_cover_spine", default="normal", help="Dvd spine width") - self.OptionParser.add_option("-b", "--bleed", action="store", type="float", dest="dvd_cover_bleed", default="3", help="Bleed (extra area around image") - - def create_horizontal_guideline(self, name, position): - self.create_guideline(name, "0,1", 0, position) - - def create_vertical_guideline(self, name, position): - self.create_guideline(name, "1,0", position, 0) - - def create_guideline(self, label, orientation, x,y): - namedview = self.root.find(inkex.addNS('namedview', 'sodipodi')) - guide = inkex.etree.SubElement(namedview, inkex.addNS('guide', 'sodipodi')) - guide.set("orientation", orientation) - guide.set("position", str(x)+","+str(y)) - # No need to set label (causes translation problems, etc.) - # guide.set(inkex.addNS('label', 'inkscape'), label) - - def effect(self): - - # Dimensions in mm - width = 259.0 # Before adding spine width or bleed - height = 183.0 # Before adding bleed - - bleed = self.options.dvd_cover_bleed - spine = float( self.options.dvd_cover_spine ) - - width += spine - width += 2.0 * bleed - height += 2.0 * bleed - - self.root = self.document.getroot() - self.root.set("id", "SVGRoot") - self.root.set("width", str(width) + 'mm') - self.root.set("height", str(height) + 'mm') - self.root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - namedview = self.root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( self.root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), "mm") - - # Until units are supported in 'cx', etc. - namedview.set(inkex.addNS('cx', 'inkscape'), str(self.uutounit( width, 'px' )/2.0 ) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(self.uutounit( height, 'px' )/2.0 ) ) - - self.create_horizontal_guideline("bottom", str(self.uutounit( bleed, 'px' )) ) - self.create_horizontal_guideline("top", str(self.uutounit( height-bleed, 'px' )) ) - self.create_vertical_guideline("left edge", str(self.uutounit( bleed, 'px' )) ) - self.create_vertical_guideline("left spline", str(self.uutounit( (width-spine)/2.0,'px' )) ) - self.create_vertical_guideline("right spline", str(self.uutounit( (width+spine)/2.0,'px' )) ) - self.create_vertical_guideline("left edge", str(self.uutounit( width-bleed, 'px' )) ) - -c = C() -c.affect() diff --git a/share/extensions/empty_generic.inx b/share/extensions/empty_generic.inx deleted file mode 100644 index af72a7c5a..000000000 --- a/share/extensions/empty_generic.inx +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Generic Canvas</_name> - <id>org.inkscape.render.empty_generic_canvas</id> - <dependency type="executable" location="extensions">empty_generic.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="width" _gui-text="Custom Width:" type="float" min="1" max="15360">800</param> - <param name="height" _gui-text="Custom Height:" type="float" min="1" max="8640">600</param> - - <param name="unit" _gui-text="SVG Unit:" type="enum"> - <item value="px">'px'</item> - <item value="in">'in'</item> - <item value="mm">'mm'</item> - <item value="cm">'cm'</item> - <item value="pc">'pc'</item> - <item value="pt">'pt'</item> - </param> - - <param name="background" _gui-text="Canvas background:" type="enum"> - <item value="normal">Normal</item> - <item value="black">Black Opaque</item> - <item value="gray">Gray Opaque</item> - <item value="white">White Opaque</item> - </param> - - <param name="noborder" type="boolean" _gui-text="Hide border">false</param> - - <!-- - <param name="layer" type="boolean" _gui-text="Include default layer">true</param> - --> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Generic canvas...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Generic canvas of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-09</inkscape:date> - <inkscape:_keywords>empty generic canvas</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_generic.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_generic.py b/share/extensions/empty_generic.py deleted file mode 100755 index 8dd66d5df..000000000 --- a/share/extensions/empty_generic.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex -import re - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-w", "--width", action="store", type="int", dest="generic_width", default="1920", help="Custom width") - self.OptionParser.add_option("-z", "--height", action="store", type="int", dest="generic_height", default="1080", help="Custom height") - self.OptionParser.add_option("-u", "--unit", action="store", type="string", dest="generic_unit", default="px", help="SVG Unit") - self.OptionParser.add_option("-b", "--background", action="store", type="string", dest="generic_background", default="normal", help="Canvas background") - self.OptionParser.add_option("-n", "--noborder", action="store", type="inkbool", dest="generic_noborder", default=False) - # self.OptionParser.add_option("-l", "--layer", action="store", type="inkbool", dest="generic_layer", default=True) - - def effect(self): - - width = self.options.generic_width - height = self.options.generic_height - unit = self.options.generic_unit - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(width) + unit) - root.set("height", str(height) + unit) - root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), unit) - - # Until units are supported in 'cx', etc. - namedview.set(inkex.addNS('zoom', 'inkscape'), str(512.0/self.uutounit( width, 'px' )) ) - namedview.set(inkex.addNS('cx', 'inkscape'), str(self.uutounit( width, 'px' )/2.0 ) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(self.uutounit( height, 'px' )/2.0 ) ) - - if self.options.generic_background == "white": - namedview.set( 'pagecolor', "#ffffff" ) - namedview.set( 'bordercolor', "#666666" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.generic_background == "gray": - namedview.set( 'pagecolor', "#808080" ) - namedview.set( 'bordercolor', "#444444" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.generic_background == "black": - namedview.set( 'pagecolor', "#000000" ) - namedview.set( 'bordercolor', "#999999" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.generic_noborder: - pagecolor = namedview.get( 'pagecolor' ) - namedview.set( 'bordercolor', pagecolor ) - namedview.set( 'borderopacity', "0" ) - - # This needs more thought... we need to set "Current layer" to (root), how? - # if self.options.generic_layer: - # # Add layer - # inkex.debug( "We want a layer" ) - # else: - # # Remove layer id default document (assuming only one) - # inkex.debug( "We don't want a layer" ) - # layer_node = self.current_layer - # if layer_node is not None: - # inkex.debug( "We have layer" ) - # root.remove(layer_node) - # try: - # del namedview.attrib[ inkex.addNS('current-layer', 'inkscape') ] - # except: - # pass - - -c = C() -c.affect() diff --git a/share/extensions/empty_icon.inx b/share/extensions/empty_icon.inx deleted file mode 100644 index 9e36b9d20..000000000 --- a/share/extensions/empty_icon.inx +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Icon</_name> - <id>org.inkscape.render.empty_icon</id> - <dependency type="executable" location="extensions">empty_icon.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="size" _gui-text="Icon size:" type="int" min="8" max="256">16</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Icon...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Empty icon of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-09</inkscape:date> - <inkscape:_keywords>empty icon</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_icon.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_icon.py b/share/extensions/empty_icon.py deleted file mode 100755 index 979edbae4..000000000 --- a/share/extensions/empty_icon.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", action="store", type="int", dest="icon_size", default="16", help="Icon size") - - def effect(self): - - size = self.options.icon_size - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(size) + 'px') - root.set("height", str(size) + 'px') - root.set("viewBox", "0 0 " + str(size) + " " + str(size) ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), 'px') - - namedview.set(inkex.addNS('zoom', 'inkscape'), str(256.0/size) ) - namedview.set(inkex.addNS('cx', 'inkscape'), str(size/2.0) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(size/2.0) ) - namedview.set(inkex.addNS('grid-bbox', 'inkscape'), "true" ) - - - -c = C() -c.affect() diff --git a/share/extensions/empty_page.inx b/share/extensions/empty_page.inx deleted file mode 100644 index 6882b7273..000000000 --- a/share/extensions/empty_page.inx +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Page</_name> - <id>org.inkscape.render.empty_page</id> - <dependency type="executable" location="extensions">empty_page.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="size" _gui-text="Page size:" type="enum"> - <item value="a3">A3</item> - <item value="a4">A4</item> - <item value="a5">A5</item> - <item value="letter">letter</item> - </param> - - <param name="orientation" _gui-text="Page orientation:" type="enum"> - <item value="horizontal">Horizontal</item> - <item value="vertical">Vertical</item> - </param> - - <param name="background" _gui-text="Page background:" type="enum"> - <item value="normal">Normal</item> - <item value="black">Black Opaque</item> - <item value="gray">Gray Opaque</item> - <item value="white">White Opaque</item> - </param> - - <param name="noborder" type="boolean" _gui-text="Hide border">false</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Page...</inkscape:_name> - <inkscape:author>Jan Darowski, updated by Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Empty page of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-06</inkscape:date> - <inkscape:_keywords>empty sheet a4 a3 a5 letter black white opaque</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_page.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_page.py b/share/extensions/empty_page.py deleted file mode 100755 index 3c1f67041..000000000 --- a/share/extensions/empty_page.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python - -# Rewritten by Tavmjong Bah to add correct viewBox, inkscape:cx, etc. attributes - -import inkex - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", action="store", type="string", dest="page_size", default="a4", help="Page size") - self.OptionParser.add_option("-o", "--orientation", action="store", type="string", dest="page_orientation", default="vertical", help="Page orientation") - self.OptionParser.add_option("-b", "--background", action="store", type="string", dest="page_background", default="normal", help="Page background") - self.OptionParser.add_option("-n", "--noborder", action="store", type="inkbool", dest="page_noborder", default=False) - - def effect(self): - - width = 300 - height = 300 - units = 'px' - - if self.options.page_size == "a5": - width = 148 - height= 210 - units = 'mm' - - if self.options.page_size == "a4": - width = 210 - height= 297 - units = 'mm' - - if self.options.page_size == "a3": - width = 297 - height= 420 - units = 'mm' - - if self.options.page_size == "letter": - width = 8.5 - height = 11 - units = 'in' - - if self.options.page_orientation == "horizontal": - width, height = height, width - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(width) + units) - root.set("height", str(height) + units) - root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), units) - - # Until units are supported in 'cx', etc. - namedview.set(inkex.addNS('cx', 'inkscape'), str(self.uutounit( width, 'px' )/2.0 ) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(self.uutounit( height, 'px' )/2.0 ) ) - - - if self.options.page_background == "white": - namedview.set( 'pagecolor', "#ffffff" ) - namedview.set( 'bordercolor', "#666666" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.page_background == "gray": - namedview.set( 'pagecolor', "#808080" ) - namedview.set( 'bordercolor', "#444444" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.page_background == "black": - namedview.set( 'pagecolor', "#000000" ) - namedview.set( 'bordercolor', "#999999" ) - namedview.set(inkex.addNS('pageopacity', 'inkscape'), "1.0" ) - namedview.set(inkex.addNS('pageshadow', 'inkscape'), "0" ) - - if self.options.page_noborder: - pagecolor = namedview.get( 'pagecolor' ) - namedview.set( 'bordercolor', pagecolor ) - namedview.set( 'borderopacity', "0" ) - -c = C() -c.affect() diff --git a/share/extensions/empty_video.inx b/share/extensions/empty_video.inx deleted file mode 100644 index 8ca148cfc..000000000 --- a/share/extensions/empty_video.inx +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Video Screen</_name> - <id>org.inkscape.render.empty_video</id> - <dependency type="executable" location="extensions">empty_video.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="size" _gui-text="Video size:" type="enum"> - <item value="Custom">Custom</item> - <item value="720x486">720x486 (NTSC)</item> - <item value="720x576">720x576 (PAL)</item> - <item value="1920x1080">1920x1080 (HDTV)</item> - <item value="3840x2160">3840x2160 (4K)</item> - <item value="7680x4320">7680x4320 (8K)</item> - </param> - - <!-- Maximum size is '16k' --> - <param name="width" _gui-text="Custom Width:" type="int" min="240" max="15360">1920</param> - <param name="height" _gui-text="Custom Height:" type="int" min="160" max="8640">1080</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Video...</inkscape:_name> - <inkscape:author>Tavmjong Bah</inkscape:author> - <inkscape:_shortdesc>Video screen of chosen size.</inkscape:_shortdesc> - <inkscape:date>2014-10-09</inkscape:date> - <inkscape:_keywords>empty video</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">empty_video.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/empty_video.py b/share/extensions/empty_video.py deleted file mode 100755 index 4b440704c..000000000 --- a/share/extensions/empty_video.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python - -# Written by Tavmjong Bah - -import inkex -import re - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", action="store", type="string", dest="video_size", default="16", help="Video size") - - self.OptionParser.add_option("-w", "--width", action="store", type="int", dest="video_width", default="1920", help="Custom width") - self.OptionParser.add_option("-z", "--height", action="store", type="int", dest="video_height", default="1080", help="Custom height") - - def effect(self): - - size = self.options.video_size - width = self.options.video_width - height = self.options.video_height - - if size != "Custom": - p = re.compile('([0-9]*)x([0-9]*)') - m = p.match( size ) - width = int(m.group(1)) - height = int(m.group(2)) - - - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(width) + 'px') - root.set("height", str(height) + 'px') - root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), 'px') - - namedview.set(inkex.addNS('cx', 'inkscape'), str(width/2.0) ) - namedview.set(inkex.addNS('cy', 'inkscape'), str(height/2.0) ) - - -c = C() -c.affect() diff --git a/share/extensions/eps_input.inx b/share/extensions/eps_input.inx deleted file mode 100644 index 411d82cd8..000000000 --- a/share/extensions/eps_input.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>EPS Input</_name> - <id>org.inkscape.input.eps</id> - <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> - <_filetypename>Encapsulated PostScript (*.eps)</_filetypename> - <_filetypetooltip>Encapsulated PostScript</_filetypetooltip> - <output_extension>org.inkscape.output.eps</output_extension> - </input> - <script> - <command reldir="extensions" interpreter="python">ps2pdf-ext.py</command> - <helper_extension>org.inkscape.input.pdf</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/eqtexsvg.inx b/share/extensions/eqtexsvg.inx deleted file mode 100644 index 583c1b649..000000000 --- a/share/extensions/eqtexsvg.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>LaTeX</_name> - <id>org.inkscape.effect.eqtexsvg</id> - <dependency type="executable" location="extensions">eqtexsvg.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="path">latex</dependency> - <dependency type="executable" location="path">dvips</dependency> - <dependency type="executable" location="path">pstoedit</dependency> - <param name="formule" type="string" _gui-text="LaTeX input: ">\(\displaystyle\frac{\pi^2}{6}=\lim_{n \to \infty}\sum_{k=1}^n \frac{1}{k^2}\)</param> - <param name="packages" type="string" _gui-text="Additional packages (comma-separated): "></param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">eqtexsvg.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/eqtexsvg.py b/share/extensions/eqtexsvg.py deleted file mode 100755 index 99d3c0660..000000000 --- a/share/extensions/eqtexsvg.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python -# -*- coding: cp1252 -*- -""" -eqtexsvg.py -functions for converting LaTeX equation string into SVG path -This extension need, to work properly: - - a TeX/LaTeX distribution (MiKTeX ...) - - pstoedit software: <http://www.pstoedit.net/pstoedit> - -Copyright (C) 2006 Julien Vitard <julienvitard@gmail.com> - -2010-04-04: Added support for custom packages - Christoph Schmidt-Hieber <christsc@gmx.de> - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -""" - -import inkex, os, tempfile, sys, xml.dom.minidom - -def parse_pkgs(pkgstring): - pkglist = pkgstring.replace(" ","").split(",") - header = "" - for pkg in pkglist: - header += "\\usepackage{%s}\n" % pkg - - return header - -def create_equation_tex(filename, equation, add_header=""): - tex = open(filename, 'w') - tex.write("""%% processed with eqtexsvg.py -\\documentclass{article} -\\usepackage{amsmath} -\\usepackage{amssymb} -\\usepackage{amsfonts} -""") - tex.write(add_header) - tex.write("""\\thispagestyle{empty} -\\begin{document} -""") - tex.write(equation) - tex.write("\n\\end{document}\n") - tex.close() - -def svg_open(self,filename): - doc_width = self.unittouu(self.document.getroot().get('width')) - doc_height = self.unittouu(self.document.getroot().get('height')) - doc_sizeH = min(doc_width,doc_height) - doc_sizeW = max(doc_width,doc_height) - - def clone_and_rewrite(self, node_in): - in_tag = node_in.tag.rsplit('}',1)[-1] - if in_tag != 'svg': - node_out = inkex.etree.Element(inkex.addNS(in_tag,'svg')) - for name in node_in.attrib: - node_out.set(name, node_in.attrib[name]) - else: - node_out = inkex.etree.Element(inkex.addNS('g','svg')) - for c in node_in.iterchildren(): - c_tag = c.tag.rsplit('}',1)[-1] - if c_tag in ('g', 'path', 'polyline', 'polygon'): - child = clone_and_rewrite(self, c) - if c_tag == 'g': - child.set('transform','matrix('+str(doc_sizeH/700.)+',0,0,'+str(-doc_sizeH/700.)+','+str(-doc_sizeH*0.25)+','+str(doc_sizeW*0.75)+')') - node_out.append(child) - - return node_out - - doc = inkex.etree.parse(filename) - svg = doc.getroot() - group = clone_and_rewrite(self, svg) - self.current_layer.append(group) - -class EQTEXSVG(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-f", "--formule", - action="store", type="string", - dest="formula", default="", - help="LaTeX formula") - self.OptionParser.add_option("-p", "--packages", - action="store", type="string", - dest="packages", default="", - help="Additional packages") - def effect(self): - - base_dir = tempfile.mkdtemp("", "inkscape-"); - latex_file = os.path.join(base_dir, "eq.tex") - aux_file = os.path.join(base_dir, "eq.aux") - log_file = os.path.join(base_dir, "eq.log") - ps_file = os.path.join(base_dir, "eq.ps") - dvi_file = os.path.join(base_dir, "eq.dvi") - svg_file = os.path.join(base_dir, "eq.svg") - out_file = os.path.join(base_dir, "eq.out") - err_file = os.path.join(base_dir, "eq.err") - - def clean(): - os.remove(latex_file) - os.remove(aux_file) - os.remove(log_file) - os.remove(ps_file) - os.remove(dvi_file) - os.remove(svg_file) - os.remove(out_file) - if os.path.exists(err_file): - os.remove(err_file) - os.rmdir(base_dir) - - if self.options.formula == "": - print >>sys.stderr, "empty LaTeX input. Nothing to be done" - return - - add_header = parse_pkgs(self.options.packages) - create_equation_tex(latex_file, self.options.formula, add_header) - os.system('latex "-output-directory=%s" -halt-on-error "%s" > "%s"' \ - % (base_dir, latex_file, out_file)) - try: - os.stat(dvi_file) - except OSError: - print >>sys.stderr, "invalid LaTeX input:" - print >>sys.stderr, self.options.formula - print >>sys.stderr, "temporary files were left in:", base_dir - sys.exit(1) - - os.system('dvips -q -f -E -D 600 -y 5000 -o "%s" "%s"' % (ps_file, dvi_file)) - # cd to base_dir is necessary, because pstoedit writes - # temporary files to cwd and needs write permissions - separator = ';' - if os.name == 'nt': - separator = '&&' - os.system('cd "%s" %s pstoedit -f plot-svg -dt -ssp "%s" "%s" > "%s" 2> "%s"' \ - % (base_dir, separator, ps_file, svg_file, out_file, err_file)) - - # forward errors to stderr but skip pstoedit header - if os.path.exists(err_file): - err_stream = open(err_file, 'r') - for line in err_stream: - if not line.startswith('pstoedit: version'): - sys.stderr.write(line + '\n') - err_stream.close() - - svg_open(self, svg_file) - - clean() - -if __name__ == '__main__': - e = EQTEXSVG() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/export_gimp_palette.inx b/share/extensions/export_gimp_palette.inx deleted file mode 100644 index b7a1b158e..000000000 --- a/share/extensions/export_gimp_palette.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Export as GIMP Palette</_name> - <id>com.kaioa.export_gimp_palette</id> - <dependency type="executable" location="extensions">export_gimp_palette.py</dependency> - <dependency type="executable" location="extensions">simplestyle.py</dependency> - <output> - <extension>.gpl</extension> - <mimetype>text/plain</mimetype> - <_filetypename>GIMP Palette (*.gpl)</_filetypename> - <_filetypetooltip>Exports the colors of this document as GIMP Palette</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">export_gimp_palette.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/export_gimp_palette.py b/share/extensions/export_gimp_palette.py deleted file mode 100755 index 9c04d6e34..000000000 --- a/share/extensions/export_gimp_palette.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -''' -Author: Jos Hirth, kaioa.com -License: GNU General Public License - http://www.gnu.org/licenses/gpl.html -Warranty: see above -''' - -DOCNAME='sodipodi:docname' - -# standard library -import sys -# third party -try: - from xml.dom.minidom import parse -except: - inkex.errormsg(_('The export_gpl.py module requires PyXML. Please download the latest version from http://pyxml.sourceforge.net/.')) - sys.exit() -# local library -import inkex -import simplestyle - -colortags=(u'fill',u'stroke',u'stop-color',u'flood-color',u'lighting-color') -colors={} - -def walk(node): - checkStyle(node) - if node.hasChildNodes(): - childs=node.childNodes - for child in childs: - walk(child) - -def checkStyle(node): - if hasattr(node,"hasAttributes") and node.hasAttributes(): - sa=node.getAttribute('style') - if sa!='': - styles=simplestyle.parseStyle(sa) - for c in range(len(colortags)): - if colortags[c] in styles.keys(): - addColor(styles[colortags[c]]) - -def addColor(col): - if simplestyle.isColor(col): - c=simplestyle.parseColor(col) - colors['%3i %3i %3i ' % (c[0],c[1],c[2])]=simplestyle.formatColoria(c).upper() - -stream = open(sys.argv[-1:][0],'r') -dom = parse(stream) -stream.close() -walk(dom) -print 'GIMP Palette\nName: %s\n#' % (dom.getElementsByTagName('svg')[0].getAttribute(DOCNAME).split('.')[0]) - -for k,v in sorted(colors.items()): - print k+v - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/extractimage.inx b/share/extensions/extractimage.inx deleted file mode 100644 index 9d1984168..000000000 --- a/share/extensions/extractimage.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Extract Image</_name> - <id>org.ekips.filter.extractimage</id> - <dependency type="executable" location="extensions">extractimage.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="selectedonly" type="boolean" _gui-text="Extract only selected images">True</param> - <param name="filepath" type="string" _gui-text="Path to save image:">none</param> - <_param name="desc" type="description" xml:space="preserve">* Don't type the file extension, it is appended automatically. -* A relative path (or a filename without path) is relative to the user's home directory.</_param> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Images"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">extractimage.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/extractimage.py b/share/extensions/extractimage.py deleted file mode 100755 index fe70de433..000000000 --- a/share/extensions/extractimage.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import base64 -import os -# local library -import inkex - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--desc") - self.OptionParser.add_option("-s", "--selectedonly", - action="store", type="inkbool", - dest="selectedonly", default=True, - help="extract only selected images") - self.OptionParser.add_option("--filepath", - action="store", type="string", - dest="filepath", default=None, - help="") - - def effect(self): - # if slectedonly is enabled and there is a selection only extractselected - # images. otherwise extract all images - if (self.options.selectedonly): - self.extractSelected(self.document, self.selected) - else: - self.extractAll(self.document) - - def extractSelected(self, document, selected): - self.document=document - self.selected=selected - if (self.options.ids): - for id, node in selected.iteritems(): - if node.tag == inkex.addNS('image','svg'): - self.extractImage(node) - - def extractAll(self, document): - self.document=document #not that nice... oh well - path = '//svg:image' - for node in self.document.getroot().xpath(path, namespaces=inkex.NSS): - self.extractImage(node) - - def extractImage(self, node): - mimesubext={ - 'png' : '.png', - 'svg+xml' : '.svg', - 'bmp' : '.bmp', - 'jpeg' : '.jpg', - 'jpg' : '.jpg', #bogus mime - 'icon' : '.ico', - 'gif' : '.gif' - } - - # exbed the first embedded image - path = self.options.filepath - if (path != ''): - if node.tag == inkex.addNS('image','svg'): - xlink = node.get(inkex.addNS('href','xlink')) - if (xlink[:4]=='data'): - comma = xlink.find(',') - if comma>0: - #get extension - fileext='' - semicolon = xlink.find(';') - if semicolon>0: - for sub in mimesubext.keys(): - if sub in xlink[5:semicolon].lower(): - fileext=mimesubext[sub] - pathwext=path+fileext - if os.path.isfile(pathwext): - pathwext=path + "_" + node.get("id") +fileext - if (not os.path.isabs(pathwext)): - if os.name == 'nt': - pathwext = os.path.join(os.environ['USERPROFILE'],pathwext) - else: - pathwext = os.path.join(os.path.expanduser("~"),pathwext) - inkex.errormsg(_('Image extracted to: %s') % pathwext) - break - #save - data = base64.decodestring(xlink[comma:]) - open(pathwext,'wb').write(data) - node.set(inkex.addNS('href','xlink'),os.path.realpath(pathwext)) #absolute for making in-mem cycles work - else: - inkex.errormsg(_('Unable to find image data.')) - -if __name__ == '__main__': - e = MyEffect() - e.affect() - - -# 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 deleted file mode 100644 index 02a1bd803..000000000 --- a/share/extensions/extrude.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Extrude</_name> - <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="enum" _gui-text="Mode:"> - <_item value="Lines">Lines</_item> - <_item value="Polygons">Polygons</_item> - </param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">extrude.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/extrude.py b/share/extensions/extrude.py deleted file mode 100755 index b11d0d36c..000000000 --- a/share/extensions/extrude.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -import inkex -import simplepath -import simplestyle -import simpletransform -import cubicsuperpath - -class Extrude(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - opts = [('-m', '--mode', 'string', 'mode', 'Lines', - 'Join paths with lines or polygons'), - ] - for o in opts: - self.OptionParser.add_option(o[0], o[1], action="store", type=o[2], - dest=o[3], default=o[4], help=o[5]) - - def effect(self): - paths = [] - for id, node in self.selected.iteritems(): - if node.tag == '{http://www.w3.org/2000/svg}path': - paths.append(node) - if len(paths) < 2: - inkex.errormsg(_('Need at least 2 paths selected')) - return - - pts = [cubicsuperpath.parsePath(paths[i].get('d')) - for i in range(len(paths))] - - for i in range(len(paths)): - if 'transform' in paths[i].keys(): - trans = paths[i].get('transform') - trans = simpletransform.parseTransform(trans) - simpletransform.applyTransformToPath(trans, pts[i]) - - for n1 in range(0, len(paths)): - for n2 in range(n1 + 1, len(paths)): - verts = [] - for i in range(0, min(map(len, pts))): - comp = [] - for j in range(0, min(len(pts[n1][i]), len(pts[n2][i]))): - comp.append([pts[n1][i][j][1][-2:], pts[n2][i][j][1][-2:]]) - verts.append(comp) - - if self.options.mode.lower() == 'lines': - line = [] - for comp in verts: - for n,v in enumerate(comp): - line += [('M', v[0])] - line += [('L', v[1])] - ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') - paths[0].xpath('..')[0].append(ele) - ele.set('d', simplepath.formatPath(line)) - style = { - 'fill': 'none', - 'stroke': '#000000', - 'stroke-opacity': 1, - 'stroke-width': self.unittouu('1px'), - } - ele.set('style', simplestyle.formatStyle(style)) - elif self.options.mode.lower() == 'polygons': - g = inkex.etree.Element('{http://www.w3.org/2000/svg}g') - style = { - 'fill': '#000000', - 'fill-opacity': 0.3, - 'stroke': '#000000', - 'stroke-opacity': 0.6, - 'stroke-width': self.unittouu('2px'), - } - g.set('style', simplestyle.formatStyle(style)) - paths[0].xpath('..')[0].append(g) - for comp in verts: - for n,v in enumerate(comp): - nn = n+1 - if nn == len(comp): nn = 0 - line = [] - line += [('M', comp[n][0])] - line += [('L', comp[n][1])] - line += [('L', comp[nn][1])] - line += [('L', comp[nn][0])] - line += [('L', comp[n][0])] - ele = inkex.etree.Element('{http://www.w3.org/2000/svg}path') - g.append(ele) - ele.set('d', simplepath.formatPath(line)) - - -if __name__ == '__main__': #pragma: no cover - e = Extrude() - e.affect() diff --git a/share/extensions/ffgeom.py b/share/extensions/ffgeom.py deleted file mode 100755 index a6d268239..000000000 --- a/share/extensions/ffgeom.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -""" - ffgeom.py - Copyright (C) 2005 Aaron Cyril Spike, aaron@ekips.org - - This file is part of FretFind 2-D. - - FretFind 2-D 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. - - FretFind 2-D 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 FretFind 2-D; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" -import math -try: - NaN = float('NaN') -except ValueError: - PosInf = 1e300000 - NaN = PosInf/PosInf - -class Point: - precision = 5 - def __init__(self, x, y): - self.__coordinates = {'x' : float(x), 'y' : float(y)} - def __getitem__(self, key): - return self.__coordinates[key] - def __setitem__(self, key, value): - self.__coordinates[key] = float(value) - def __repr__(self): - return '(%s, %s)' % (round(self['x'],self.precision),round(self['y'],self.precision)) - def copy(self): - return Point(self['x'],self['y']) - def translate(self, x, y): - self['x'] += x - self['y'] += y - def move(self, x, y): - self['x'] = float(x) - self['y'] = float(y) - -class Segment: - def __init__(self, e0, e1): - self.__endpoints = [e0, e1] - def __getitem__(self, key): - return self.__endpoints[key] - def __setitem__(self, key, value): - self.__endpoints[key] = value - def __repr__(self): - return repr(self.__endpoints) - def copy(self): - return Segment(self[0],self[1]) - def translate(self, x, y): - self[0].translate(x,y) - self[1].translate(x,y) - def move(self,e0,e1): - self[0] = e0 - self[1] = e1 - def delta_x(self): - return self[1]['x'] - self[0]['x'] - def delta_y(self): - return self[1]['y'] - self[0]['y'] - #alias functions - run = delta_x - rise = delta_y - def slope(self): - if self.delta_x() != 0: - return self.delta_x() / self.delta_y() - return NaN - def intercept(self): - if self.delta_x() != 0: - return self[1]['y'] - (self[0]['x'] * self.slope()) - return NaN - def distanceToPoint(self, p): - s2 = Segment(self[0],p) - c1 = dot(s2,self) - if c1 <= 0: - return Segment(p,self[0]).length() - c2 = dot(self,self) - if c2 <= c1: - return Segment(p,self[1]).length() - return self.perpDistanceToPoint(p) - def perpDistanceToPoint(self, p): - len = self.length() - if len == 0: return NaN - return math.fabs(((self[1]['x'] - self[0]['x']) * (self[0]['y'] - p['y'])) - \ - ((self[0]['x'] - p['x']) * (self[1]['y'] - self[0]['y']))) / len - def angle(self): - return math.pi * (math.atan2(self.delta_y(), self.delta_x())) / 180 - def length(self): - return math.sqrt((self.delta_x() ** 2) + (self.delta_y() ** 2)) - def pointAtLength(self, len): - if self.length() == 0: return Point(NaN, NaN) - ratio = len / self.length() - x = self[0]['x'] + (ratio * self.delta_x()) - y = self[0]['y'] + (ratio * self.delta_y()) - return Point(x, y) - def pointAtRatio(self, ratio): - if self.length() == 0: return Point(NaN, NaN) - x = self[0]['x'] + (ratio * self.delta_x()) - y = self[0]['y'] + (ratio * self.delta_y()) - return Point(x, y) - def createParallel(self, p): - return Segment(Point(p['x'] + self.delta_x(), p['y'] + self.delta_y()), p) - def intersect(self, s): - return intersectSegments(self, s) - -def intersectSegments(s1, s2): - x1 = s1[0]['x'] - x2 = s1[1]['x'] - x3 = s2[0]['x'] - x4 = s2[1]['x'] - - y1 = s1[0]['y'] - y2 = s1[1]['y'] - y3 = s2[0]['y'] - y4 = s2[1]['y'] - - denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)) - num1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)) - num2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3)) - - num = num1 - - if denom != 0: - x = x1 + ((num / denom) * (x2 - x1)) - y = y1 + ((num / denom) * (y2 - y1)) - return Point(x, y) - return Point(NaN, NaN) - -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 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/fig2dev-ext.py b/share/extensions/fig2dev-ext.py deleted file mode 100755 index ac51b00ef..000000000 --- a/share/extensions/fig2dev-ext.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -fig2dev-ext.py -Python script for running fig2dev in Inkscape extensions - -Copyright (C) 2008 Stephen Silver - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import sys -from run_command import run - -run('fig2dev -L svg "%s" "%%s"' % sys.argv[1].replace("%","%%"), "fig2dev") - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/fig_input.inx b/share/extensions/fig_input.inx deleted file mode 100644 index 8f0410221..000000000 --- a/share/extensions/fig_input.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>XFIG Input</_name> - <id>org.inkscape.input.fig</id> - <dependency type="executable" location="path">fig2dev</dependency> - <dependency type="executable" location="extensions">fig2dev-ext.py</dependency> - <input> - <extension>.fig</extension> - <mimetype>image/x-xfig</mimetype> - <_filetypename>XFIG Graphics File (*.fig)</_filetypename> - <_filetypetooltip>Open files saved with XFIG</_filetypetooltip> - <output_extension>org.inkscape.output.fig</output_extension> - </input> - <script> - <command reldir="extensions" interpreter="python">fig2dev-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/flatten.inx b/share/extensions/flatten.inx deleted file mode 100644 index 74b939c02..000000000 --- a/share/extensions/flatten.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Flatten Beziers</_name> - <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.1" max="1000.0" _gui-text="Flatness:">10.0</param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">flatten.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/flatten.py b/share/extensions/flatten.py deleted file mode 100755 index 7b4d2a7d6..000000000 --- a/share/extensions/flatten.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, cubicsuperpath, simplepath, cspsubdiv - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-f", "--flatness", - action="store", type="float", - dest="flat", default=10.0, - help="Minimum flatness of the subdivided curves") - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - p = cubicsuperpath.parsePath(d) - cspsubdiv.cspsubdiv(p, self.options.flat) - np = [] - for sp in p: - first = True - for csp in sp: - cmd = 'L' - if first: - cmd = 'M' - first = False - np.append([cmd,[csp[1][0],csp[1][1]]]) - node.set('d',simplepath.formatPath(np)) - -if __name__ == '__main__': - e = MyEffect() - e.affect() - - -# 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 deleted file mode 100644 index 72475ca3f..000000000 --- a/share/extensions/foldablebox.inx +++ /dev/null @@ -1,29 +0,0 @@ -<?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="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 deleted file mode 100755 index a26427389..000000000 --- a/share/extensions/foldablebox.py +++ /dev/null @@ -1,272 +0,0 @@ -#! /usr/bin/env python -''' -Copyright (C) 2009 Aurelio A. Heckert <aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -__version__ = "0.2" - -import inkex, simplestyle -from math import * -from simplepath import formatPath -import simpletransform - -class FoldableBox(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-x", "--width", - action="store", type="float", - dest="width", default=10.0, - help="The Box Width - in the X dimension") - self.OptionParser.add_option("-y", "--height", - action="store", type="float", - dest="height", default=15.0, - help="The Box Height - in the Y dimension") - self.OptionParser.add_option("-z", "--depth", - action="store", type="float", - dest="depth", default=3.0, - help="The Box Depth - in the Z dimension") - self.OptionParser.add_option("-u", "--unit", - action="store", type="string", - dest="unit", default="cm", - help="The unit of the box dimensions") - self.OptionParser.add_option("-p", "--paper-thickness", - action="store", type="float", - dest="thickness", default=0.01, - help="Paper Thickness - sometimes that is important") - self.OptionParser.add_option("-t", "--tab-proportion", - action="store", type="float", - dest="tabProportion", default=0.6, - help="Inner tab proportion for upper tab") - self.OptionParser.add_option("-g", "--guide-line", - action="store", type="inkbool", - dest="guideLine", default=True, - help="Add guide lines to help the drawing limits") - - def effect(self): - - docW = self.unittouu(self.document.getroot().get('width')) - docH = self.unittouu(self.document.getroot().get('height')) - - boxW = self.unittouu( str(self.options.width) + self.options.unit ) - boxH = self.unittouu( str(self.options.height) + self.options.unit ) - boxD = self.unittouu( str(self.options.depth) + self.options.unit ) - tabProp = self.options.tabProportion - tabH = boxD * tabProp - - box_id = self.uniqueId('box') - self.box = g = inkex.etree.SubElement(self.current_layer, 'g', {'id':box_id}) - - line_style = simplestyle.formatStyle({ 'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.unittouu('1px')) }) - - #self.createGuide( 0, docH, 0 ); - - # Inner Close Tab - line_path = [ - [ 'M', [ boxW-(tabH*0.7), 0 ] ], - [ 'C', [ boxW-(tabH*0.25), 0, boxW, tabH*0.3, boxW, tabH*0.9 ] ], - [ 'L', [ boxW, tabH ] ], - [ 'L', [ 0, tabH ] ], - [ 'L', [ 0, tabH*0.9 ] ], - [ 'C', [ 0, tabH*0.3, tabH*0.25, 0, tabH*0.7, 0 ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-inner-close-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - lower_pos = boxD+tabH - left_pos = 0 - - #self.createGuide( 0, docH-tabH, 0 ); - - # Upper Close Tab - line_path = [ - [ 'M', [ left_pos, tabH ] ], - [ 'L', [ left_pos + boxW, tabH ] ], - [ 'L', [ left_pos + boxW, lower_pos ] ], - [ 'L', [ left_pos + 0, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-upper-close-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW - - # Upper Right Tab - sideTabH = lower_pos - (boxW/2) - if sideTabH < tabH: sideTabH = tabH - line_path = [ - [ 'M', [ left_pos, sideTabH ] ], - [ 'L', [ left_pos + (boxD*0.8), sideTabH ] ], - [ 'L', [ left_pos + boxD, ((lower_pos*3)-sideTabH)/3 ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'L', [ left_pos + 0, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-upper-right-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW + boxD - - # Upper Left Tab - line_path = [ - [ 'M', [ left_pos + boxD, sideTabH ] ], - [ 'L', [ left_pos + (boxD*0.2), sideTabH ] ], - [ 'L', [ left_pos, ((lower_pos*3)-sideTabH)/3 ] ], - [ 'L', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-upper-left-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos = 0 - - #self.createGuide( 0, docH-tabH-boxD, 0 ); - - # Right Tab - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos - (boxD/2), lower_pos + (boxD/4) ] ], - [ 'L', [ left_pos - (boxD/2), lower_pos + boxH - (boxD/4) ] ], - [ 'L', [ left_pos, lower_pos + boxH ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-left-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - # Front - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos + boxW, lower_pos ] ], - [ 'L', [ left_pos + boxW, lower_pos + boxH ] ], - [ 'L', [ left_pos, lower_pos + boxH ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-front', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW - - # Right - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'L', [ left_pos + boxD, lower_pos + boxH ] ], - [ 'L', [ left_pos, lower_pos + boxH ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-right', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxD - - # Back - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos + boxW, lower_pos ] ], - [ 'L', [ left_pos + boxW, lower_pos + boxH ] ], - [ 'L', [ left_pos, lower_pos + boxH ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-back', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW - - # Left - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'L', [ left_pos + boxD, lower_pos + boxH ] ], - [ 'L', [ left_pos, lower_pos + boxH ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-left', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - lower_pos += boxH - left_pos = 0 - bTab = lower_pos + boxD - if bTab > boxW / 2.5: bTab = boxW / 2.5 - - # Bottom Front Tab - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos, lower_pos + (boxD/2) ] ], - [ 'L', [ left_pos + boxW, lower_pos + (boxD/2) ] ], - [ 'L', [ left_pos + boxW, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-bottom-front-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW - - # Bottom Right Tab - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos, lower_pos + bTab ] ], - [ 'L', [ left_pos + boxD, lower_pos + bTab ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-bottom-right-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxD - - # Bottom Back Tab - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos, lower_pos + (boxD/2) ] ], - [ 'L', [ left_pos + boxW, lower_pos + (boxD/2) ] ], - [ 'L', [ left_pos + boxW, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-bottom-back-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxW - - # Bottom Left Tab - line_path = [ - [ 'M', [ left_pos, lower_pos ] ], - [ 'L', [ left_pos, lower_pos + bTab ] ], - [ 'L', [ left_pos + boxD, lower_pos + bTab ] ], - [ 'L', [ left_pos + boxD, lower_pos ] ], - [ 'Z', [] ] - ] - line_atts = { 'style':line_style, 'id':box_id+'-bottom-left-tab', 'd':formatPath(line_path) } - inkex.etree.SubElement(g, inkex.addNS('path','svg'), line_atts ) - - left_pos += boxD - lower_pos += bTab - - g.set( 'transform', 'translate(%f,%f)' % ( (docW-left_pos)/2, (docH-lower_pos)/2 ) ) - - # compensate preserved transforms of parent layer - if self.current_layer.getparent() is not None: - mat = simpletransform.composeParents(self.current_layer, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - simpletransform.applyTransformToNode(simpletransform.invertTransform(mat), g) - - -if __name__ == '__main__': #pragma: no cover - e = FoldableBox() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/fontfix.conf b/share/extensions/fontfix.conf deleted file mode 100644 index 4f66174c9..000000000 --- a/share/extensions/fontfix.conf +++ /dev/null @@ -1,55 +0,0 @@ -# This file contains correction factors for the PowerPoint compensation method -# when files are saved to EMF. PowerPoint applies some odd offsets when it ungroups -# fonts from within an EMF. This file contains compensating factors so that the -# imported, ungrouped characters end up in the desired location. -# -# Format(s) -# -# # a comment -# -# f1 f2 f3 FontName -# where -# f1: vertical (rotating) correction factor (a double) -# f2: vertical (nonrotating) correction factor (a double) -# f3: horizontal (nonrotating) correction factor (a double) -# FontName: Case sensitive, may contain spaces. Example: Times New Roman -# -# The first font will listed will be used as the default for any font which -# is later requested but was not explicitly listed. -# -# If f1 specifies a multiplicative correction factor. It is multiplied by the font size -# and then the character is offset parallel to the (original) vertical direction of the character, -# that is, along the long part of a capital L. -# -# If f2 or f3 is nonzero then for angles <1 degree from 0,90,180,270 degrees -# the angle is snapped to n*90 and f2 is used for the vertical displacements, f3 -# for the horizontal displacements (that is, for 90 degrees, f3 is used). -# -# There is are one special type of fontname: Convert To FontName, -# for instance "Convert To Symbol". It is used when EMF print converts -# from unicode to Symbol, Wingdings, or Zapf Dingbats. -# -# Positive values lower the letter, negative raise it -# -# File history: -# 1.0.0 03/26/2012, David Mathog, initial values -##################################################################### -0.05 -0.055 -0.065 Arial -0.05 -0.055 -0.065 Times New Roman --0.025 -0.055 -0.065 Lucida Sans -0.05 -0.055 -0.065 Sans --0.05 -0.055 -0.065 Microsoft Sans Serif -0.05 -0.055 -0.065 Serif -0.05 -0.055 -0.065 Garamond -0.25 0.025 0.025 Century Schoolbook -0.025 0.0 0.0 Verdana -0.045 0.025 0.025 Tahoma -0.025 0.0 0.0 Symbol -0.05 0.0 0.0 Wingdings -0.025 0.0 0.0 Zapf Dingbats -0.025 0.0 0.0 Convert To Symbol -0.05 0.0 0.0 Convert To Wingdings -0.025 0.0 0.0 Convert To Zapf Dingbats -0.1 0.0 0.0 Sylfaen -0.175 0.125 0.125 Palatino Linotype -0.1 0.0 0.0 Segoe UI diff --git a/share/extensions/fractalize.inx b/share/extensions/fractalize.inx deleted file mode 100644 index 4893189e8..000000000 --- a/share/extensions/fractalize.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Fractalize</_name> - <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> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">fractalize.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/fractalize.py b/share/extensions/fractalize.py deleted file mode 100755 index c6bbe397a..000000000 --- a/share/extensions/fractalize.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2005 Carsten Goetze c.goetze@tu-bs.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import random, math, inkex, simplepath - -def calculateSubdivision(x1,y1,x2,y2,smoothness): - """ Calculate the vector from (x1,y1) to (x2,y2) """ - x3 = x2 - x1 - y3 = y2 - y1 - """ Calculate the point half-way between the two points """ - hx = x1 + x3/2 - hy = y1 + y3/2 - """ Calculate normalized vector perpendicular to the vector (x3,y3) """ - length = math.sqrt(x3*x3 + y3*y3) - if length != 0: - nx = -y3/length - ny = x3/length - else: - nx = 1 - ny = 0 - """ Scale perpendicular vector by random factor """ - r = random.uniform(-length/(1+smoothness),length/(1+smoothness)) - nx = nx * r - ny = ny * r - """ add scaled perpendicular vector to the half-way point to get the final - displaced subdivision point """ - x = hx + nx - y = hy + ny - return [x, y] - -class PathFractalize(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--subdivs", - action="store", type="int", - dest="subdivs", default="6", - help="Number of subdivisons") - self.OptionParser.add_option("-f", "--smooth", - action="store", type="float", - dest="smooth", default="4.0", - help="Smoothness of the subdivision") - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - p = simplepath.parsePath(d) - - a = [] - first = 1 - for cmd,params in p: - if cmd != 'Z': - if first == 1: - x1 = params[-2] - y1 = params[-1] - a.append(['M',params[-2:]]) - first = 2 - else : - x2 = params[-2] - y2 = params[-1] - self.fractalize(a,x1,y1,x2,y2,self.options.subdivs,self.options.smooth) - x1 = x2 - y1 = y2 - a.append(['L',params[-2:]]) - - node.set('d', simplepath.formatPath(a)) - - def fractalize(self,a,x1,y1,x2,y2,s,f): - subdivPoint = calculateSubdivision(x1,y1,x2,y2,f) - - if s > 0 : - """ recursively subdivide the segment left of the subdivision point """ - self.fractalize(a,x1,y1,subdivPoint[-2],subdivPoint[-1],s-1,f) - a.append(['L',subdivPoint]) - """ recursively subdivide the segment right of the subdivision point """ - self.fractalize(a,subdivPoint[-2],subdivPoint[-1],x2,y2,s-1,f) - -if __name__ == '__main__': - e = PathFractalize() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/frame.inx b/share/extensions/frame.inx deleted file mode 100644 index a2b011430..000000000 --- a/share/extensions/frame.inx +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Frame</_name> - <id>frame</id> - <dependency type="executable" location="extensions">frame.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="stroke" gui-text="Stroke"> - <param name="stroke_color" type="color" gui-text="Stroke Color:">000000FF</param> - </page> - <page name="fill" gui-text="Fill"> - <param name="fill_color" type="color" gui-text="Fill Color:">00000000</param> - </page> - </param> - <param name="position" type="optiongroup" appearance="minimal" gui-text="Position"> - <option value="outside">Outside</option> - <option value="inside">Inside</option> - </param> - <param name="clip" type="boolean" gui-text="Clip"></param> - <param name="group" type="boolean" gui-text="Group"></param> - <param name="width" type="float" min="0" max="100" gui-text="Width(px)">2</param> - <param name="corner_radius" type="int" min="0" max="1000" gui-text="Corner Radius">0</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">frame.py</command> - </script> -</inkscape-extension>
\ No newline at end of file diff --git a/share/extensions/frame.py b/share/extensions/frame.py deleted file mode 100644 index f6d54e180..000000000 --- a/share/extensions/frame.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python -""" -An Inkscape extension that creates a frame around a selected object. - -Copyright (C) 2016 Richard White, rwhite8282@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 -""" - -# These two lines are only needed if you don't put the script directly into -# the installation directory -import sys -sys.path.append('/usr/share/inkscape/extensions') - -import inkex -import simplestyle -from simpletransform import * -from simplestyle import * - - -def get_picker_data(value): - """ Returns color data in style string format. - value -- The value returned from the color picker. - Returns an object with color and opacity properties. - """ - v = '%08X' % (value & 0xFFFFFFFF) - color = '#' + v[0:-2].rjust(6, '0') - opacity = '%1.2f' % (float(int(v[6:].rjust(2, '0'), 16))/255) - return type('', (object,), {'color':color, 'opacity':opacity})() - - -def size_box(box, delta): - """ Returns a box with an altered size. - delta -- The amount the box should grow. - Returns a box with an altered size. - """ - return ((box[0]-delta), (box[1]+delta), (box[2]-delta), (box[3]+delta)) - - -# Frame maker Inkscape effect extension -class Frame(inkex.Effect): - """ An Inkscape extension that creates a frame around a selected object. - """ - def __init__(self): - inkex.Effect.__init__(self) - self.defs = None - - # Parse the options. - self.OptionParser.add_option('--clip', - action='store', type='inkbool', - dest='clip', default=False) - self.OptionParser.add_option('--corner_radius', - action='store', type='int', - dest='corner_radius', default=0) - self.OptionParser.add_option('--fill_color', - action='store', type='int', - dest='fill_color', default='00000000') - self.OptionParser.add_option('--group', - action='store', type='inkbool', - dest='group', default=False) - self.OptionParser.add_option('--position', - action='store', type='string', - dest='position', default='outside') - self.OptionParser.add_option('--stroke_color', - action='store', type='int', - dest='stroke_color', default='00000000') - self.OptionParser.add_option('--tab', - action='store', type='string', - dest='tab', default='object') - self.OptionParser.add_option('--width', - action='store', type='float', - dest='width', default=2) - - - def add_clip(self, node, clip_path): - """ Adds a new clip path node to the defs and sets - the clip-path on the node. - node -- The node that will be clipped. - clip_path -- The clip path object. - """ - if self.defs is None: - defs_nodes = self.document.getroot().xpath('//svg:defs', namespaces=inkex.NSS) - if defs_nodes: - self.defs = defs_nodes[0] - else: - inkex.errormsg('Could not locate defs node for clip.') - return - clip = inkex.etree.SubElement(self.defs, inkex.addNS('clipPath','svg')) - clip.append(copy.deepcopy(clip_path)) - clip_id = self.uniqueId('clipPath') - clip.set('id', clip_id) - node.set('clip-path', 'url(#%s)' % str(clip_id)) - - - def add_frame(self, parent, name, box, style, radius=0): - """ Adds a new frame to the parent object. - parent -- The parent that the frame will be added to. - name -- The name of the new frame object. - box -- The boundary box of the node. - style -- The style used to draw the path. - radius -- The corner radius of the frame. - returns a new frame node. - """ - r = min([radius, (abs(box[1]-box[0])/2), (abs(box[3]-box[2])/2)]) - if (radius > 0): - d = ' '.join(str(x) for x in - ['M', box[0], (box[2]+r) - ,'A', r, r, '0 0 1', (box[0]+r), box[2] - ,'L', (box[1]-r), box[2] - ,'A', r, r, '0 0 1', box[1], (box[2]+r) - ,'L', box[1], (box[3]-r) - ,'A', r, r, '0 0 1', (box[1]-r), box[3] - ,'L', (box[0]+r), box[3] - ,'A', r, r, '0 0 1', box[0], (box[3]-r), 'Z']) - else: - d = ' '.join(str(x) for x in - ['M', box[0], box[2] - ,'L', box[1], box[2] - ,'L', box[1], box[3] - ,'L', box[0], box[3], 'Z']) - - attributes = {'style':style, inkex.addNS('label','inkscape'):name, 'd':d} - return inkex.etree.SubElement(parent, inkex.addNS('path','svg'), attributes ) - - - def effect(self): - """ Performs the effect. - """ - # Get the style values. - corner_radius = self.options.corner_radius - stroke_data = get_picker_data(self.options.stroke_color) - fill_data = get_picker_data(self.options.fill_color) - - # Determine common properties. - parent = self.current_layer - position = self.options.position - width = self.options.width - style = simplestyle.formatStyle({'stroke':stroke_data.color - , 'stroke-opacity':stroke_data.opacity - , 'stroke-width':str(width) - , 'fill':(fill_data.color if (fill_data.opacity > 0) else 'none') - , 'fill-opacity':fill_data.opacity}) - - for id, node in self.selected.iteritems(): - box = computeBBox([node]) - if 'outside' == position: - box = size_box(box, (width/2)) - else: - box = size_box(box, -(width/2)) - name = 'Frame' - frame = self.add_frame(parent, name, box, style, corner_radius) - if self.options.clip: - self.add_clip(node, frame) - if self.options.group: - group = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg')) - group.append(node) - group.append(frame) - - -if __name__ == '__main__': #pragma: no cover - # Create effect instance and apply it. - effect = Frame() - effect.affect()
\ No newline at end of file diff --git a/share/extensions/funcplot.inx b/share/extensions/funcplot.inx deleted file mode 100644 index 58cf158ca..000000000 --- a/share/extensions/funcplot.inx +++ /dev/null @@ -1,57 +0,0 @@ -<?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">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: - -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); -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="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="clip" type="boolean" _gui-text="Clip with rectangle">false</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 deleted file mode 100755 index 64f280624..000000000 --- a/share/extensions/funcplot.py +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -Changes: - * This program is a modified version of wavy.py by Aaron Spike. - * 22-Dec-2006: Wiora : Added axis and isotropic scaling - * 21-Jun-2007: Tavmjong: Added polar coordinates - -''' -# standard library -from math import * -from random import * -from copy import deepcopy -# local library -import inkex -import simplepath -import simplestyle - -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, endpts = False): - - if times2pi == True: - xstart = 2 * pi * xstart - xend = 2 * pi * xend - - # coords and scales based on the source rect - if xstart == xend: - inkex.errormsg(_("x-interval cannot be zero. Please modify 'Start X value' or 'End X value'")) - return [] - scalex = width / (xend - xstart) - xoff = left - coordx = lambda x: (x - xstart) * scalex + xoff #convert x-value to coordinate - if polar : # Set scale so that left side of rectangle is -1, right side is +1. - # (We can't use xscale for both range and scale.) - centerx = left + width/2.0 - polar_scalex = width/2.0 - coordx = lambda x: x * polar_scalex + centerx #convert x-value to coordinate - - if ytop == ybottom: - inkex.errormsg(_("y-interval cannot be zero. Please modify 'Y value of rectangle's top' or 'Y value of rectangle's bottom'")) - return [] - 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 and not polar: - if scaley<scalex: - # compute zero location - xzero = coordx(0) - # set scale - scalex = scaley - # correct x-offset - xstart = (left-xzero)/scalex - xend = (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 - try: - if fx != "": - f = eval('lambda x: ' + fx.strip('"')) - if fpx != "": - fp = eval('lambda x: ' + fpx.strip('"')) - # handle incomplete/invalid function gracefully - except SyntaxError: - return [] - - # step is the distance between nodes on x - step = (xend - xstart) / (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 xstart<=0 and xend>=0: - # xaxis - a.append([' M ',[coordx(0),bottom]]) - a.append([' l ',[0, -height]]) - - # initialize function and derivative for 0; - # they are carried over from one iteration to the next, to avoid extra function calculations. - x0 = xstart - y0 = f(xstart) - if polar : - xp0 = y0 * cos( x0 ) - yp0 = y0 * sin( x0 ) - x0 = xp0 - y0 = yp0 - if fponum or polar: # numerical derivative, using 0.001*step as the small differential - x1 = xstart + ds # Second point AFTER first point (Good for first point) - y1 = f(x1) - if polar : - xp1 = y1 * cos( x1 ) - yp1 = y1 * sin( x1 ) - x1 = xp1 - y1 = yp1 - dx0 = (x1 - x0)/ds - dy0 = (y1 - y0)/ds - else: # derivative given by the user - dx0 = 1 # Only works for rectangular coordinates - dy0 = fp(xstart) - - # Start curve - 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 - x2 = x1 - ds # Second point BEFORE first point (Good for last point) - y1 = f(x1) - y2 = f(x2) - if polar : - xp1 = y1 * cos( x1 ) - yp1 = y1 * sin( x1 ) - xp2 = y2 * cos( x2 ) - yp2 = y2 * sin( x2 ) - x1 = xp1 - y1 = yp1 - x2 = xp2 - y2 = yp2 - if fponum or polar: # numerical derivative - dx1 = (x1 - x2)/ds - dy1 = (y1 - y2)/ds - else: # derivative given by the user - dx1 = 1 # Only works for rectangular coordinates - dy1 = fp(x1) - # 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)] - ]) - 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 - if endpts: - a.append([' L ',[left + width, coordy(0)]]) - return a - -class FuncPlot(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--xstart", - action="store", type="float", - dest="xstart", default=0.0, - help="Start x-value") - self.OptionParser.add_option("--xend", - action="store", type="float", - dest="xend", default=1.0, - help="End x-value") - self.OptionParser.add_option("--times2pi", - action="store", type="inkbool", - dest="times2pi", default=True, - help="Multiply x-range by 2*pi") - self.OptionParser.add_option("--polar", - action="store", type="inkbool", - dest="polar", default=False, - help="Plot using polar coordinates") - 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="sin(x)", - help="f(x) for plotting") - self.OptionParser.add_option("--fponum", - action="store", type="inkbool", - dest="fponum", default=True, - help="Calculate the first derivative numerically") - self.OptionParser.add_option("--fpofx", - action="store", type="string", - dest="fpofx", default="cos(x)", - help="f'(x) for plotting") - self.OptionParser.add_option("--clip", - action="store", type="inkbool", - dest="clip", default=False, - help="If True, clip with copy of source rectangle") - 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("--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", - help="The selected UI-tab when OK was pressed") - self.OptionParser.add_option("--funcplotuse", - action="store", type="string", - dest="funcplotuse", default="", - help="dummy") - self.OptionParser.add_option("--pythonfunctions", - action="store", type="string", - dest="pythonfunctions", default="", - help="dummy") - - def effect(self): - newpath = None - 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.xstart, - self.options.xend, - self.options.ybottom, - self.options.ytop, - self.options.samples, - w,h,x,y+h, - self.options.fofx, - self.options.fpofx, - self.options.fponum, - self.options.times2pi, - self.options.polar, - self.options.isoscale, - self.options.drawaxis, - self.options.endpts))) - newpath.set('title', self.options.fofx) - - #newpath.setAttribute('desc', '!func;' + self.options.fofx + ';' - # + self.options.fpofx + ';' - # + `self.options.fponum` + ';' - # + `self.options.xstart` + ';' - # + `self.options.xend` + ';' - # + `self.options.samples`) - - # add path into SVG structure - node.getparent().append(newpath) - # option whether to clip the path with rect or not. - if self.options.clip: - defs = self.xpathSingle('/svg:svg//svg:defs') - if defs == None: - defs = inkex.etree.SubElement(self.document.getroot(),inkex.addNS('defs','svg')) - clip = inkex.etree.SubElement(defs,inkex.addNS('clipPath','svg')) - clip.append(deepcopy(node)) - clipId = self.uniqueId('clipPath') - clip.set('id', clipId) - newpath.set('clip-path', 'url(#'+clipId+')') - # option whether to remove the rectangle or not. - if self.options.remove: - node.getparent().remove(node) - if newpath is None: - inkex.errormsg(_("Please select a rectangle")) - -if __name__ == '__main__': - e = FuncPlot() - e.affect() - - -# 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 deleted file mode 100755 index be471136e..000000000 --- a/share/extensions/gcodetools.py +++ /dev/null @@ -1,6752 +0,0 @@ -#!/usr/bin/env python -""" -Comments starting "#LT" or "#CLT" are by Chris Lusby Taylor who rewrote the engraving function in 2011. -History of CLT changes to engraving and other functions it uses: -9 May 2011 Changed test of tool diameter to square it -10 May Note that there are many unused functions, including: - bound_to_bound_distance, csp_curvature_radius_at_t, - csp_special_points, csplength, rebuild_csp, csp_slope, - csp_simple_bound_to_point_distance, csp_bound_to_point_distance, - bez_at_t, bez_to_point_distance, bez_normalized_slope, matrix_mul, transpose - Fixed csp_point_inside_bound() to work if x outside bounds -20 May Now encoding the bisectors of angles. -23 May Using r/cos(a) instead of normalised normals for bisectors of angles. -23 May Note that Z values generated for engraving are in pixels, not mm. - Removed the biarc curves - straight lines are better. -24 May Changed Bezier slope calculation to be less sensitive to tiny differences in points. - Added use of self.options.engraving_newton_iterations to control accuracy -25 May Big restructure and new recursive function. - Changed the way I treat corners - I now find if the centre of a proposed circle is - within the area bounded by the line being tested and the two angle bisectors at - its ends. See get_radius_to_line(). -29 May Eliminating redundant points. If A,B,C colinear, drop B -30 May Eliminating redundant lines in divided Beziers. Changed subdivision of lines - 7Jun Try to show engraving in 3D - 8 Jun Displaying in stereo 3D. - Fixed a bug in bisect - it could go wrong due to rounding errors if - 1+x1.x2+y1.y2<0 which should never happen. BTW, I spotted a non-normalised normal - returned by csp_normalized_normal. Need to check for that. - 9 Jun Corrected spelling of 'definition' but still match previous 'defention' and 'defenition' if found in file - Changed get_tool to find 1.6.04 tools or new tools with corrected spelling -10 Jun Put 3D into a separate layer called 3D, created unless it already exists - Changed csp_normalized_slope to reject lines shorter than 1e-9. -10 Jun Changed all dimensions seen by user to be mm/inch, not pixels. This includes - tool diameter, maximum engraving distance, tool shape and all Z values. -12 Jun ver 208 Now scales correctly if orientation points moved or stretched. -12 Jun ver 209. Now detect if engraving toolshape not a function of radius - Graphics now indicate Gcode toolpath, limited by min(tool diameter/2,max-dist) -24 Jan 2017 Removed hard-coded scale values from orientation point calculation -TODO Change line division to be recursive, depending on what line is touched. See line_divide - - -engraving() functions (c) 2011 Chris Lusby Taylor, clusbytaylor@enterprise.net -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" - -### -### Gcodetools v 1.7 -### - -gcodetools_current_version = "1.7" - -# standard library -import os -import math -import bezmisc -import re -import copy -import sys -import time -import cmath -import codecs -import random -# local library -import inkex -import simplestyle -import simplepath -import cubicsuperpath -import simpletransform -import bezmisc - -### Check if inkex has errormsg (0.46 version does not 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")) - -try: - import numpy -except: - inkex.errormsg(_("Failed to import the numpy modules. These modules are required by this extension. Please install them and try again. On a Debian-like system this can be done with the command, sudo apt-get install python-numpy.")) - exit() - - -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) - -def isset(variable): - # VARIABLE NAME SHOULD BE A STRING! Like isset("foobar") - return variable in locals() or variable in globals() - - -################################################################################ -### -### 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 - -EMC_TOLERANCE_EQUAL = 0.00001 - -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 = { - "in_out_path_style" : simplestyle.formatStyle({ 'stroke': '#0072a7', 'fill': 'none', 'stroke-width':'1', 'marker-mid':'url(#InOutPathMarker)' }), - - "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"}), - - } - - - -################################################################################ -### Gcode additional functions -################################################################################ - -def gcode_comment_str(s, replace_new_line = False): - if replace_new_line : - s = re.sub(r"[\n\r]+", ".", s) - res = "" - if s[-1] == "\n" : s = s[:-1] - for a in s.split("\n") : - if a != "" : - res += "(" + re.sub(r"[\(\)\\\n\r]", ".", a) + ")\n" - else : - res += "\n" - return res - - -################################################################################ -### Cubic Super Path additional functions -################################################################################ - - -def csp_from_polyline(line) : - return [ [ [point[:] for k in range(3) ] for point in subline ] for subline in line ] - -def csp_remove_zerro_segments(csp, tolerance = 1e-7): - res = [] - for subpath in csp: - if len(subpath) > 0 : - res.append([subpath[0]]) - for sp1,sp2 in zip(subpath,subpath[1:]) : - if point_to_point_d2(sp1[1],sp2[1])<=tolerance and point_to_point_d2(sp1[2],sp2[1])<=tolerance and point_to_point_d2(sp1[1],sp2[0])<=tolerance : - res[-1][-1][2] = sp2[2] - else : - res[-1].append(sp2) - return res - - - - - -def point_inside_csp(p,csp, on_the_path = True) : - # we'll do the raytracing and see how many intersections are there on the ray's way. - # if number of intersections is even then point is outside. - # ray will be x=p.x and y=>p.y - # you can assing any value to on_the_path, by dfault if point is on the path - # function will return thai it's inside the path. - x,y = p - ray_intersections_count = 0 - for subpath in csp : - - for i in range(1, len(subpath)) : - sp1, sp2 = subpath[i-1], subpath[i] - ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2) - if ax==0 and bx==0 and cx==0 and dx==x : - #we've got a special case here - b = csp_true_bounds( [[sp1,sp2]]) - if b[1][1]<=y<=b[3][1] : - # points is on the path - return on_the_path - else : - # we can skip this segment because it wont influence the answer. - pass - else: - for t in csp_line_intersection([x,y],[x,y+5],sp1,sp2) : - if t == 0 or t == 1 : - #we've got another special case here - x1,y1 = csp_at_t(sp1,sp2,t) - if y1==y : - # the point is on the path - return on_the_path - # if t == 0 we should have considered this case previously. - if t == 1 : - # we have to check the next segmant if it is on the same side of the ray - st_d = csp_normalized_slope(sp1,sp2,1)[0] - if st_d == 0 : st_d = csp_normalized_slope(sp1,sp2,0.99)[0] - - for j in range(1, len(subpath)+1): - if (i+j) % len(subpath) == 0 : continue # skip the closing segment - sp11,sp22 = subpath[(i-1+j) % len(subpath)], subpath[(i+j) % len(subpath)] - ax1,ay1,bx1,by1,cx1,cy1,dx1,dy1 = csp_parameterize(sp1,sp2) - if ax1==0 and bx1==0 and cx1==0 and dx1==x : continue # this segment parallel to the ray, so skip it - en_d = csp_normalized_slope(sp11,sp22,0)[0] - if en_d == 0 : en_d = csp_normalized_slope(sp11,sp22,0.01)[0] - if st_d*en_d <=0 : - ray_intersections_count += 1 - break - else : - x1,y1 = csp_at_t(sp1,sp2,t) - if y1==y : - # the point is on the path - return on_the_path - else : - if y1>y and 3*ax*t**2 + 2*bx*t + cx !=0 : # if it's 0 the path only touches the ray - ray_intersections_count += 1 - return ray_intersections_count%2 == 1 - -def csp_close_all_subpaths(csp, tolerance = 0.000001): - for i in range(len(csp)): - if point_to_point_d2(csp[i][0][1] , csp[i][-1][1])> tolerance**2 : - csp[i][-1][2] = csp[i][-1][1][:] - csp[i] += [ [csp[i][0][1][:] for j in range(3)] ] - else: - if csp[i][0][1] != csp[i][-1][1] : - csp[i][-1][1] = csp[i][0][1][:] - return csp - -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_at_length(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_at_t(sp1,sp2,t) - - -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.01): - 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_seg_split(sp1,sp2, points): - # points is float=t or list [t1, t2, ..., tn] - if type(points) is float : - points = [points] - points.sort() - res = [sp1,sp2] - last_t = 0 - for t in points: - if 1e-10<t<1.-1e-10 : - sp3,sp4,sp5 = csp_split(res[-2],res[-1], (t-last_t)/(1-last_t)) - last_t = t - res[-2:] = [sp3,sp4,sp5] - return res - - -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 arc_from_s_r_n_l(s,r,n,l) : - if abs(n[0]**2+n[1]**2 - 1) > 1e-10 : n = normalize(n) - return arc_from_c_s_l([s[0]+n[0]*r, s[1]+n[1]*r],s,l) - - -def arc_from_c_s_l(c,s,l) : - r = point_to_point_d(c,s) - if r == 0 : return [] - alpha = l/r - cos_, sin_ = math.cos(alpha), math.sin(alpha) - e = [ c[0] + (s[0]-c[0])*cos_ - (s[1]-c[1])*sin_, c[1] + (s[0]-c[0])*sin_ + (s[1]-c[1])*cos_] - n = [c[0]-s[0],c[1]-s[1]] - slope = rotate_cw(n) if l>0 else rotate_ccw(n) - return csp_from_arc(s, e, c, r, slope) - - -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 - #CLT added test of x in range - xmin=1e100 - xmax=-1e100 - for i in range(4): - [x0,y0], [x1,y1] = bez[i-1], bez[i] - xmin=min(xmin,x0) - xmax=max(xmax,x0) - 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 xmin<=x<=xmax and 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-9 : #LT changed this from 1e-20, which caused problems - 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-9 : #LT changed this from 1e-20, which caused problems - 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-9 : - 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_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, prepend = False) : - # Appends subpath with line or polyline. - if len(points)>0 : - if not prepend : - 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] ] - else : - if len(subpath)>0: - subpath[0][0] = subpath[0][1][:] - if type(points[0]) == type([1,1]) : - for p in points : - subpath = [ [p[:],p[:],p[:]] ] + subpath - else: - subpath = [ [points,points,points] ] + subpath - 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 happened which is something that shouldn't 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 rotate_cw(d) : - return [d[1],-d[0]] - - -def vectors_ccw(a,b): - return a[0]*b[1]-b[0]*a[1] < 0 - -def vector_add(a,b) : - return [a[0]+b[0],a[1]+b[1]] - -def vector_mul(a,b) : - return [a[0]*b,a[1]*b] - - -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 get_text(node) : - value = None - if node.text!=None : value = value +"\n" + node.text if value != None else node.text - for k in node : - if k.tag == inkex.addNS('tspan','svg'): - if k.text!=None : value = value +"\n" + k.text if value != None else k.text - return value - - - -def draw_text(text,x,y, group = None, style = None, font_size = 10, gcodetools_tag = None) : - if style == None : - style = "font-family:DejaVu Sans;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:DejaVu Sans;fill:#000000;fill-opacity:1;stroke:none;" - style += "font-size:%fpx;"%font_size - attributes = { 'x': str(x), - inkex.addNS("space","xml"):"preserve", - 'y': str(y), - 'style' : style - } - if gcodetools_tag!=None : - attributes["gcodetools"] = str(gcodetools_tag) - - if group == None: - group = options.doc_root - - t = inkex.etree.SubElement( group, inkex.addNS('text','svg'), attributes) - 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 = str(s) - -def draw_csp(csp, stroke = "#f00", fill = "none", comment = "", width = 0.354, group = None, style = None, gcodetools_tag = None) : - if style == None : - style = "fill:%s;fill-opacity:1;stroke:%s;stroke-width:%s"%(fill,stroke,width) - attributes = { 'd': cubicsuperpath.formatPath(csp), - 'style' : style - } - if comment != '': - attributes['comment'] = comment - if group == None : - group = options.doc_root - - return inkex.etree.SubElement( group, inkex.addNS('path','svg'), attributes) - -def draw_pointer(x,color = "#f00", figure = "cross", group = None, comment = "", fill=None, width = .1, size = 10., text = None, font_size=None, pointer_type=None, attrib = None) : - size = size/2 - if attrib == None : attrib = {} - if pointer_type == None: - pointer_type = "Pointer" - attrib["gcodetools"] = pointer_type - if group == None: - group = options.self.current_layer - if text != None : - if font_size == None : font_size = 7 - group = inkex.etree.SubElement( group, inkex.addNS('g','svg'), {"gcodetools": pointer_type+" group"} ) - draw_text(text,x[0]+size*2.2,x[1]-size, group = group, font_size = font_size) - if figure == "line" : - s = "" - for i in range(1,len(x)/2) : - s+= " %s, %s " %(x[i*2],x[i*2+1]) - attrib.update({"d": "M %s,%s L %s"%(x[0],x[1],s), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)}) - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib) - elif figure == "arrow" : - if fill == None : fill = "#12b3ff" - fill_opacity = "0.8" - d = "m %s,%s " % (x[0],x[1]) + re.sub("([0-9\-.e]+)",(lambda match: str(float(match.group(1))*size*2.)), "0.88464,-0.40404 c -0.0987,-0.0162 -0.186549,-0.0589 -0.26147,-0.1173 l 0.357342,-0.35625 c 0.04631,-0.039 0.0031,-0.13174 -0.05665,-0.12164 -0.0029,-1.4e-4 -0.0058,-1.4e-4 -0.0087,0 l -2.2e-5,2e-5 c -0.01189,0.004 -0.02257,0.0119 -0.0305,0.0217 l -0.357342,0.35625 c -0.05818,-0.0743 -0.102813,-0.16338 -0.117662,-0.26067 l -0.409636,0.88193 z") - attrib.update({"d": d, "style":"fill:%s;stroke:none;fill-opacity:%s;"%(fill,fill_opacity),"comment":str(comment)}) - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib) - else : - attrib.update({"d": "m %s,%s l %f,%f %f,%f %f,%f %f,%f , %f,%f"%(x[0],x[1], size,size, -2*size,-2*size, size,size, size,-size, -2*size,2*size ), "style":"fill:none;stroke:%s;stroke-width:%f;"%(color,width),"comment":str(comment)}) - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attrib) - - -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_real(a,b,c,d): - # returns only real roots of a cubic equation. - roots = cubic_solver(a,b,c,d) - res = [] - for root in roots : - if type(root) is complex : - if -1e-10<root.imag<1e-10 : - res.append(root.real) - else : - res.append(root) - return res - - -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 - - -class Arc(): - def __init__(self,st,end,c,a): - self.st = P(st) - self.end = P(end) - self.c = P(c) - self.r = (P(st)-P(c)).mag() - self.a = ( (self.st-self.c).angle() - (self.end-self.c).angle() ) % math.pi2 - if a<0 : self.a -= math.pi2 - - def offset(self, r): - if self.a>0 : - r += self.r - else : - r = self.r - r - - if self.r != 0 : - self.st = self.c + (self.st-self.c)*r/self.r - self.end = self.c + (self.end-self.c)*r/self.r - self.r = r - - def length(self): - return abs(self.a*self.r) - - - def draw(self, group, style, layer, transform, num = 0, reverse_angle = 1): - st = P(gcodetools.transform(self.st.to_list(), layer, True)) - c = P(gcodetools.transform(self.c.to_list(), layer, True)) - a = self.a * reverse_angle - r = (st-c) - a_st = (math.atan2(r.x,-r.y) - math.pi/2) % (math.pi*2) - r = r.mag() - if a<0: - a_end = a_st+a - style = style['biarc%s'%(num%2)] - else: - a_end = a_st - a_st = a_st+a - style = style['biarc%s_r'%(num%2)] - - attr = { - 'style': style, - inkex.addNS('cx','sodipodi'): str(c.x), - inkex.addNS('cy','sodipodi'): str(c.y), - 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", - } - if transform != [] : - attr["transform"] = transform - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr) - - def intersect(self,b) : - return [] - - -class Line(): - def __init__(self,st,end): - if st.__class__ == P : - st = st.to_list() - if end.__class__ == P : - end = end.to_list() - self.st = P(st) - self.end = P(end) - self.l = self.length() - if self.l != 0 : - self.n = ((self.end-self.st)/self.l).ccw() - else: - self.n = [0,1] - - def offset(self, r): - self.st -= self.n*r - self.end -= self.n*r - - def l2(self): return (self.st-self.end).l2() - def length(self): return (self.st-self.end).mag() - - def draw(self, group, style, layer, transform, num = 0, reverse_angle = 1): - st = gcodetools.transform(self.st.to_list(), layer, True) - end = gcodetools.transform(self.end.to_list(), layer, True) - - - attr = { 'style': style['line'], - 'd':'M %s,%s L %s,%s' % (st[0],st[1],end[0],end[1]), - "gcodetools": "Preview", - } - if transform != [] : - attr["transform"] = transform - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr ) - - def intersect(self,b) : - if b.__class__ == Line : - if self.l < 10e-8 or b.l < 10e-8 : return [] - v1 = self.end - self.st - v2 = b.end - b.st - x = v1.x*v2.y - v2.x*v1.y - if x == 0 : - # lines are parallel - res = [] - - if (self.st.x-b.st.x)*v1.y - (self.st.y-b.st.y)*v1.x == 0: - # lines are the same - if v1.x != 0 : - if 0<=(self.st.x-b.st.x)/v2.x<=1 : res.append(self.st) - if 0<=(self.end.x-b.st.x)/v2.x<=1 : res.append(self.end) - if 0<=(b.st.x-self.st.x)/v1.x<=1 : res.append(b.st) - if 0<=(b.end.x-b.st.x)/v1.x<=1 : res.append(b.end) - else : - if 0<=(self.st.y-b.st.y)/v2.y<=1 : res.append(self.st) - if 0<=(self.end.y-b.st.y)/v2.y<=1 : res.append(self.end) - if 0<=(b.st.y-self.st.y)/v1.y<=1 : res.append(b.st) - if 0<=(b.end.y-b.st.y)/v1.y<=1 : res.append(b.end) - return res - else : - t1 = ( -v1.x*(b.end.y-self.end.y) + v1.y*(b.end.x-self.end.x) ) / x - t2 = ( -v1.y*(self.st.x-b.st.x) + v1.x*(self.st.y-b.st.y) ) / x - - gcodetools.error((x,t1,t2), "warning") - if 0<=t1<=1 and 0<=t2<=1 : return [ self.st+v1*t1 ] - else : return [] - else: return [] - - - - -class Biarc: - def __init__(self, items=None): - if items == None : - self.items = [] - else: - self.items = items - - def l(self) : - return sum([i.length() for i in items]) - - def close(self) : - for subitems in self.items: - if (subitems[0].st-subitems[-1].end).l2()>10e-16 : - subitems.append(Line(subitems[-1].end,subitems[0].st)) - - def offset(self,r) : - # offset each element - self.close() - for subitems in self.items : - for item in subitems : - item.offset(r) - self.connect(r) - - def connect(self, r) : - for subitems in self.items : - for a,b in zip(subitems, subitems[1:]) : - i = a.intersect(b) - for p in i : - draw_pointer(p.to_list()) - - - - - def clip_offset(self): - pass - - def draw(self, layer, group=None, style=styles["biarc_style"]): - global gcodetools - gcodetools.set_markers() - - 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: - if "preview_groups" not in dir(options.self) : - gcodetools.preview_groups = { layer: inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) } - elif layer not in gcodetools.preview_groups : - gcodetools.preview_groups[layer] = inkex.etree.SubElement( gcodetools.layers[min(1,len(gcodetools.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) - group = gcodetools.preview_groups[layer] - - transform = gcodetools.get_transforms(group) - if transform != [] : - transform = gcodetools.reverse_transform(transform) - transform = simpletransform.formatTransform(transform) - - 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 = gcodetools.transform(a, layer, True), gcodetools.transform(b, layer, True), gcodetools.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 - - - num = 0 - for subitems in self.items : - for item in subitems : - num += 1 - #if num>1 : break - item.draw(group, style, layer, transform, num, reverse_angle) - - def from_old_style(self, curve) : - #Crve defenitnion [start point, type = {'arc','line','move','end'}, arc center, arc angle, end point, [zstart, zend]] - self.items = [] - for sp in curve: - print_(sp) - if sp[1] == 'move': - self.items.append([]) - if sp[1] == 'arc': - self.items[-1].append(Arc(sp[0],sp[4],sp[2],sp[3])) - if sp[1] == 'line': - self.items[-1].append(Line(sp[0],sp[4])) - - - - - -################################################################################ -### -### 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" - #draw_csp([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 : - #draw_csp([[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) - #draw_csp([prev],"Blue") - #draw_csp([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) - #draw_csp([prev],"Blue") - #draw_csp([arc],"Red") - #draw_csp([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)): - # draw_csp([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)): - # draw_csp([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 : - draw_csp([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 - #draw_csp(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: - draw_csp([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: - draw_csp([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**2 : - 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)) - - l = (P0-P2).l2() - if l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R1.l2() /100 : - # arc should be straight otherwise it could be threated as full circle - arc1 = [ sp1[1], 'line', 0, 0, [P2.x,P2.y], [z1,zm] ] - else : - arc1 = [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ] - - l = (P4-P2).l2() - if l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R2.l2() /100 : - # arc should be straight otherwise it could be threated as full circle - arc2 = [ [P2.x,P2.y], 'line', 0, 0, [P4.x,P4.y], [zm,z2] ] - else : - arc2 = [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ] - - return [ arc1, arc2 ] - - -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, - "regex" : self.re_sub_on_gcode_lines - } - - - 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, parameters): - gcode = self.gcode.split("\n") - self.gcode = "" - try : - for line in gcode : - self.gcode += eval( "re.sub(%s,line)"%parameters) +"\n" - - except Exception as ex : - self.error("Bad parameters for regexp. They should be as re.sub pattern and replacement parameters! For example: r\"G0(\d)\", r\"G\\1\" \n(Parameters: '%s')\n %s"%(parameters, ex), "error") - - - 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) : - self.polygon = [ - [ - [point[0]*cos - point[1]*sin,point[0]*sin + point[1]*cos] for point in subpoly - ] - for subpoly in self.polygon - ] - - - 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, group = None) : - csp = [csp_subpath_line_to([],poly+[poly[0]]) for poly in self.polygon] - draw_csp( csp, color=color,width=width, group = group) - - - - 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 dimensions - # 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 : - pass -# 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): - time_ = time.time() - 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( self.polygons[spiece[0][0]].polygon[:]) - poly.rotate(spiece[0][1]*math.pi2) - surface = Polygon(poly.polygon) - for p in spiece[1:] : - poly = Polygon(self.polygons[p[0]].polygon[:]) - c = surface.centroid() - surface.move(-c[0],-c[1]) - c1 = poly.centroid() - poly.move(-c1[0],-c1[1]) - poly.rotate(p[1]*math.pi2+p[2]*math.pi2) - surface.rotate(p[2]*math.pi2) - poly.drop_down(surface) - surface.add(poly) - surface.rotate(-p[2]*math.pi2) - return surface - - - def test_inline(self) : - ### - ### Fast test function using weave's from scipy inline function - ### - try : - converters is None - except : - try: - from scipy import weave - from scipy.weave import converters - except: - options.self.error("For this function Scipy is needed. See http://www.cnc-club.ru/gcodetools for details.","error") - - # Prepare vars - poly_, subpoly_, points_ = [], [], [] - for poly in self.polygons : - p = poly.polygon - poly_ += [len(subpoly_), len(subpoly_)+len(p)*2] - for subpoly in p : - subpoly_ += [len(points_), len(points_)+len(subpoly)*2+2] - for point in subpoly : - points_ += point - points_ += subpoly[0] # Close subpolygon - - test_ = [] - population_ = [] - for spiece in self.population: - test_.append( spiece[0] if spiece[0] != None else -1) - for sp in spiece[1]: - population_ += sp - - lp_, ls_, l_, lt_ = len(poly_), len(subpoly_), len(points_), len(test_) - - f = open('inline_test.c', 'r') - code = f.read() - f.close() - - f = open('inline_test_functions.c', 'r') - functions = f.read() - f.close() - - stdout_ = sys.stdout - s = '' - sys.stdout = s - - test = weave.inline( - code, - ['points_','subpoly_','poly_', 'lp_', 'ls_', 'l_', 'lt_','test_', 'population_'], - compiler='gcc', - support_code = functions, - ) - if s!='' : options.self.error(s,"warning") - sys.stdout = stdout_ - - for i in range(len(test_)): - self.population[i][0] = test_[i] - - - - - #surface.draw() - - -################################################################################ -### -### Gcodetools class -### -################################################################################ - -class Gcodetools(inkex.Effect): - - def export_gcode(self,gcode, no_headers = False) : - 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) - - if not no_headers : - postprocessor.gcode = self.header + postprocessor.gcode + self.footer - - f = open(self.options.directory+self.options.file, "w") - f.write(postprocessor.gcode) - f.close() - - -################################################################################ -### In/out paths: -### TODO move it to the bottom -################################################################################ - def plasma_prepare_path(self) : - - def add_arc(sp1,sp2,end = False,l=10.,r=10.) : - if not end : - n = csp_normalized_normal(sp1,sp2,0.) - return csp_reverse([arc_from_s_r_n_l(sp1[1],r,n,-l)])[0] - else: - n = csp_normalized_normal(sp1,sp2,1.) - return arc_from_s_r_n_l(sp2[1],r,n,l) - - def add_normal(sp1,sp2,end = False,l=10.,r=10.) : - # r is needed only for be compatible with add_arc - if not end : - n = csp_normalized_normal(sp1,sp2,0.) - p = [n[0]*l+sp1[1][0],n[1]*l+sp1[1][1]] - return csp_subpath_line_to([], [p,sp1[1]]) - else: - n = csp_normalized_normal(sp1,sp2,1.) - p = [n[0]*l+sp2[1][0],n[1]*l+sp2[1][1]] - return csp_subpath_line_to([], [sp2[1],p]) - - def add_tangent(sp1,sp2,end = False,l=10.,r=10.) : - # r is needed only for be compatible with add_arc - if not end : - n = csp_normalized_slope(sp1,sp2,0.) - p = [-n[0]*l+sp1[1][0],-n[1]*l+sp1[1][1]] - return csp_subpath_line_to([], [p,sp1[1]]) - else: - n = csp_normalized_slope(sp1,sp2,1.) - p = [n[0]*l+sp2[1][0],n[1]*l+sp2[1][1]] - return csp_subpath_line_to([], [sp2[1],p]) - - if not self.options.in_out_path and not self.options.plasma_prepare_corners and self.options.in_out_path_do_not_add_reference_point: - self.error("Warning! Extenstion is not said to do anything! Enable one of Create in-out paths or Prepare corners checkboxes or disable Do not add in-out referense point!") - return - - # Add in-out-reference point if there is no one yet. - if ( (len(self.in_out_reference_points)==0 and self.options.in_out_path - or not self.options.in_out_path and not self.options.plasma_prepare_corners ) - and not self.options.in_out_path_do_not_add_reference_point) : - self.options.orientation_points_count = "in-out reference point" - self.orientation() - - if self.options.in_out_path or self.options.plasma_prepare_corners: - self.set_markers() - add_func = {"Round":add_arc, "Perpendicular": add_normal, "Tangent": add_tangent}[self.options.in_out_path_type] - if self.options.in_out_path_type == "Round" and self.options.in_out_path_len > self.options.in_out_path_radius*3/2*math.pi : - self.error("In-out len is to big for in-out radius will cropp it to be r*3/2*pi!", "warning") - - if self.selected_paths == {} and self.options.auto_select_paths: - self.selected_paths = self.paths - self.error(_("No paths are selected! Trying to work on all available paths."),"warning") - - if self.selected_paths == {}: - self.error(_("Nothing is selected. Please select something."),"warning") - a = self.options.plasma_prepare_corners_tolerance - corner_tolerance = cross([1.,0.], [math.cos(a),math.sin(a)]) - - for layer in self.layers : - if layer in self.selected_paths : - max_dist = self.transform_scalar(self.options.in_out_path_point_max_dist, layer, reverse=True) - l = self.transform_scalar(self.options.in_out_path_len, layer, reverse=True) - plasma_l = self.transform_scalar(self.options.plasma_prepare_corners_distance, layer, reverse=True) - r = self.transform_scalar(self.options.in_out_path_radius, layer, reverse=True) - l = min(l,r*3/2*math.pi) - - for path in self.selected_paths[layer]: - csp = self.apply_transforms( path, cubicsuperpath.parsePath(path.get("d")) ) - csp = csp_remove_zerro_segments(csp) - res = [] - - for subpath in csp : - # Find closes point to in-out reference point - # If subpath is open skip this step - if self.options.in_out_path : - # split and reverse path for further add in-out points - if point_to_point_d2(subpath[0][1], subpath[-1][1]) < 1.e-10 : - d = [1e100,1,1,1.] - for p in self.in_out_reference_points : - d1 = csp_to_point_distance([subpath], p, dist_bounds = [0,max_dist], tolerance=.01) - if d1[0] < d[0] : - d = d1[:] - p_ = p - if d[0] < max_dist**2 : - # Lets find is there any angles near this point to put in-out path in - # the angle if it's possible - # remove last node to make iterations easier - subpath[0][0] = subpath[-1][0] - del subpath[-1] - max_cross = [-1e100, None] - for j in range(len(subpath)) : - sp1,sp2,sp3 = subpath[j-2],subpath[j-1],subpath[j] - if point_to_point_d2(sp2[1],p_)<max_dist**2: - s1,s2 = csp_normalized_slope(sp1,sp2,1.), csp_normalized_slope(sp2,sp3,0.) - max_cross = max(max_cross,[cross(s1,s2),j-1]) - # return back last point - subpath.append(subpath[0]) - if max_cross[1] !=None and max_cross[0]>corner_tolerance : - # there's an angle near the point - j = max_cross[1] - if j<0 : j -= 1 - if j!=0 : - subpath = csp_concat_subpaths(subpath[j:],subpath[:j+1]) - else : - # have to cut path's segment - d,i,j,t = d - sp1,sp2,sp3 = csp_split(subpath[j-1],subpath[j],t) - subpath = csp_concat_subpaths([sp2,sp3], subpath[j:], subpath[:j], [sp1,sp2]) - - if self.options.plasma_prepare_corners : - # prepare corners - # find corners and add some nodes - # corner at path's start/end is ignored - res_ = [subpath[0]] - for sp2, sp3 in zip(subpath[1:],subpath[2:]) : - sp1 = res_[-1] - s1,s2 = csp_normalized_slope(sp1,sp2,1.), csp_normalized_slope(sp2,sp3,0.) - if cross(s1,s2) > corner_tolerance : - # got a corner to process - S1,S2 = P(s1),P(s2) - N = (S1-S2).unit()*plasma_l - SP2= P(sp2[1]) - P1 = (SP2 + N) - res_ += [ - [sp2[0],sp2[1], (SP2+S1*plasma_l).to_list() ], - [ (P1-N.ccw()/2 ).to_list(), P1.to_list(), (P1+N.ccw()/2).to_list()], - [(SP2-S2*plasma_l).to_list(), sp2[1],sp2[2]] - ] - else: - res_ += [sp2] - res_ += [sp3] - subpath = res_ - if self.options.in_out_path : - # finally add let's add in-out paths... - subpath = csp_concat_subpaths( - add_func(subpath[0],subpath[1],False,l,r), - subpath, - add_func(subpath[-2],subpath[-1],True,l,r) - ) - - - res += [ subpath ] - - - if self.options.in_out_path_replace_original_path : - path.set("d", cubicsuperpath.formatPath( self.apply_transforms(path,res,True) )) - else: - draw_csp(res, width=1, style=styles["in_out_path_style"] ) - -################################################################################ -### 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_("Reduced 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 algorithm start at %s"%(time_)) - start_time = time.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 = -1 - 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) - print_("Populate done at %s"%(time.time()-time_)) - """ - 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) - """ - if self.options.arrangement_inline_test : - population.test_inline() - else: - population.test(population.test_spiece_centroid) - - print_("Test done at %s"%(time.time()-time_)) - draw_new_champ = False - print_() - - - if population.population[0][0]!= last_champ : - draw_new_champ = True - improve = last_champ-population.population[0][0] - last_champ = population.population[0][0]*1 - - - print_("Cicle %s done in %s"%(i,time.time()-time_)) - time_ = time.time() - print_("%s incests been found"%population.inc) - 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\nSquare improvement = %f\nTime from start = %f"%(i,(b[2]-b[0])*(b[3]-b[1]),improve,time.time()-start_time),x,y-50) - 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("", "--path-to-gcode-order", action="store", type="string", dest="path_to_gcode_order", default="path by path", help="Defines cutting order path by path or layer by layer.") - self.OptionParser.add_option("", "--path-to-gcode-depth-function",action="store", type="string", dest="path_to_gcode_depth_function", default="zd", help="Path to gcode depth function.") - self.OptionParser.add_option("", "--path-to-gcode-sort-paths", action="store", type="inkbool", dest="path_to_gcode_sort_paths", default=True, help="Sort paths to reduce rapid distance.") - self.OptionParser.add_option("", "--comment-gcode", action="store", type="string", dest="comment_gcode", default="", help="Comment Gcode") - self.OptionParser.add_option("", "--comment-gcode-from-properties",action="store", type="inkbool", dest="comment_gcode_from_properties", default=False,help="Get additional comments from Object Properties") - - - - 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="0", help="Area curves overlaping (depends on tool diameter [0,0.9])") - self.OptionParser.add_option("", "--area-tool-overlap", action="store", type="float", dest="area_tool_overlap", 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-fill-angle", action="store", type="float", dest="area_fill_angle", default="0", help="Fill area with lines heading this angle") - self.OptionParser.add_option("", "--area-fill-shift", action="store", type="float", dest="area_fill_shift", default="0", help="Shift the lines by tool d * shift") - self.OptionParser.add_option("", "--area-fill-method", action="store", type="string", dest="area_fill_method", default="zig-zag", help="Filling method either zig-zag or spiral") - - 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="Distance from original path where engraving is not needed (usually 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("", "--lathe-rectangular-cutter-width",action="store", type="float", dest="lathe_rectangular_cutter_width", default="4", help="Rectangular cutter width") - - 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="string", 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 definition") - - 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("", "--arrangement-inline-test", action="store", type="inkbool", dest="arrangement_inline_test", default=False, help="Use C-inline test (some additional packets will be needed)") - - - 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.OptionParser.add_option("", "--graffiti-max-seg-length", action="store", type="float", dest="graffiti_max_seg_length", default=1., help="Graffiti maximum segment length.") - self.OptionParser.add_option("", "--graffiti-min-radius", action="store", type="float", dest="graffiti_min_radius", default=10., help="Graffiti minimal connector's radius.") - self.OptionParser.add_option("", "--graffiti-start-pos", action="store", type="string", dest="graffiti_start_pos", default="(0;0)", help="Graffiti Start position (x;y).") - self.OptionParser.add_option("", "--graffiti-create-linearization-preview", action="store", type="inkbool", dest="graffiti_create_linearization_preview", default=True, help="Graffiti create linearization preview.") - self.OptionParser.add_option("", "--graffiti-create-preview", action="store", type="inkbool", dest="graffiti_create_preview", default=True, help="Graffiti create preview.") - self.OptionParser.add_option("", "--graffiti-preview-size", action="store", type="int", dest="graffiti_preview_size", default=800, help="Graffiti preview's size.") - self.OptionParser.add_option("", "--graffiti-preview-emmit", action="store", type="int", dest="graffiti_preview_emmit", default=800, help="Preview's paint emmit (pts/s).") - - - self.OptionParser.add_option("", "--in-out-path", action="store", type="inkbool", dest="in_out_path", default=True, help="Create in-out paths") - self.OptionParser.add_option("", "--in-out-path-do-not-add-reference-point", action="store", type="inkbool", dest="in_out_path_do_not_add_reference_point", default=False, help="Just add reference in-out point") - self.OptionParser.add_option("", "--in-out-path-point-max-dist", action="store", type="float", dest="in_out_path_point_max_dist", default=10., help="In-out path max distance to reference point") - self.OptionParser.add_option("", "--in-out-path-type", action="store", type="string", dest="in_out_path_type", default="Round", help="In-out path type") - self.OptionParser.add_option("", "--in-out-path-len", action="store", type="float", dest="in_out_path_len", default=10., help="In-out path length") - self.OptionParser.add_option("", "--in-out-path-replace-original-path",action="store", type="inkbool", dest="in_out_path_replace_original_path", default=False, help="Replace original path") - self.OptionParser.add_option("", "--in-out-path-radius", action="store", type="float", dest="in_out_path_radius", default=10., help="In-out path radius for round path") - - self.OptionParser.add_option("", "--plasma-prepare-corners", action="store", type="inkbool", dest="plasma_prepare_corners", default=True, help="Prepare corners") - self.OptionParser.add_option("", "--plasma-prepare-corners-distance", action="store", type="float", dest="plasma_prepare_corners_distance", default=10.,help="Stepout distance for corners") - self.OptionParser.add_option("", "--plasma-prepare-corners-tolerance", action="store", type="float", dest="plasma_prepare_corners_tolerance", default=10.,help="Maximum angle for corner (0-180 deg)") - - 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 - - -################################################################################ -### Draw csp -################################################################################ - - def draw_csp(self, csp, layer=None, group=None, fill='none', stroke='#178ade', width=0.354, style=None): - if layer!=None : - csp = self.transform_csp(csp,layer,reverse=True) - if group==None and layer==None: - group = self.document.getroot() - elif group==None and layer!=None : - group = layer - csp = self.apply_transforms(group,csp, reverse=True) - if style!=None : - return draw_csp(csp, group=group, style=style) - else : - return draw_csp(csp, group=group, fill=fill, stroke=stroke, width=width) - - - - - def draw_curve(self, curve, layer, group=None, style=styles["biarc_style"]): - self.set_markers() - - 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: - if "preview_groups" not in dir(self) : - self.preview_groups = { layer: inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) } - elif layer not in self.preview_groups : - self.preview_groups[layer] = inkex.etree.SubElement( self.layers[min(1,len(self.layers)-1)], inkex.addNS('g','svg'), {"gcodetools": "Preview group"} ) - group = self.preview_groups[layer] - - s, arcn = '', 0 - - transform = self.get_transforms(group) - if transform != [] : - transform = self.reverse_transform(transform) - transform = simpletransform.formatTransform(transform) - - 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': - attr = { 'style': style['line'], - 'd':'M %s,%s L %s,%s' % (s[0][0], s[0][1], si[0][0], si[0][1]), - "gcodetools": "Preview", - } - if transform != [] : - attr["transform"] = transform - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr ) - 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)] - - attr = { - '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", - } - - if transform != [] : - attr["transform"] = transform - inkex.etree.SubElement( group, inkex.addNS('path','svg'), attr) - 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 directory: '%s'"%self.options.directory) - if (os.path.isdir(self.options.directory)): - if (os.path.isfile(self.options.directory+'header')): - f = open(self.options.directory+'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 - - if self.options.directory[-1] not in ["/","\\"]: - if "\\" in self.options.directory : - self.options.directory += "\\" - else : - self.options.directory += "/" - - 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. -### -### Curve definition [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] - g = "" - - 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) - - if tool != self.last_used_tool : - g += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",tool["name"]) ) + tool["tool change gcode"] + "\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 +"(Penetrate)\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 + "(Penetrate)\n" - if (r[0]**2 + r[1]**2)>self.options.min_arc_radius**2: - 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 reverse_transform(self,transform): - trans = numpy.array(transform + [[0,0,1]]) - if numpy.linalg.det(trans)!=0 : - trans = numpy.linalg.inv(trans).tolist()[:2] - return trans - else : - return transform - - - def apply_transforms(self,g,csp, reverse=False): - trans = self.get_transforms(g) - if trans != []: - if not reverse : - simpletransform.applyTransformToPath(trans, csp) - else : - simpletransform.applyTransformToPath(self.reverse_transform(trans), csp) - return csp - - - - def transform_scalar(self,x,layer,reverse=False): - return self.transform([x,0],layer,reverse)[0] - self.transform([0,0],layer,reverse)[0] - - 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]] - self.Zcoordinates[layer] = self.Zcoordinates[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 should 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 should 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 and 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 - orientation_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 - Continue - """ - errors = """ - Error - wrong_orientation_points - area_tools_diameter_error - no_tool_error - active_layer_already_has_tool - active_layer_already_has_orientation_points - """ - s = str(s) - 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() - - -################################################################################ -### Set markers -################################################################################ - def set_markers(self) : - 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":"-4","refY":"-1.687441","style":"overflow:visible"}) - inkex.etree.SubElement( marker, inkex.addNS("path","svg"), - - { "d":" m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882", - "style": "fill:#000044; fill-rule:evenodd;stroke:none;" } - ) - - 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":"-4","refY":"-1.687441","style":"overflow:visible"}) - inkex.etree.SubElement( marker, inkex.addNS("path","svg"), - { "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882", - "style": "fill:#000044; fill-rule:evenodd;stroke:none;" } - ) - - 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":"4","refY":"-1.687441","style":"overflow:visible"}) - inkex.etree.SubElement( marker, inkex.addNS("path","svg"), - { "d":"m 4.588864,-1.687441 0.0,0.0 L 9.177728,0.0 c -0.73311,-0.996261 -0.728882,-2.359329 0.0,-3.374882", - "style": "fill:#000044; fill-rule:evenodd;stroke:none;" } - ) - - if "InOutPathMarker" 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":"InOutPathMarker","orient":"auto","refX":"-4","refY":"-1.687441","style":"overflow:visible"}) - inkex.etree.SubElement( marker, inkex.addNS("path","svg"), - { "d":"m -4.588864,-1.687441 0.0,0.0 L -9.177728,0.0 c 0.73311,-0.996261 0.728882,-2.359329 0.0,-3.374882", - "style": "fill:#0072a7; fill-rule:evenodd;stroke:none;" } - ) - - - -################################################################################ -### 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.graffiti_reference_points = {} - self.layers = [self.document.getroot()] - self.Zcoordinates = {} - self.transform_matrix = {} - self.transform_matrix_reverse = {} - self.Zauto_scale = {} - self.in_out_reference_points = [] - self.my3Dlayer = None - - 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': - if i.get(inkex.addNS('label','inkscape')) == '3D' : - self.my3Dlayer=i - else : - 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") - - #Need to recognise old files ver 1.6.04 and earlier - elif i.get("gcodetools") == "Gcodetools tool definition" or 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.get("gcodetools") == "Gcodetools graffiti reference point" : - point = self.get_graffiti_reference_points(i) - if point != [] : - self.graffiti_reference_points[layer] = self.graffiti_reference_points[layer]+[point[:]] if layer in self.graffiti_reference_points else [point] - else : - self.error(_("Warning! Found bad graffiti reference point in '%s' layer. Resulting Gcode could be corrupt!") % layer.get(inkex.addNS('label','inkscape')), "bad_orientation_points_in_some_layers") - - 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.get("gcodetools") == "In-out reference point group" : - items_ = i.getchildren() - items_.reverse() - for j in items_ : - if j.get("gcodetools") == "In-out reference point" : - self.in_out_reference_points.append( self.apply_transforms(j,cubicsuperpath.parsePath(j.get("d")))[0][0][1] ) - - - 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()) - - if len(self.layers) == 1 : - self.error(_("Document has no layers! Add at least one layer using layers panel (Ctrl+Shift+L)"),"Error") - root = self.document.getroot() - - if root in self.selected_paths or root in self.paths : - self.error(_("Warning! There are some paths in the root of the document, but not in any layer! Using bottom-most layer for them."), "tools_warning" ) - - if root in self.selected_paths : - if self.layers[-1] in self.selected_paths : - self.selected_paths[self.layers[-1]] += self.selected_paths[root][:] - else : - self.selected_paths[self.layers[-1]] = self.selected_paths[root][:] - del self.selected_paths[root] - - if root in self.paths : - if self.layers[-1] in self.paths : - self.paths[self.layers[-1]] += self.paths[root][:] - else : - self.paths[self.layers[-1]] = self.paths[root][:] - del self.paths[root] - - - 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*',get_text(node)) - 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_graffiti_reference_points(self,g): - point = [[], ''] - for node in g : - if node.get('gcodetools') == "Gcodetools graffiti reference point arrow": - point[0] = self.apply_transforms(node,cubicsuperpath.parsePath(node.get("d")))[0][0][1] - if node.get('gcodetools') == "Gcodetools graffiti reference point text": - point[1] = get_text(node) - if point[0]!=[] and point[1]!='' : return point - else : return [] - - 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: - #need to recognise old tools from ver 1.6.04 - if j.get("gcodetools") == "Gcodetools tool definition field name" or j.get("gcodetools") == "Gcodetools tool defention field name": - key = get_text(j) - if j.get("gcodetools") == "Gcodetools tool definition field value" or j.get("gcodetools") == "Gcodetools tool defention field value": - value = get_text(j) - if value == "(None)": value = "" - 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) : - from functools import partial - 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 sort_lines(lines): - if len(lines) == 0 : return [] - lines = [ [key]+lines[key] for key in range(len(lines))] - keys = [0] - end_point = lines[0][3:] - print_("!!!",lines,"\n",end_point) - del lines[0] - while len(lines)>0: - dist = [ [point_to_point_d2(end_point,lines[i][1:3]),i] for i in range(len(lines))] - i = min(dist)[1] - keys.append(lines[i][0]) - end_point = lines[i][3:] - del lines[i] - return keys - - def sort_curves(curves): - lines = [] - for curve in curves: - lines += [curve[0][0][0] + curve[-1][-1][0]] - return sort_lines(lines) - - 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 - - def get_path_properties(node, recursive=True, tags={inkex.addNS('desc','svg'):"Description",inkex.addNS('title','svg'):"Title"} ) : - res = {} - done = False - root = self.document.getroot() - while not done and node != root : - for i in node.getchildren(): - if i.tag in tags: - res[tags[i.tag]] = i.text - done = True - node = node.getparent() - return res - - 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)) - colors = {} - for layer in self.layers : - if layer in paths : - print_(("layer",layer)) - # transform simple path to get all var about orientation - self.transform_csp([ [ [[0,0],[0,0],[0,0]], [[0,0],[0,0],[0,0]] ] ], layer) - - self.set_tool(layer) - curves = [] - dxfpoints = [] - - try : - depth_func = eval('lambda c,d,s: ' + self.options.path_to_gcode_depth_function.strip('"')) - except: - self.error("Bad depth function! Enter correct function at Path to Gcode tab!") - - for path in paths[layer] : - if "d" not in path.keys() : - self.error(_("Warning: One or more paths do not 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) - id_ = path.get("id") - - def set_comment(match, path): - if match.group(1) in path.keys() : - return path.get(match.group(1)) - else: - return "None" - if self.options.comment_gcode != "" : - comment = re.sub("\[([A-Za-z_\-\:]+)\]", partial(set_comment, path=path), self.options.comment_gcode) - comment = comment.replace(":newline:","\n") - comment = gcode_comment_str(comment) - else: - comment = "" - if self.options.comment_gcode_from_properties : - tags = get_path_properties(path) - for tag in tags : - comment += gcode_comment_str("%s: %s"%(tag,tags[tag])) - - style = simplestyle.parseStyle(path.get("style")) - colors[id_] = simplestyle.parseColor(style['stroke'] if "stroke" in style and style['stroke']!='none' else "#000") - 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: - - zd,zs = self.Zcoordinates[layer][1], self.Zcoordinates[layer][0] - c = 1. - float(sum(colors[id_]))/255/3 - curves += [ - [ - [id_, depth_func(c,zd,zs), comment], - [ self.parse_curve([subpath], layer) for subpath in csp ] - ] - ] -# for c in curves : -# print_(c) - dxfpoints=sort_dxfpoints(dxfpoints) - gcode+=print_dxfpoints(dxfpoints) - - - for curve in curves : - for subcurve in curve[1] : - self.draw_curve(subcurve, layer) - - if self.options.path_to_gcode_order == 'subpath by subpath': - curves_ = [] - for curve in curves : - curves_ += [ [curve[0],[subcurve]] for subcurve in curve[1] ] - curves = curves_ - - self.options.path_to_gcode_order = 'path by path' - - if self.options.path_to_gcode_order == 'path by path': - if self.options.path_to_gcode_sort_paths : - keys = sort_curves( [curve[1] for curve in curves] ) - else : - keys = range(len(curves)) - for key in keys: - d = curves[key][0][1] - for step in range( 0, int(math.ceil( abs((zs-d)/self.tools[layer][0]["depth step"] )) ) ): - z = max(d, zs - abs(self.tools[layer][0]["depth step"]*(step+1))) - - gcode += gcode_comment_str("\nStart cutting path id: %s"%curves[key][0][0]) - if curves[key][0][2] != "()" : - gcode += curves[key][0][2] # add comment - - for curve in curves[key][1]: - gcode += self.generate_gcode(curve, layer, z) - - gcode += gcode_comment_str("End cutting path id: %s\n\n"%curves[key][0][0]) - - else: # pass by pass - mind = min( [curve[0][1] for curve in curves] ) - for step in range( 0, int(math.ceil( abs((zs-mind)/self.tools[layer][0]["depth step"] )) ) ): - z = zs - abs(self.tools[layer][0]["depth step"]*(step)) - curves_ = [] - for curve in curves: - if curve[0][1]<z : - curves_.append(curve) - - z = zs - abs(self.tools[layer][0]["depth step"]*(step+1)) - gcode += "\n(Pass at depth %s)\n"%z - - if self.options.path_to_gcode_sort_paths : - keys = sort_curves( [curve[1] for curve in curves_] ) - else : - keys = range(len(curves_)) - for key in keys: - - gcode += gcode_comment_str("Start cutting path id: %s"%curves[key][0][0]) - if curves[key][0][2] != "()" : - gcode += curves[key][0][2] # add comment - - for subcurve in curves_[key][1]: - gcode += self.generate_gcode(subcurve, layer, max(z,curves_[key][0][1])) - - gcode += gcode_comment_str("End cutting path id: %s\n\n"%curves[key][0][0]) - - - self.export_gcode(gcode) - -################################################################################ -### -### dxfpoints -### -################################################################################ - def dxfpoints(self): - if self.selected_paths == {}: - self.error(_("Nothing 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 do not 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")) - remove = [] - for i in range(len(csp)) : - subpath = [ [point[:] for point in points] for points in csp[i]] - subpath = self.apply_transforms(path,[subpath])[0] - 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" : - arrow = cubicsuperpath.parsePath( '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]) ) - arrow = self.apply_transforms(path,arrow,True) - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), - { - 'd': cubicsuperpath.formatPath(arrow), - 'style': styles["area artefact arrow"], - 'gcodetools': 'area artefact arrow', - }) - elif self.options.area_find_artefacts_action == "mark with style" : - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), {'d': cubicsuperpath.formatPath(csp[i]), 'style': styles["area artefact"]}) - remove.append(i) - elif self.options.area_find_artefacts_action == "delete" : - remove.append(i) - print_("Deleted artefact %s" % subpath ) - remove.reverse() - for i in remove : - del csp[i] - if len(csp) == 0 : - parent.remove(path) - else : - path.set("d", cubicsuperpath.formatPath(csp)) - - 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 beginning 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)) - - # avoiding infinite loops - if self.options.area_tool_overlap>0.9 : self.options.area_tool_overlap = .9 - - for i in range(self.options.max_area_curves): - radius = - tool_d * (i*(1-self.options.area_tool_overlap)+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 - - -################################################################################ -### -### Polyline to biarc -### -### Converts Polyline to Biarc -################################################################################ - def polyline_to_biarc(self): - - - - def biarc(sm, 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**2 : - 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)) - - l = (P0-P2).l2() - if l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R1.l2() /100 : - # arc should be straight otherwise it could be threated as full circle - arc1 = [ sp1[1], 'line', 0, 0, [P2.x,P2.y], [z1,zm] ] - else : - arc1 = [ sp1[1], 'arc', [R1.x,R1.y], a1, [P2.x,P2.y], [z1,zm] ] - - l = (P4-P2).l2() - if l < EMC_TOLERANCE_EQUAL**2 or l<EMC_TOLERANCE_EQUAL**2 * R2.l2() /100 : - # arc should be straight otherwise it could be threated as full circle - arc2 = [ [P2.x,P2.y], 'line', 0, 0, [P4.x,P4.y], [zm,z2] ] - else : - arc2 = [ [P2.x,P2.y], 'arc', [R2.x,R2.y], a2, [P4.x,P4.y], [zm,z2] ] - - return [ arc1, arc2 ] - - - - - - for layer in self.layers : - if layer in self.selected_paths : - for path in self.selected_paths[layer]: - d = path.get('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) - csp = self.apply_transforms(path, csp) - csp = self.transform_csp(csp, layer) - - # lets pretend that csp is a polyline - poly = [ [point[1] for point in subpath] for subpath in csp ] - - self.draw_csp([ [ [point,point,point] for point in subpoly] for subpoly in poly ],layer) - - # lets create biarcs - for subpoly in poly : - # lets split polyline into different smooth parths. - - if len(subpoly)>2 : - smooth = [ [subpoly[0],subpoly[1]] ] - for p1,p2,p3 in zip(subpoly,subpoly[1:],subpoly[2:]) : - # normalize p1p2 and p2p3 to get angle - s1,s2 = normalize( p1[0]-p2[0], p1[1]-p2[1]), normalize( p3[0]-p2[0], p3[1]-p2[1]) - if cross(s1,s2) > corner_tolerance : - #it's an angle - smooth += [ [p2,p3] ] - else: - smooth[-1].append(p3) - for sm in smooth : - smooth_polyline_to_biarc(sm) - -################################################################################ -### -### Area fill -### -### Fills area with lines -################################################################################ - - - def area_fill(self): - # convert degrees into rad - self.options.area_fill_angle = self.options.area_fill_angle * math.pi / 180 - 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") - tool = self.tools[layer][0] - for path in self.selected_paths[layer]: - lines = [] - print_(("doing path", path.get("style"), path.get("d"))) - area_group = inkex.etree.SubElement( path.getparent(), inkex.addNS('g','svg') ) - d = path.get('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) - csp = self.apply_transforms(path, csp) - csp = csp_close_all_subpaths(csp) - csp = self.transform_csp(csp, layer) - #maxx = max([x,y,i,j,root],maxx) - - # rotate the path to get bounds in defined direction. - a = - self.options.area_fill_angle - rotated_path = [ [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)] for point in sp] for sp in subpath] for subpath in csp ] - bounds = csp_true_bounds(rotated_path) - - # Draw the lines - # Get path's bounds - b = [0.0, 0.0, 0.0, 0.0] # [minx,miny,maxx,maxy] - for k in range(4): - i, j, t = bounds[k][2], bounds[k][3], bounds[k][4] - b[k] = csp_at_t(rotated_path[i][j-1],rotated_path[i][j],t)[k%2] - - - # Zig-zag - r = tool['diameter']*(1-self.options.area_tool_overlap) - if r<=0 : - self.error('Tools diameter must be greater than 0!', 'error') - return - - lines += [ [] ] - - if self.options.area_fill_method == 'zig-zag' : - i = b[0] - self.options.area_fill_shift*r - top = True - last_one = True - while (i<b[2] or last_one) : - if i>=b[2] : last_one = False - if lines[-1] == [] : - lines[-1] += [ [i,b[3]] ] - - if top : - lines[-1] += [ [i,b[1]],[i+r,b[1]] ] - - else : - lines[-1] += [ [i,b[3]], [i+r,b[3]] ] - - top = not top - i += r - else : - - w, h = b[2]-b[0] + self.options.area_fill_shift*r , b[3]-b[1] + self.options.area_fill_shift*r - x,y = b[0] - self.options.area_fill_shift*r, b[1] - self.options.area_fill_shift*r - lines[-1] += [ [x,y] ] - stage = 0 - start = True - while w>0 and h>0 : - stage = (stage+1)%4 - if stage == 0 : - y -= h - h -= r - elif stage == 1: - x += w - if not start: - w -= r - start = False - elif stage == 2 : - y += h - h -= r - elif stage == 3: - x -= w - w -=r - - lines[-1] += [ [x,y] ] - - stage = (stage+1)%4 - if w <= 0 and h>0 : - y = y-h if stage == 0 else y+h - if h <= 0 and w>0 : - x = x-w if stage == 3 else x+w - lines[-1] += [ [x,y] ] - # Rotate created paths back - a = self.options.area_fill_angle - lines = [ [ [point[0]*math.cos(a) - point[1]*math.sin(a), point[0]*math.sin(a)+point[1]*math.cos(a)] for point in subpath] for subpath in lines ] - - # get the intersection points - - splitted_line = [ [lines[0][0]] ] - intersections = {} - for l1,l2, in zip(lines[0],lines[0][1:]): - ints = [] - - if l1[0]==l2[0] and l1[1]==l2[1] : continue - for i in range(len(csp)) : - for j in range(1,len(csp[i])) : - sp1,sp2 = csp[i][j-1], csp[i][j] - roots = csp_line_intersection(l1,l2,sp1,sp2) - for t in roots : - p = tuple(csp_at_t(sp1,sp2,t)) - if l1[0]==l2[0] : - t1 = (p[1]-l1[1])/(l2[1]-l1[1]) - else : - t1 = (p[0]-l1[0])/(l2[0]-l1[0]) - if 0<=t1<=1 : - ints += [[t1, p[0],p[1], i,j,t]] - if p in intersections : - intersections[p] += [ [i,j,t] ] - else : - intersections[p] = [ [i,j,t] ] - #p = self.transform(p,layer,True) - #draw_pointer(p) - ints.sort() - for i in ints: - splitted_line[-1] +=[ [ i[1], i[2]] ] - splitted_line += [ [ [ i[1], i[2]] ] ] - splitted_line[-1] += [ l2 ] - i = 0 - print_(splitted_line) - while i < len(splitted_line) : - # check if the middle point of the first lines segment is inside the path. - # and remove the subline if not. - l1,l2 = splitted_line[i][0],splitted_line[i][1] - p = [(l1[0]+l2[0])/2, (l1[1]+l2[1])/2] - if not point_inside_csp(p, csp): - #i +=1 - del splitted_line[i] - else : - i += 1 - - - - # if we've used spiral method we'll try to save the order of cutting - do_not_change_order = self.options.area_fill_method == 'spiral' - # now let's try connect splitted lines - #while len(splitted_line)>0 : - #TODO - - # and apply back transrormations to draw them - csp_line = csp_from_polyline(splitted_line) - csp_line = self.transform_csp(csp_line, layer, True) - - self.draw_csp(csp_line, group = area_group) -# draw_csp(lines) - - - - - - -################################################################################ -### -### Engraving -### -#LT Notes to self: See wiki.inkscape.org/wiki/index.php/PythonEffectTutorial -# To create anything in the Inkscape document, look at the XML editor for -# details of how such an element looks in XML, then follow this model. -#layer number n appears in XML as <svg:g id="layern" inkscape:label="layername"> -# -#to create it, use -#Mylayer=inkex.etree.SubElement(self.document.getroot(), 'g') #Create a generic element -#Mylayer.set(inkex.addNS('label', 'inkscape'), "layername") #Gives it a name -#Mylayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') #Tells Inkscape it's a layer -# -#group appears in XML as <svg:g id="gnnnnn"> where nnnnn is a number -# -#to create it, use -#Mygroup=inkex.etree.SubElement(parent, inkex.addNS('g','svg'), {"gcodetools":"My group label"}) -# where parent may be the layer or a parent group. To get the parent group, you can use -#parent = self.selected_paths[layer][0].getparent() -################################################################################ - def engraving(self) : - #global x1,y1,rx,ry - global cspm, wl - global nlLT, i, j - global gcode_3Dleft ,gcode_3Dright - global max_dist #minimum of tool radius and user's requested maximum distance - global eye_dist - eye_dist = 100 #3D constant. Try varying it for your eyes - - - def bisect((nx1,ny1),(nx2,ny2)) : - """LT Find angle bisecting the normals n1 and n2 - - Parameters: Normalised normals - Returns: nx - Normal of bisector, normalised to 1/cos(a) - ny - - sinBis2 - sin(angle turned/2): positive if turning in - Note that bisect(n1,n2) and bisect(n2,n1) give opposite sinBis2 results - If sinturn is less than the user's requested angle tolerance, I return 0 - """ - #We can get absolute value of cos(bisector vector) - #Note: Need to use max in case of rounding errors - cosBis = math.sqrt(max(0,(1.0+nx1*nx2-ny1*ny2)/2.0)) - #We can get correct sign of the sin, assuming cos is positive - if (abs(ny1-ny2)< engraving_tolerance) or (abs(cosBis) < engraving_tolerance) : - if (abs(nx1-nx2)< engraving_tolerance): return(nx1,ny1,0.0) - sinBis = math.copysign(1,ny1) - else : - sinBis = cosBis*(nx2-nx1)/(ny1-ny2) - #We can correct signs by noting that the dot product - # of bisector and either normal must be >0 - costurn=cosBis*nx1+sinBis*ny1 - if costurn == 0 : return (ny1*100,-nx1*100,1) #Path doubles back on itself - sinturn=sinBis*nx1-cosBis*ny1 - if costurn<0 : sinturn=-sinturn - if 0 < sinturn*114.6 < (180-self.options.engraving_sharp_angle_tollerance) : - sinturn=0 #set to zero if less than the user wants to see. - return (cosBis/costurn,sinBis/costurn, sinturn) - #end bisect - - def get_radius_to_line((x1,y1),(nx1,ny1), (nx2,ny2),(x2,y2),(nx23,ny23),(x3,y3),(nx3,ny3)): - """LT find biggest circle we can engrave here, if constrained by line 2-3 - - Parameters: - x1,y1,nx1,ny1 coordinates and normal of the line we're currently engraving - nx2,ny2 angle bisector at point 2 - x2,y2 coordinates of first point of line 2-3 - nx23,ny23 normal to the line 2-3 - x3,y3 coordinates of the other end - nx3,ny3 angle bisector at point 3 - Returns: - radius or self.options.engraving_max_dist if line doesn't limit radius - This function can be used in three ways: - - With nx1=ny1=0 it finds circle centred at x1,y1 - - with nx1,ny1 normalised, it finds circle tangential at x1,y1 - - with nx1,ny1 scaled by 1/cos(a) it finds circle centred on an angle bisector - where a is the angle between the bisector and the previous/next normals - - If the centre of the circle tangential to the line 2-3 is outside the - angle bisectors at its ends, ignore this line. - - # Note that it handles corners in the conventional manner of letter cutting - # by mitering, not rounding. - # Algorithm uses dot products of normals to find radius - # and hence coordinates of centre - """ - - global max_dist - - #Start by converting coordinates to be relative to x1,y1 - x2,y2= x2-x1, y2-y1 - x3,y3= x3-x1, y3-y1 - - #The logic uses vector arithmetic. - #The dot product of two vectors gives the product of their lengths - #multiplied by the cos of the angle between them. - # So, the perpendicular distance from x1y1 to the line 2-3 - # is equal to the dot product of its normal and x2y2 or x3y3 - #It is also equal to the projection of x1y1-xcyc on the line's normal - # plus the radius. But, as the normal faces inside the path we must negate it. - - #Make sure the line in question is facing x1,y1 and vice versa - dist=-x2*nx23-y2*ny23 - if dist<0 : return max_dist - denom=1.-nx23*nx1-ny23*ny1 - if denom < engraving_tolerance : return max_dist - - #radius and centre are: - r=dist/denom - cx=r*nx1 - cy=r*ny1 - #if c is not between the angle bisectors at the ends of the line, ignore - #Use vector cross products. Not sure if I need the .0001 safety margins: - if (x2-cx)*ny2 > (y2-cy)*nx2 +0.0001 : - return max_dist - if (x3-cx)*ny3 < (y3-cy)*nx3 -0.0001 : - return max_dist - return min(r, max_dist) - #end of get_radius_to_line - - def get_radius_to_point((x1,y1),(nx,ny), (x2,y2)): - """LT find biggest circle we can engrave here, constrained by point x2,y2 - - This function can be used in three ways: - - With nx=ny=0 it finds circle centred at x1,y1 - - with nx,ny normalised, it finds circle tangential at x1,y1 - - with nx,ny scaled by 1/cos(a) it finds circle centred on an angle bisector - where a is the angle between the bisector and the previous/next normals - - Note that I wrote this to replace find_cutter_centre. It is far less - sophisticated but, I hope, far faster. - It turns out that finding a circle touching a point is harder than a circle - touching a line. - """ - - global max_dist - - #Start by converting coordinates to be relative to x1,y1 - x2,y2= x2-x1, y2-y1 - denom=nx**2+ny**2-1 - if denom<=engraving_tolerance : #Not a corner bisector - if denom==-1 : #Find circle centre x1,y1 - return math.sqrt(x2**2+y2**2) - #if x2,y2 not in front of the normal... - if x2*nx+y2*ny <=0 : return max_dist - #print_("Straight",x1,y1,nx,ny,x2,y2) - return (x2**2+y2**2)/(2*(x2*nx+y2*ny) ) - #It is a corner bisector, so.. - discriminator = (x2*nx+y2*ny)**2 - denom*(x2**2+y2**2) - if discriminator < 0 : - return max_dist #this part irrelevant - r=(x2*nx+y2*ny -math.sqrt(discriminator))/denom - #print_("Corner",x1,y1,nx,ny,x1+x2,y1+y2,discriminator,r) - return min(r, max_dist) - #end of get_radius_to_point - - def bez_divide(a,b,c,d): - """LT recursively divide a Bezier. - - Divides until difference between each - part and a straight line is less than some limit - Note that, as simple as this code is, it is mathematically correct. - Parameters: - a,b,c and d are each a list of x,y real values - Bezier end points a and d, control points b and c - Returns: - a list of Beziers. - Each Bezier is a list with four members, - each a list holding a coordinate pair - Note that the final point of one member is the same as - the first point of the next, and the control points - there are smooth and symmetrical. I use this fact later. - """ - bx=b[0]-a[0] - by=b[1]-a[1] - cx=c[0]-a[0] - cy=c[1]-a[1] - dx=d[0]-a[0] - dy=d[1]-a[1] - limit=8*math.hypot(dx,dy)/self.options.engraving_newton_iterations - #LT This is the only limit we get from the user currently - if abs(dx*by-bx*dy)<limit and abs(dx*cy-cx*dy)<limit : - return [[a,b,c,d]] - abx=(a[0]+b[0])/2.0 - aby=(a[1]+b[1])/2.0 - bcx=(b[0]+c[0])/2.0 - bcy=(b[1]+c[1])/2.0 - cdx=(c[0]+d[0])/2.0 - cdy=(c[1]+d[1])/2.0 - abcx=(abx+bcx)/2.0 - abcy=(aby+bcy)/2.0 - bcdx=(bcx+cdx)/2.0 - bcdy=(bcy+cdy)/2.0 - m=[(abcx+bcdx)/2.0,(abcy+bcdy)/2.0] - return bez_divide(a,[abx,aby],[abcx,abcy],m) + bez_divide(m,[bcdx,bcdy],[cdx,cdy],d) - #end of bez_divide - - def get_biggest((x1,y1),(nx,ny)): - """LT Find biggest circle we can draw inside path at point x1,y1 normal nx,ny - - Parameters: - point - either on a line or at a reflex corner - normal - normalised to 1 if on a line, to 1/cos(a) at a corner - Returns: - tuple (j,i,r) - ..where j and i are indices of limiting segment, r is radius - """ - global max_dist, nlLT, i, j - n1 = nlLT[j][i-1] #current node - jjmin = -1 - iimin = -1 - r = max_dist - # set limits within which to look for lines - xmin, xmax = x1+r*nx-r, x1+r*nx+r - ymin, ymax = y1+r*ny-r, y1+r*ny+r - for jj in xrange(0,len(nlLT)) : #for every subpath of this object - for ii in xrange(0,len(nlLT[jj])) : #for every point and line - if nlLT[jj][ii-1][2] : #if a point - if jj==j : #except this one - if abs(ii-i)<3 or abs(ii-i)>len(nlLT[j])-3 : continue - t1=get_radius_to_point((x1,y1),(nx,ny),nlLT[jj][ii-1][0] ) - #print_("Try pt i,ii,t1,x1,y1",i,ii,t1,x1,y1) - else: #doing a line - if jj==j : #except this one - if abs(ii-i)<2 or abs(ii-i)==len(nlLT[j])-1 : continue - if abs(ii-i)==2 and nlLT[j][(ii+i)/2-1][3]<=0 : continue - if (abs(ii-i)==len(nlLT[j])-2) and nlLT[j][-1][3]<=0 : continue - nx2,ny2 = nlLT[jj][ii-2][1] - x2,y2 = nlLT[jj][ii-1][0] - nx23,ny23 = nlLT[jj][ii-1][1] - x3,y3 = nlLT[jj][ii][0] - nx3,ny3 = nlLT[jj][ii][1] - if nlLT[jj][ii-2][3]>0 : #acute, so use normal, not bisector - nx2=nx23 - ny2=ny23 - if nlLT[jj][ii][3]>0 : #acute, so use normal, not bisector - nx3=nx23 - ny3=ny23 - x23min,x23max=min(x2,x3),max(x2,x3) - y23min,y23max=min(y2,y3),max(y2,y3) - #see if line in range - if n1[2]==False and (x23max<xmin or x23min>xmax or y23max<ymin or y23min>ymax) : continue - t1=get_radius_to_line((x1,y1),(nx,ny), (nx2,ny2),(x2,y2),(nx23,ny23), (x3,y3),(nx3,ny3)) - #print_("Try line i,ii,t1,x1,y1",i,ii,t1,x1,y1) - if 0<=t1<r : - r = t1 - iimin = ii - jjmin = jj - xmin, xmax = x1+r*nx-r, x1+r*nx+r - ymin, ymax = y1+r*ny-r, y1+r*ny+r - #next ii - #next jj - return (jjmin,iimin,r) - #end of get_biggest - - def line_divide((x0,y0),j0,i0,(x1,y1),j1,i1,(nx,ny),length): - """LT recursively divide a line as much as necessary - - NOTE: This function is not currently used - By noting which other path segment is touched by the circles at each end, - we can see if anything is to be gained by a further subdivision, since - if they touch the same bit of path we can move linearly between them. - Also, we can handle points correctly. - Parameters: - end points and indices of limiting path, normal, length - Returns: - list of toolpath points - each a list of 3 reals: x, y coordinates, radius - - """ - global nlLT, i, j, lmin - x2=(x0+x1)/2 - y2=(y0+y1)/2 - j2,i2,r2=get_biggest( (x2,y2), (nx,ny)) - if length<lmin : return [ [x2, y2, r2] ] - if j2==j0 and i2==i0 : #Same as left end. Don't subdivide this part any more - return [ [x2, y2, r2], line_divide((x2,y2),j2,i2,(x1,y1),j1,i1,(nx,ny),length/2)] - if j2==j1 and i2==i1 : #Same as right end. Don't subdivide this part any more - return [ line_divide((x0,y0),j0,i0,(x2,y2),j2,i2,(nx,ny),length/2), [x2, y2, r2] ] - return [ line_divide((x0,y0),j0,i0,(x2,y2),j2,i2,(nx,ny),length/2), line_divide((x2,y2),j2,i2,(x1,y1),j1,i1,(nx,ny),length/2)] - #end of line_divide() - - def save_point((x,y),w,i,j,ii,jj): - """LT Save this point and delete previous one if linear - - The point is, we generate tons of points but many may be in a straight 3D line. - There is no benefit in saving the imtermediate points. - """ - global wl, cspm - x=round(x,4) #round to 4 decimals - y=round(y,4) #round to 4 decimals - w=round(w,4) #round to 4 decimals - if len(cspm)>1 : - xy1a,xy1,xy1b,i1,j1,ii1,jj1=cspm[-1] - w1=wl[-1] - if i==i1 and j==j1 and ii==ii1 and jj==jj1 : #one match - xy1a,xy2,xy1b,i1,j1,ii1,jj1=cspm[-2] - w2=wl[-2] - if i==i1 and j==j1 and ii==ii1 and jj==jj1 : #two matches. Now test linearity - length1=math.hypot(xy1[0]-x,xy1[1]-y) - length2=math.hypot(xy2[0]-x,xy2[1]-y) - length12=math.hypot(xy2[0]-xy1[0],xy2[1]-xy1[1]) - #get the xy distance of point 1 from the line 0-2 - if length2>length1 and length2>length12 : #point 1 between them - xydist=abs( (xy2[0]-x)*(xy1[1]-y)-(xy1[0]-x)*(xy2[1]-y) )/length2 - if xydist<engraving_tolerance : #so far so good - wdist=w2+(w-w2)*length1/length2 -w1 - if abs(wdist)<engraving_tolerance : - #print_("pop",j,i,xy1) - cspm.pop() - wl.pop() - cspm+=[ [ [x,y],[x,y],[x,y],i,j,ii,jj ] ] - wl+=[w] - #end of save_point - - def draw_point((x0,y0),(x,y),w,t): - """LT Draw this point as a circle with a 1px dot in the middle (x,y) - and a 3D line from (x0,y0) down to x,y. 3D line thickness should be t/2 - - Note that points that are subsequently erased as being unneeded do get - displayed, but this helps the user see the total area covered. - """ - global gcode_3Dleft ,gcode_3Dright - if self.options.engraving_draw_calculation_paths : - inkex.etree.SubElement( engraving_group, inkex.addNS('path','svg'), - {"gcodetools": "Engraving calculation toolpath", 'style': "fill:#ff00ff; fill-opacity:0.46; stroke:#000000; stroke-width:0.1;", inkex.addNS('cx','sodipodi'): str(x), inkex.addNS('cy','sodipodi'): str(y), inkex.addNS('rx','sodipodi'): str(1), inkex.addNS('ry','sodipodi'): str(1), inkex.addNS('type','sodipodi'): 'arc'}) - #Don't draw zero radius circles - if w: - 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(x), inkex.addNS('cy','sodipodi'): str(y),inkex.addNS('rx','sodipodi'): str(w), inkex.addNS('ry','sodipodi'): str(w), inkex.addNS('type','sodipodi'): 'arc'}) - # Find slope direction for shading - s=math.atan2(y-y0,x-x0) #-pi to pi - # convert to 2 hex digits as a shade of red - s2="#{0:x}0000".format(int(101*(1.5-math.sin(s+0.5)))) - inkex.etree.SubElement( gcode_3Dleft , inkex.addNS('path','svg'), - { "d": "M %f,%f L %f,%f" %(x0-eye_dist,y0,x-eye_dist-0.14*w,y), - 'style': "stroke:" + s2 + "; stroke-opacity:1; stroke-width:" + str(t/2) +" ; fill:none", - "gcodetools": "Gcode G1R" - }) - inkex.etree.SubElement( gcode_3Dright , inkex.addNS('path','svg'), - { "d": "M %f,%f L %f,%f" %(x0+eye_dist,y0,x+eye_dist+0.14*r,y), - 'style': "stroke:" + s2 + "; stroke-opacity:1; stroke-width:" + str(t/2) +" ; fill:none", - "gcodetools": "Gcode G1L" - }) - #end of draw_point - - #end of subfunction definitions. engraving() starts here: - gcode = '' - r,w, wmax = 0,0,0 #theoretical and tool-radius-limited radii in pixels - x1,y1,nx,ny =0,0,0,0 - cspe =[] - we = [] - if len(self.selected_paths)<=0: - self.error(_("Please select at least one path to engrave and run again."),"warning") - return - if not self.check_dir() : return - #Find what units the user uses - unit=" mm" - if self.options.unit == "G20 (All units in inches)" : - unit=" inches" - elif self.options.unit != "G21 (All units in mm)" : - self.error(_("Unknown unit selected. mm assumed"),"warning") - print_("engraving_max_dist mm/inch", self.options.engraving_max_dist ) - - #LT See if we can use this parameter for line and Bezier subdivision: - bitlen=20/self.options.engraving_newton_iterations - - for layer in self.layers : - if layer in self.selected_paths : - #Calculate scale in pixels per user unit (mm or inch) - p1=self.orientation_points[layer][0][0] - p2=self.orientation_points[layer][0][1] - ol=math.hypot(p1[0][0]-p2[0][0],p1[0][1]-p2[0][1]) - oluu=math.hypot(p1[1][0]-p2[1][0],p1[1][1]-p2[1][1]) - print_("Orientation2 p1 p2 ol oluu",p1,p2,ol,oluu) - orientation_scale = ol/oluu - - self.set_tool(layer) - shape = self.tools[layer][0]['shape'] - if re.search('w', shape) : - toolshape = eval('lambda w: ' + shape.strip('"')) - else: - self.error(_("Tool '%s' has no shape. 45 degree cone assumed!") % self.tools[layer][0]['name'],"Continue") - toolshape = lambda w: w - #Get tool radius in pixels - toolr=self.tools[layer][0]['diameter'] * orientation_scale/2 - print_("tool radius in pixels=", toolr) - #max dist from path to engrave in user's units - max_distuu = min(self.tools[layer][0]['diameter']/2, self.options.engraving_max_dist) - max_dist=max_distuu*orientation_scale - print_("max_dist pixels", max_dist ) - - engraving_group = inkex.etree.SubElement( self.selected_paths[layer][0].getparent(), inkex.addNS('g','svg') ) - if self.options.engraving_draw_calculation_paths and (self.my3Dlayer == None) : - self.my3Dlayer=inkex.etree.SubElement(self.document.getroot(), 'g') #Create a generic element at root level - self.my3Dlayer.set(inkex.addNS('label', 'inkscape'), "3D") #Gives it a name - self.my3Dlayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') #Tells Inkscape it's a layer - #Create groups for left and right eyes - if self.options.engraving_draw_calculation_paths : - gcode_3Dleft = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D L"}) - gcode_3Dright = inkex.etree.SubElement(self.my3Dlayer, inkex.addNS('g','svg'), {"gcodetools":"Gcode 3D R"}) - - for node in self.selected_paths[layer] : - if node.tag == inkex.addNS('path','svg'): - cspi = cubicsuperpath.parsePath(node.get('d')) - #LT: Create my own list. n1LT[j] is for subpath j - nlLT = [] - for j in xrange(len(cspi)): #LT For each subpath... - # Remove zero length segments, assume closed path - i = 0 #LT was from 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: #LT6a For each subpath... - #Create copies in 3D layer - print_("csp is zz ",csp) - cspl=[] - cspr=[] - #create list containing lines and points, starting with a point - # line members: [x,y],[nx,ny],False,i - # x,y is start of line. Normal on engraved side. - # Normal is normalised (unit length) - #Note that Y axis increases down the page - # corner members: [x,y],[nx,ny],True,sin(halfangle) - # if halfangle>0: radius 0 here. normal is bisector - # if halfangle<0. reflex angle. normal is bisector - # corner normals are divided by cos(halfangle) - #so that they will engrave correctly - print_("csp is",csp) - nlLT.append ([]) - for i in range(0,len(csp)): #LT for each point - #n = [] - sp0, sp1, sp2 = csp[i-2], csp[i-1], csp[i] - if self.options.engraving_draw_calculation_paths: - #Copy it to 3D layer objects - spl=[] - spr=[] - for j in range(0,3) : - pl=[sp2[j][0]-eye_dist,sp2[j][1]] - pr=[sp2[j][0]+eye_dist,sp2[j][1]] - spl+=[pl] - spr+=[pr] - cspl+=[spl] - cspr+=[spr] - #LT find angle between this and previous segment - x0,y0 = sp1[1] - nx1,ny1 = csp_normalized_normal(sp1,sp2,0) - #I don't trust this function, so test result - if abs(1-math.hypot(nx1,ny1))> 0.00001 : - print_("csp_normalised_normal error t=0",nx1,ny1,sp1,sp2) - self.error(_("csp_normalised_normal error. See log."),"warning") - - nx0, ny0 = csp_normalized_normal(sp0,sp1,1) - if abs(1-math.hypot(nx0,ny0))> 0.00001 : - print_("csp_normalised_normal error t=1",nx0,ny0,sp1,sp2) - self.error(_("csp_normalised_normal error. See log."),"warning") - bx,by,s=bisect((nx0,ny0),(nx1,ny1)) - #record x,y,normal,ifCorner, sin(angle-turned/2) - nlLT[-1] += [[ [x0,y0],[bx,by], True, s]] - - #LT now do the line - if sp1[1]==sp1[2] and sp2[0]==sp2[1] : #straightline - nlLT[-1]+=[[sp1[1],[nx1,ny1],False,i]] - else : #Bezier. First, recursively cut it up: - nn=bez_divide(sp1[1],sp1[2],sp2[0],sp2[1]) - first=True #Flag entry to divided Bezier - for bLT in nn : #save as two line segments - for seg in range(3) : - if seg>0 or first : - nx1=bLT[seg][1]-bLT[seg+1][1] - ny1=bLT[seg+1][0]-bLT[seg][0] - l1=math.hypot(nx1,ny1) - if l1<engraving_tolerance : - continue - nx1=nx1/l1 #normalise them - ny1=ny1/l1 - nlLT[-1]+=[[bLT[seg],[nx1,ny1], False,i]] - first=False - if seg<2 : #get outgoing bisector - nx0=nx1 - ny0=ny1 - nx1=bLT[seg+1][1]-bLT[seg+2][1] - ny1=bLT[seg+2][0]-bLT[seg+1][0] - l1=math.hypot(nx1,ny1) - if l1<engraving_tolerance : - continue - nx1=nx1/l1 #normalise them - ny1=ny1/l1 - #bisect - bx,by,s=bisect((nx0,ny0),(nx1,ny1)) - nlLT[-1] += [[bLT[seg+1],[bx,by], True, 0.]] - #LT for each segment - ends here. - print_(("engraving_draw_calculation_paths=",self.options.engraving_draw_calculation_paths)) - if self.options.engraving_draw_calculation_paths: - #Copy complete paths to 3D layer - #print_("cspl",cspl) - cspl+=[cspl[0]] #Close paths - cspr+=[cspr[0]] #Close paths - inkex.etree.SubElement( gcode_3Dleft , inkex.addNS('path','svg'), - { "d": cubicsuperpath.formatPath([cspl]), - 'style': "stroke:#808080; stroke-opacity:1; stroke-width:0.6; fill:none", - "gcodetools": "G1L outline" - }) - inkex.etree.SubElement( gcode_3Dright , inkex.addNS('path','svg'), - { "d": cubicsuperpath.formatPath([cspr]), - 'style': "stroke:#808080; stroke-opacity:1; stroke-width:0.6; fill:none", - "gcodetools": "G1L outline" - }) - - for p in nlLT[-1]: #For last sub-path - if p[2]: 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:#f000af; stroke-opacity:0.46; stroke-width:0.1; fill:none", - "gcodetools": "Engraving normals" - }) - else: 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 bisectors" - }) - - - #LT6a build nlLT[j] for each subpath - ends here - #for nnn in nlLT : - #print_("nlLT",nnn) #LT debug stuff - # Calculate offset points - reflex=False - for j in xrange(len(nlLT)): #LT6b for each subpath - cspm=[] #Will be my output. List of csps. - wl=[] #Will be my w output list - w = r = 0 #LT initial, as first point is an angle - for i in xrange(len(nlLT[j])) : #LT for each node - #LT Note: Python enables wrapping of array indices - # backwards to -1, -2, but not forwards. Hence: - n0 = nlLT[j][i-2] #previous node - n1 = nlLT[j][i-1] #current node - n2 = nlLT[j][i] #next node - #if n1[2] == True and n1[3]==0 : # A straight angle - #continue - x1a,y1a = n1[0] #this point/start of this line - nx,ny = n1[1] - x1b,y1b = n2[0] #next point/end of this line - if n1[2] == True : # We're at a corner - bits=1 - bit0=0 - #lastr=r #Remember r from last line - lastw=w #Remember w from last line - w = max_dist - if n1[3]>0 : #acute. Limit radius - len1=math.hypot( (n0[0][0]-n1[0][0]),( n0[0][1]-n1[0][1]) ) - if i<(len(nlLT[j])-1) : - len2=math.hypot( (nlLT[j][i+1][0][0]-n1[0][0]),(nlLT[j][i+1][0][1]-n1[0][1]) ) - else: - len2=math.hypot( (nlLT[j][0][0][0]-n1[0][0]),(nlLT[j][0][0][1]-n1[0][1]) ) - #set initial r value, not to be exceeded - w = math.sqrt(min(len1,len2))/n1[3] - else: #line. Cut it up if long. - if n0[3]>0 and not self.options.engraving_draw_calculation_paths : - bit0=r*n0[3] #after acute corner - else : bit0=0.0 - length=math.hypot((x1b-x1a),(y1a-y1b)) - bit0=(min(length,bit0)) - bits=int((length-bit0)/bitlen) - #split excess evenly at both ends - bit0+=(length-bit0-bitlen*bits)/2 - #print_("j,i,r,bit0,bits",j,i,w,bit0,bits) - for b in xrange(bits) : #divide line into bits - x1=x1a+ny*(b*bitlen+bit0) - y1=y1a-nx*(b*bitlen+bit0) - jjmin,iimin,w=get_biggest( (x1,y1), (nx,ny)) - print_("i,j,jjmin,iimin,w",i,j,jjmin,iimin,w) - #w = min(r, toolr) - wmax=max(wmax,w) - if reflex : #just after a reflex corner - reflex = False - if w<lastw : #need to adjust it - draw_point((x1,y1),(n0[0][0]+n0[1][0]*w,n0[0][1]+n0[1][1]*w),w, (lastw-w)/2) - save_point((n0[0][0]+n0[1][0]*w,n0[0][1]+n0[1][1]*w),w,i,j,iimin,jjmin) - if n1[2] == True : # We're at a corner - if n1[3]>0 : #acute - save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin) - draw_point((x1,y1),(x1,y1),0,0) - save_point((x1,y1),0,i,j,iimin,jjmin) - elif n1[3]<0 : #reflex - if w>lastw : - draw_point((x1,y1),(x1+nx*lastw,y1+ny*lastw),w, (w-lastw)/2) - wmax=max(wmax,w) - save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin) - elif b>0 and n2[3]>0 and not self.options.engraving_draw_calculation_paths : #acute corner coming up - if jjmin==j and iimin==i+2 : break - draw_point((x1,y1),(x1+nx*w,y1+ny*w),w, bitlen) - save_point((x1+nx*w,y1+ny*w),w,i,j,iimin,jjmin) - - #LT end of for each bit of this line - if n1[2] == True and n1[3]<0 : #reflex angle - reflex=True - lastw = w #remember this w - #LT next i - cspm+=[cspm[0]] - print_("cspm",cspm) - wl+=[wl[0]] - print_("wl",wl) - #Note: Original csp_points was a list, each element - #being 4 points, with the first being the same as the - #last of the previous set. - #Each point is a list of [cx,cy,r,w] - #I have flattened it to a flat list of points. - - 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(wl[i]), inkex.addNS('ry','sodipodi'): str(wl[i]), inkex.addNS('type','sodipodi'): 'arc'}) - cspe += [cspm] - wluu = [] #width list in user units: mm/inches - for w in wl : - wluu+=[ w / orientation_scale ] - print_("wl in pixels",wl) - print_("wl in user units",wluu) - #LT previously, we was in pixels so gave wrong depth - we += [wluu] - #LT6b For each subpath - ends here - #LT5 if it is a path - ends here - #print_("cspe",cspe) - #print_("we",we) - #LT4 for each selected object in this layer - ends here - - if cspe!=[]: - curve = self.parse_curve(cspe, layer, we, toolshape) #convert to lines - self.draw_curve(curve, layer, engraving_group) - gcode += self.generate_gcode(curve, layer, self.options.Zsurface) - - #LT3 for layers loop ends here - if gcode!='' : - self.header+="(Tool diameter should be at least "+str(2*wmax/orientation_scale)+unit+ ")\n" - self.header+="(Depth, as a function of radius w, must be "+ self.tools[layer][0]['shape']+ ")\n" - self.header+="(Rapid feeds use safe Z="+ str(self.options.Zsafe) + unit + ")\n" - self.header+="(Material surface at Z="+ str(self.options.Zsurface) + unit + ")\n" - self.export_gcode(gcode) - else : self.error(_("No need to engrave sharp angles."),"warning") - - -################################################################################ -### -### Orientation -### -################################################################################ - def orientation(self, layer=None) : - - if layer == None : - layer = self.current_layer if self.current_layer is not None else self.document.getroot() - - transform = self.get_transforms(layer) - if transform != [] : - transform = self.reverse_transform(transform) - transform = simpletransform.formatTransform(transform) - - if self.options.orientation_points_count == "graffiti" : - print_(self.graffiti_reference_points) - print_("Inserting graffiti points") - if layer in self.graffiti_reference_points: graffiti_reference_points_count = len(self.graffiti_reference_points[layer]) - else: graffiti_reference_points_count = 0 - axis = ["X","Y","Z","A"][graffiti_reference_points_count%4] - attr = {'gcodetools': "Gcodetools graffiti reference point"} - if transform != [] : - attr["transform"] = transform - g = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), attr) - inkex.etree.SubElement( g, inkex.addNS('path','svg'), - { - 'style': "stroke:none;fill:#00ff00;", - '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' % (graffiti_reference_points_count*100, 0), - 'gcodetools': "Gcodetools graffiti reference point arrow" - }) - - draw_text(axis,graffiti_reference_points_count*100+10,-10, group = g, gcodetools_tag = "Gcodetools graffiti reference point text") - - elif self.options.orientation_points_count == "in-out reference point" : - draw_pointer(group = self.current_layer, x = self.view_center, figure="arrow", pointer_type = "In-out reference point", text = "In-out point") - - else : - print_("Inserting orientation points") - - 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") - - attr = {"gcodetools":"Gcodetools orientation group"} - if transform != [] : - attr["transform"] = transform - - orientation_group = inkex.etree.SubElement(layer, inkex.addNS('g','svg'), attr) - doc_height = self.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.]] - elif self.options.unit == "G20 (All units in inches)" : - points = [[0.,0.,self.options.Zsurface],[5.,0.,self.options.Zdepth],[0.,5.,0.]] - if self.options.orientation_points_count == "2" : - points = points[:2] - for i in points : - 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' % (i[0], -i[1]+doc_height), - 'gcodetools': "Gcodetools orientation point arrow" - }) - - draw_text("(%s; %s; %s)" % (i[0],i[1],i[2]), (i[0]+10), (-i[1]-10+doc_height), group = g, gcodetools_tag = "Gcodetools orientation point text") - - -################################################################################ -### -### 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 (zero 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", - } - elif self.options.tools_library_type == "graffiti": - tool = { - "name": "Graffiti", - "id": "Graffiti 0001", - "diameter":10, - "penetration feed":100, - "feed":400, - "gcode before path":"""M03 S1(Turn spray on)\n """, - "gcode after path":"M05 (Turn spray off)\n ", - "tool change gcode":"(Add G00 here to change sprayer if needed)\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 definition"}) - 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"}) - draw_text(key, 0, y, group = g, gcodetools_tag = "Gcodetools tool definition field name", font_size = 10 if key!='name' else 20) - param = tool[key] - if type(param)==str and re.match("^\s*$",param) : param = "(None)" - draw_text(param, 150, y, group = g, gcodetools_tag = "Gcodetools tool definition field value", font_size = 10 if key!='name' else 20) - v = str(param).split("\n") - y += 15*len(v) if key!='name' else 20*len(v) - - 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.set_markers() - - 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] ] - #draw_csp(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**2: - 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 - if self.options.lathe_create_fine_cut_using == "Move path" : - subpath = [ [ [i2[0],i2[1]+r] for i2 in i1] for i1 in subpath] - else : - # 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] ) - #draw_csp(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) - -################################################################################ -### -### Lathe modify path -### Modifies path to fit current cutter. As for now straight rect cutter. -### -################################################################################ - - def lathe_modify_path(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 self.layers : - if layer in paths : - width = self.options.lathe_rectangular_cutter_width - #self.set_tool(layer) - for path in paths[layer]: - csp = self.transform_csp(cubicsuperpath.parsePath(path.get("d")),layer) - new_csp = [] - for subpath in csp: - orientation = subpath[-1][1][0]>subpath[0][1][0] - last_n = None - last_o = 0 - new_subpath = [] - - # Split segment at x' and y' == 0 - for sp1, sp2 in zip(subpath[:],subpath[1:]): - ax,ay,bx,by,cx,cy,dx,dy = csp_parameterize(sp1,sp2) - roots = cubic_solver_real(0, 3*ax, 2*bx, cx) - roots += cubic_solver_real(0, 3*ay, 2*by, cy) - new_subpath = csp_concat_subpaths(new_subpath, csp_seg_split(sp1,sp2,roots)) - subpath = new_subpath - new_subpath = [] - first_seg = True - for sp1, sp2 in zip(subpath[:],subpath[1:]): - n = csp_normalized_normal(sp1,sp2,0) - a = math.atan2(n[0],n[1]) - if a == 0 or a == math.pi : - n = csp_normalized_normal(sp1,sp2,1) - a = math.atan2(n[0],n[1]) - if a!=0 and a!=math.pi: - o = 0 if 0<a<=math.pi/2 or -math.pi<a<-math.pi/2 else 1 - if not orientation: o = 1-o - - # Add first horisontal straight line if needed - if not first_seg and new_subpath==[] : new_subpath = [ [[subpath[0][i][0] - width*o ,subpath[0][i][1]] for i in range(3)] ] - - new_subpath = csp_concat_subpaths( - new_subpath, - [ - [[sp1[i][0] - width*o ,sp1[i][1]] for i in range(3)], - [[sp2[i][0] - width*o ,sp2[i][1]] for i in range(3)] - ] - ) - first_seg = False - - # Add last horisontal straigth line if needed - if a==0 or a==math.pi : - new_subpath += [ [[subpath[-1][i][0] - width*o ,subpath[-1][i][1]] for i in range(3)] ] - - - new_csp += [new_subpath] - self.draw_csp(new_csp,layer) -# -# o = (1 if cross(n, [0,1])>0 else -1)*orientation -# new_subpath += [ [sp1[i][0] - width*o,sp1[i][1]] for i in range(3) ] -# n = csp_normalized_normal(sp1,sp2,1) -# o = (1 if cross(n, [0,1])>0 else -1)*orientation -# new_subpath += [ [sp2[i][0] - width*o,sp2[i][1]] for i in range(3) ] - - -################################################################################ -### -### Update function -### -### Gets file containing version information from the web and compaares it with. -### current version. -################################################################################ - - 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") - - - -################################################################################ -### Graffiti function generates Gcode for graffiti drawer -################################################################################ - def graffiti(self) : - # Get reference points. - - def get_gcode_coordinates(point,layer): - gcode = '' - pos = [] - for ref_point in self.graffiti_reference_points[layer] : - c = math.sqrt((point[0]-ref_point[0][0])**2 + (point[1]-ref_point[0][1])**2) - gcode += " %s %f"%(ref_point[1], c) - pos += [c] - return pos, gcode - - - def graffiti_preview_draw_point(x1,y1,color,radius=.5): - self.graffiti_preview = self.graffiti_preview - r,g,b,a_ = color - for x in range(int(x1-1-math.ceil(radius)), int(x1+1+math.ceil(radius)+1)): - for y in range(int(y1-1-math.ceil(radius)), int(y1+1+math.ceil(radius)+1)): - if x>=0 and y>=0 and y<len(self.graffiti_preview) and x*4<len(self.graffiti_preview[0]) : - d = math.sqrt( (x1-x)**2 +(y1-y)**2 ) - a = float(a_)*( max(0,(1-(d-radius))) if d>radius else 1 )/256 - self.graffiti_preview[y][x*4] = int(r*a + (1-a)*self.graffiti_preview[y][x*4]) - self.graffiti_preview[y][x*4+1] = int(g*a + (1-a)*self.graffiti_preview[y][x*4+1]) - self.graffiti_preview[y][x*4+2] = int(g*b + (1-a)*self.graffiti_preview[y][x*4+2]) - self.graffiti_preview[y][x*4+3] = min(255,int(self.graffiti_preview[y][x*4+3]+a*256)) - - def graffiti_preview_transform(x,y): - tr = self.graffiti_preview_transform - d = max(tr[2]-tr[0]+2,tr[3]-tr[1]+2) - return [(x-tr[0]+1)*self.options.graffiti_preview_size/d, self.options.graffiti_preview_size - (y-tr[1]+1)*self.options.graffiti_preview_size/d] - - - def draw_graffiti_segment(layer,start,end,feed,color=(0,255,0,40),emmit=1000): - # Emit = dots per second - l = math.sqrt(sum([(start[i]-end[i])**2 for i in range(len(start))])) - time_ = l/feed - c1,c2 = self.graffiti_reference_points[layer][0][0],self.graffiti_reference_points[layer][1][0] - d = math.sqrt( (c1[0]-c2[0])**2 + (c1[1]-c2[1])**2 ) - if d == 0 : raise ValueError, "Error! Reference points should not be the same!" - for i in range(int(time_*emmit+1)) : - t = i/(time_*emmit) - r1,r2 = start[0]*(1-t) + end[0]*t, start[1]*(1-t) + end[1]*t - a = (r1**2-r2**2+d**2)/(2*d) - h = math.sqrt(r1**2 - a**2) - xa = c1[0] + a*(c2[0]-c1[0])/d - ya = c1[1] + a*(c2[1]-c1[1])/d - - x1 = xa + h*(c2[1]-c1[1])/d - x2 = xa - h*(c2[1]-c1[1])/d - y1 = ya - h*(c2[0]-c1[0])/d - y2 = ya + h*(c2[0]-c1[0])/d - - x = x1 if y1<y2 else x2 - y = min(y1,y2) - x,y = graffiti_preview_transform(x,y) - graffiti_preview_draw_point(x,y,color) - - def create_connector(p1,p2,t1,t2): - P1,P2 = P(p1), P(p2) - N1, N2 = P(rotate_ccw(t1)), P(rotate_ccw(t2)) - r = self.options.graffiti_min_radius - C1,C2 = P1+N1*r, P2+N2*r - # Get closest possible centers of arcs, also we define that arcs are both ccw or both not. - dc, N1, N2, m = ( - ( - (((P2-N1*r) - (P1-N2*r)).l2(),-N1,-N2, 1) - if vectors_ccw(t1,t2) else - (((P2+N1*r) - (P1+N2*r)).l2(), N1, N2,-1) - ) - if vectors_ccw((P1-C1).to_list(),t1) == vectors_ccw((P2-C2).to_list(),t2) else - ( - (((P2+N1*r) - (P1-N2*r)).l2(), N1,-N2, 1) - if vectors_ccw(t1,t2) else - (((P2-N1*r) - (P1+N2*r)).l2(),-N1, N2, 1) - ) - ) - dc = math.sqrt(dc) - C1,C2 = P1+N1*r, P2+N2*r - Dc = C2-C1 - - if dc == 0 : - # can be joined by one arc - return csp_from_arc(p1, p2, C1.to_list(), r, t1) - - cos, sin = Dc.x/dc, Dc.y/dc - #draw_csp(self.transform_csp([[ [[C1.x-r*sin,C1.y+r*cos]]*3,[[C2.x-r*sin,C2.y+r*cos]]*3 ]],layer,reverse=True), color = "#00ff00;" ) - #draw_pointer(self.transform(C1.to_list(),layer,reverse=True)) - #draw_pointer(self.transform(C2.to_list(),layer,reverse=True)) - - p1_end = [C1.x-r*sin*m,C1.y+r*cos*m] - p2_st = [C2.x-r*sin*m,C2.y+r*cos*m] - if point_to_point_d2(p1,p1_end)<0.0001 and point_to_point_d2(p2,p2_st)<0.0001 : - return ([[p1,p1,p1],[p2,p2,p2]]) - - arc1 = csp_from_arc(p1, p1_end, C1.to_list(), r, t1) - arc2 = csp_from_arc(p2_st, p2, C2.to_list(), r, [cos,sin]) - return csp_concat_subpaths(arc1,arc2) - - if not self.check_dir() : return - 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.tool = [] - gcode = """(Header) -(Generated by gcodetools from Inkscape.) -(Using graffiti extension.) -(Header end.)""" - - minx,miny,maxx,maxy = float("inf"),float("inf"),float("-inf"),float("-inf") - - # Get all reference points and path's bounds to make preview - - for layer in self.layers : - if layer in paths : - # Set reference points - if layer not in self.graffiti_reference_points: - reference_points = None - for i in range(self.layers.index(layer),-1,-1): - if self.layers[i] in self.graffiti_reference_points : - reference_points = self.graffiti_reference_points[self.layers[i]] - self.graffiti_reference_points[layer] = self.graffiti_reference_points[self.layers[i]] - break - if reference_points == None : - self.error('There are no graffiti reference points for layer %s'%layer,"error") - - # Transform reference points - for i in range(len(self.graffiti_reference_points[layer])): - self.graffiti_reference_points[layer][i][0] = self.transform(self.graffiti_reference_points[layer][i][0], layer) - point = self.graffiti_reference_points[layer][i] - gcode += "(Reference point %f;%f for %s axis)\n"%(point[0][0],point[0][1],point[1]) - - if self.options.graffiti_create_preview : - for point in self.graffiti_reference_points[layer]: - minx,miny,maxx,maxy = min(minx,point[0][0]), min(miny,point[0][1]), max(maxx,point[0][0]), max(maxy,point[0][1]) - for path in paths[layer]: - csp = cubicsuperpath.parsePath(path.get("d")) - csp = self.apply_transforms(path, csp) - csp = self.transform_csp(csp, layer) - bounds = csp_simple_bound(csp) - minx,miny,maxx,maxy = min(minx,bounds[0]), min(miny,bounds[1]), max(maxx,bounds[2]), max(maxy,bounds[3]) - - if self.options.graffiti_create_preview : - self.graffiti_preview = list([ [255]*(4*self.options.graffiti_preview_size) for i in range(self.options.graffiti_preview_size)]) - self.graffiti_preview_transform = [minx,miny,maxx,maxy] - - for layer in self.layers : - if layer in paths : - - r = re.match("\s*\(\s*([0-9\-,.]+)\s*;\s*([0-9\-,.]+)\s*\)\s*",self.options.graffiti_start_pos) - if r : - start_point = [float(r.group(1)),float(r.group(2))] - else : - start_point = [0.,0.] - last_sp1 = [[start_point[0],start_point[1]-10] for i in range(3)] - last_sp2 = [start_point for i in range(3)] - - self.set_tool(layer) - self.tool = self.tools[layer][0] - # Change tool every layer. (Probably layer = color so it'll be - # better to change it even if the tool has not been changed) - gcode += ( "(Change tool to %s)\n" % re.sub("\"'\(\)\\\\"," ",self.tool["name"]) ) + self.tool["tool change gcode"] + "\n" - - subpaths = [] - for path in paths[layer]: - # Rebuild the paths to polyline. - csp = cubicsuperpath.parsePath(path.get("d")) - csp = self.apply_transforms(path, csp) - csp = self.transform_csp(csp, layer) - subpaths += csp - polylines = [] - while len(subpaths)>0: - i = min( [( point_to_point_d2(last_sp2[1],subpaths[i][0][1]),i) for i in range(len(subpaths))] )[1] - subpath = subpaths[i][:] - del subpaths[i] - polylines += [ - ['connector', create_connector( - last_sp2[1], - subpath[0][1], - csp_normalized_slope(last_sp1,last_sp2,1.), - csp_normalized_slope(subpath[0],subpath[1],0.), - )] - ] - polyline = [] - spl = None - - # remove zerro length segments - i = 0 - while i<len(subpath)-1: - if (cspseglength(subpath[i],subpath[i+1])<0.00000001 ) : - subpath[i][2] = subpath[i+1][2] - del subpath[i+1] - else : - i += 1 - - for sp1, sp2 in zip(subpath,subpath[1:]) : - if spl != None and abs(cross( csp_normalized_slope(spl,sp1,1.),csp_normalized_slope(sp1,sp2,0.) )) > 0.1 : # TODO add coefficient into inx - # We've got sharp angle at sp1. - polyline += [sp1] - polylines += [['draw',polyline[:]]] - polylines += [ - ['connector', create_connector( - sp1[1], - sp1[1], - csp_normalized_slope(spl,sp1,1.), - csp_normalized_slope(sp1,sp2,0.), - )] - ] - polyline = [] - # max_segment_length - polyline += [ sp1 ] - print_(polyline) - print_(sp1) - - spl = sp1 - polyline += [ sp2 ] - polylines += [ ['draw',polyline[:]] ] - - last_sp1, last_sp2 = sp1,sp2 - - - # Add return to start_point - if polylines == [] : continue - polylines += [ ["connect1", [ [polylines[-1][1][-1][1] for i in range(3)],[start_point for i in range(3)] ] ] ] - - # Make polilynes from polylines. They are still csp. - for i in range(len(polylines)) : - polyline = [] - l = 0 - print_("polylines",polylines) - print_(polylines[i]) - for sp1,sp2 in zip(polylines[i][1],polylines[i][1][1:]) : - print_(sp1,sp2) - l = cspseglength(sp1,sp2) - if l>0.00000001 : - polyline += [sp1[1]] - parts = int(math.ceil(l/self.options.graffiti_max_seg_length)) - for j in range(1,parts): - polyline += [csp_at_length(sp1,sp2,float(j)/parts) ] - if l>0.00000001 : - polyline += [sp2[1]] - print_(i) - polylines[i][1] = polyline - - t = 0 - last_state = None - for polyline_ in polylines: - polyline = polyline_[1] - # Draw linearization - if self.options.graffiti_create_linearization_preview : - t += 1 - csp = [ [polyline[i],polyline[i],polyline[i]] for i in range(len(polyline))] - draw_csp(self.transform_csp([csp],layer,reverse=True), color = "#00cc00;" if polyline_[0]=='draw' else "#ff5555;") - - - # Export polyline to gcode - # we are making trnsform from XYZA coordinates to R1...Rn - # where R1...Rn are radius vectors from grafiti reference points - # to current (x,y) point. Also we need to assign custom feed rate - # for each segment. And we'll use only G01 gcode. - last_real_pos, g = get_gcode_coordinates(polyline[0],layer) - last_pos = polyline[0] - if polyline_[0] == "draw" and last_state!="draw": - gcode += self.tool['gcode before path']+"\n" - for point in polyline : - real_pos, g = get_gcode_coordinates(point,layer) - real_l = sum([(real_pos[i]-last_real_pos[i])**2 for i in range(len(last_real_pos))]) - l = (last_pos[0]-point[0])**2 + (last_pos[1]-point[1])**2 - if l!=0: - feed = self.tool['feed']*math.sqrt(real_l/l) - gcode += "G01 " + g + " F %f\n"%feed - if self.options.graffiti_create_preview : - draw_graffiti_segment(layer,real_pos,last_real_pos,feed,color=(0,0,255,200) if polyline_[0] == "draw" else (255,0,0,200),emmit=self.options.graffiti_preview_emmit) - last_real_pos = real_pos - last_pos = point[:] - if polyline_[0] == "draw" and last_state!="draw" : - gcode += self.tool['gcode after path']+"\n" - last_state = polyline_[0] - self.export_gcode(gcode, no_headers=True) - if self.options.graffiti_create_preview : - try : - # Draw reference points - for layer in self.graffiti_reference_points: - for point in self.graffiti_reference_points[layer] : - x, y = graffiti_preview_transform(point[0][0],point[0][1]) - graffiti_preview_draw_point(x,y,(0,255,0,255),radius=5) - - import png - writer = png.Writer(width=self.options.graffiti_preview_size, height=self.options.graffiti_preview_size, size=None, greyscale=False, alpha=True, bitdepth=8, palette=None, transparent=None, background=None, gamma=None, compression=None, interlace=False, bytes_per_sample=None, planes=None, colormap=None, maxval=None, chunk_limit=1048576) - f = open(self.options.directory+self.options.file+".png", 'wb') - writer.write(f,self.graffiti_preview) - f.close() - - except : - self.error("Png module have not been found!","warning") - - - -################################################################################ -### -### Effect -### -### Main function of Gcodetools class -### -################################################################################ - def effect(self) : - start_time = time.time() - 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 == '"about"' : - self.help() - return - - elif self.options.active_tab == '"test"' : - self.test() - - elif self.options.active_tab not in ['"dxfpoints"','"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"orientation"', '"tools_library"', '"lathe"', '"offset"', '"arrangement"', '"update"', '"graffiti"', '"lathe_modify_path"', '"plasma-prepare-path"']: - self.error(_("Select one of the action tabs - Path to Gcode, Area, Engraving, DXF points, Orientation, Offset, Lathe or Tools library.\n Current active tab id is %s" % self.options.active_tab),"error") - else: - # Get all Gcodetools data from the scene. - self.get_info() - if self.options.active_tab in ['"dxfpoints"','"path-to-gcode"', '"area_fill"', '"area"', '"area_artefacts"', '"engraving"', '"lathe"', '"graffiti"', '"plasma-prepare-path"']: - 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_fill"': - self.area_fill() - 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 == '"graffiti"': - self.graffiti() - 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 == '"lathe_modify_path"': - self.lathe_modify_path() - 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_ : - draw_csp([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() - - elif self.options.active_tab == '"plasma-prepare-path"': - self.plasma_prepare_path() - - - print_("------------------------------------------") - print_("Done in %f seconds"%(time.time()-start_time)) - print_("End at %s."%time.strftime("%d.%m.%Y %H:%M:%S")) - - -# -gcodetools = Gcodetools() -gcodetools.affect() - diff --git a/share/extensions/gcodetools_about.inx b/share/extensions/gcodetools_about.inx deleted file mode 100644 index 4a1579181..000000000 --- a/share/extensions/gcodetools_about.inx +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>About</_name> - <id>ru.cnc-club.filter.gcodetools_about_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='about' _gui-text='About'> - <_param name="help" type="description" xml:space="preserve">Gcodetools was developed to make simple Gcode from Inkscape's paths. Gcode is a special format which is used in most of CNC machines. So Gcodetools allows you to use Inkscape as CAM program. - -It can be used with a lot of machine types: - Mills - Lathes - Laser and Plasma cutters and engravers - Mill engravers - Plotters - etc. - -To get more info visit developers page at http://www.cnc-club.ru/gcodetools</_param> - </page> - - <page name='help' _gui-text='Help'> - <_param name="fullhelp" type="description" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 8dbcb1e1f..000000000 --- a/share/extensions/gcodetools_area.inx +++ /dev/null @@ -1,134 +0,0 @@ -<?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_fill_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="area-tool-overlap" type="float" min="0" max="1" _gui-text="Area tool overlap (0..0.9):">0</param> - - <_param name="help" type="description" xml:space="preserve"> -"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_fill' _gui-text='Fill area'> - <param name="area-fill-angle" type="float" min="-360" max="360" _gui-text="Area fill angle">0</param> - <param name="area-fill-shift" type="float" min="-1" max="1" _gui-text="Area fill shift">0</param> - <param name="area-fill-method" type="float" min="-1" max="1" _gui-text="Area fill shift">0</param> - <param name="area-fill-method" _gui-text="Filling method" type="optiongroup"> - <_option value="zig-zag">Zig zag</_option> - <_option value="spiral">Spiral</_option> - </param> - </page> - - <page name='area_artefacts' _gui-text='Area artifacts'> - <param name="area-find-artefacts-diameter" type="float" min="0.01" max="1000" _gui-text="Artifact 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" xml:space="preserve"> -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="path-to-gcode-order" _gui-text="Cutting order:" type="optiongroup" appearance="minimal"> - <_option value="subpath by subpath">Subpath by subpath</_option> - <_option value="path by path">Path by path</_option> - <_option value="pass by pass">Pass by Pass</_option> - </param> - - <param name="path-to-gcode-depth-function" type="string" _gui-text="Depth function:">d</param> - <param name="path-to-gcode-sort-paths" type="boolean" _gui-text="Sort paths to reduce rapid distance">True</param> - - <_param name="help" type="description" xml:space="preserve"> -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 its approximation exceeds biarc interpolation tolerance. -For depth function c=color intensity from 0.0 (white) to 1.0 (black), d is the depth defined by orientation points, s - surface defined by orientation points. -</_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> - <param name="comment-gcode" type="string" _gui-text="Comment Gcode:"></param> - <param name="comment-gcode-from-properties" type="boolean" _gui-text="Get additional comments from object's properties">False</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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 05cc97b1d..000000000 --- a/share/extensions/gcodetools_check_for_updates.inx +++ /dev/null @@ -1,43 +0,0 @@ -<?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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 06d655624..000000000 --- a/share/extensions/gcodetools_dxf_points.inx +++ /dev/null @@ -1,80 +0,0 @@ -<?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" xml:space="preserve"> - -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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 6dd1a3c73..000000000 --- a/share/extensions/gcodetools_engraving.inx +++ /dev/null @@ -1,92 +0,0 @@ -<?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="150" max="180" _gui-text="Smooth convex corners between this value and 180 degrees:">175</param> - <param name="engraving-max-dist" type="float" precision="5" min="0" max="1000" _gui-text="Maximum distance for engraving (mm/inch):">10</param> - <param name="engraving-newton-iterations" type="int" min="2" max="10" _gui-text="Accuracy factor (2 low to 10 high):">4</param> - <param name="engraving-draw-calculation-paths" type="boolean" _gui-text="Draw additional graphics to see engraving path">false</param> - - <_param name="help" type="description" xml:space="preserve"> -This function creates path to engrave letters or any shape with sharp angles. -Cutter's depth as a function of radius is defined by the tool. -Depth may be any Python expression. For instance: - -cone....(45 degrees)......................: w -cone....(height/diameter=10/3)..: 10*w/3 -sphere..(radius r)...........................: math.sqrt(max(0,r**2-w**2)) -ellipse.(minor axis r, major 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> - <param name="comment-gcode" type="string" _gui-text="Comment Gcode:"></param> - <param name="comment-gcode-from-properties" type="boolean" _gui-text="Get additional comments from object's properties">False</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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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_graffiti.inx b/share/extensions/gcodetools_graffiti.inx deleted file mode 100644 index c2ea161d9..000000000 --- a/share/extensions/gcodetools_graffiti.inx +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Graffiti</_name> - <id>ru.cnc-club.filter.gcodetools_graffiti_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='graffiti' _gui-text='Graffiti'> - <param name="graffiti-max-seg-length" type="float" precision="5" min="0" max="1000" _gui-text="Maximum segment length:">10</param> - <param name="graffiti-min-radius" type="float" precision="5" min="0" max="1000" _gui-text="Minimal connector radius:">10</param> - <param name="graffiti-start-pos" type="string" _gui-text="Start position (x;y):">(0.0;0.0)</param> - <param name="graffiti-create-preview" type="boolean" _gui-text="Create preview">true</param> - <param name="graffiti-create-linearization-preview" type="boolean" _gui-text="Create linearization preview">true</param> - <param name="graffiti-preview-size" type="int" min="100" max="10000" _gui-text="Preview's size (px):">800</param> - <param name="graffiti-preview-emmit" type="int" min="100" max="10000" _gui-text="Preview's paint emmit (pts/s):">1000</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> -<_option value="graffiti">graffiti points</_option> -<_option value="in-out reference point">in-out reference point</_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" xml:space="preserve"> -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> - <param name="comment-gcode" type="string" _gui-text="Comment Gcode:"></param> - <param name="comment-gcode-from-properties" type="boolean" _gui-text="Get additional comments from object's properties">False</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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 4bb9888a6..000000000 --- a/share/extensions/gcodetools_lathe.inx +++ /dev/null @@ -1,114 +0,0 @@ -<?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_lathe_modify_path_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='lathe_modify_path' _gui-text='Lathe modify path'> - <_param name="help" type="description" xml:space="preserve"> - This function modifies path so it will be possible to be cut it with a rectangular cutter. - </_param> - <param name="lathe-rectangular-cutter-width" type="float" precision="5" min="0" max="1000" _gui-text="Lathe width:">4</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="path-to-gcode-order" _gui-text="Cutting order:" type="optiongroup" appearance="minimal"> - <_option value="subpath by subpath">Subpath by subpath</_option> - <_option value="path by path">Path by path</_option> - <_option value="pass by pass">Pass by Pass</_option> - </param> - - <param name="path-to-gcode-depth-function" type="string" _gui-text="Depth function:">d</param> - <param name="path-to-gcode-sort-paths" type="boolean" _gui-text="Sort paths to reduce rapid distance">True</param> - - <_param name="help" type="description" xml:space="preserve"> -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 its approximation exceeds biarc interpolation tolerance. -For depth function c=color intensity from 0.0 (white) to 1.0 (black), d is the depth defined by orientation points, s - surface defined by orientation points. -</_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> - <param name="comment-gcode" type="string" _gui-text="Comment Gcode:"></param> - <param name="comment-gcode-from-properties" type="boolean" _gui-text="Get additional comments from object's properties">False</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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 9f07ff219..000000000 --- a/share/extensions/gcodetools_orientation_points.inx +++ /dev/null @@ -1,73 +0,0 @@ -<?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> -<_option value="graffiti">graffiti points</_option> -<_option value="in-out reference point">in-out reference point</_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" xml:space="preserve"> -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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 6862a40a4..000000000 --- a/share/extensions/gcodetools_path_to_gcode.inx +++ /dev/null @@ -1,94 +0,0 @@ -<?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="path-to-gcode-order" _gui-text="Cutting order:" type="optiongroup" appearance="minimal"> - <_option value="subpath by subpath">Subpath by subpath</_option> - <_option value="path by path">Path by path</_option> - <_option value="pass by pass">Pass by Pass</_option> - </param> - - <param name="path-to-gcode-depth-function" type="string" _gui-text="Depth function:">d</param> - <param name="path-to-gcode-sort-paths" type="boolean" _gui-text="Sort paths to reduce rapid distance">True</param> - - <_param name="help" type="description" xml:space="preserve"> -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 its approximation exceeds biarc interpolation tolerance. -For depth function c=color intensity from 0.0 (white) to 1.0 (black), d is the depth defined by orientation points, s - surface defined by orientation points. -</_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> - <param name="comment-gcode" type="string" _gui-text="Comment Gcode:"></param> - <param name="comment-gcode-from-properties" type="boolean" _gui-text="Get additional comments from object's properties">False</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 msgctxt="GCode postprocessor" 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> - <_item value='regex("G01 Z([0-9\.\-]+).*\(Penetrate\)", lambda match: "G00 Z%f (Fast pre-penetrate)\n%s" %(float(match.group(1))+5, match.group(0)));'>Fast pre-penetrate</_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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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_prepare_path_for_plasma.inx b/share/extensions/gcodetools_prepare_path_for_plasma.inx deleted file mode 100644 index c6d77e7db..000000000 --- a/share/extensions/gcodetools_prepare_path_for_plasma.inx +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Prepare path for plasma</_name> - <id>ru.cnc-club.filter.gcodetools_plasma-prepare-path_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='plasma-prepare-path' _gui-text='Prepare path for plasma or laser cutters'> - <param name='in-out-path' type="boolean" _gui-text="Create in-out paths" >True</param> - <param name='in-out-path-len' type="float" precision="5" min="0" max="1000000" _gui-text='In-out path length:'>10</param> - <param name='in-out-path-point-max-dist' type="float" precision="5" min="0" max="1000000" _gui-text='In-out path max distance to reference point:'>10</param> - <param name="in-out-path-type" _gui-text="In-out path type:" type="optiongroup" appearance="minimal"> - <_option value="Round">Round</_option> - <_option value="Perpendicular">Perpendicular</_option> - <_option value="Tangent">Tangent</_option> - </param> - <param name='in-out-path-radius' type="float" precision="5" min="0" max="1000000" _gui-text='In-out path radius for round path:'>10</param> - <param name='in-out-path-replace-original-path' type="boolean" _gui-text="Replace original path" >False</param> - <param name='in-out-path-do-not-add-reference-point' type="boolean" _gui-text="Do not add in-out reference points" >False</param> - - <_param name="help" type="description">-------------------------------------------------</_param> - <param name='plasma-prepare-corners' type="boolean" _gui-text="Prepare corners" >True</param> - <param name='plasma-prepare-corners-distance' type="float" precision="5" min="0" max="1000000" _gui-text='Stepout distance for corners:'>10</param> - <param name='plasma-prepare-corners-tolerance' type="float" precision="5" min="0" max="180" _gui-text='Maximum angle for corner (0-180 deg):'>140</param> - - - - </page> - - <page name='help' _gui-text='Help'> - <_param name="fullhelp" type="description" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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 deleted file mode 100644 index 7841c3130..000000000 --- a/share/extensions/gcodetools_tools_library.inx +++ /dev/null @@ -1,64 +0,0 @@ -<?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='graffiti'>graffiti</_option> - - -<_option value='check'>Just check tools</_option> - - </param> - - <_param name="help" type="description" xml:space="preserve"> -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" xml:space="preserve"> -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, Chris Lusby Taylor. - -Gcodetools ver. 1.7 -</_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/generate_voronoi.inx b/share/extensions/generate_voronoi.inx deleted file mode 100644 index 0c1e827aa..000000000 --- a/share/extensions/generate_voronoi.inx +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Voronoi Pattern</_name> - <id>com.vaxxine.generate.voronoi</id> - <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="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> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">generate_voronoi.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/generate_voronoi.py b/share/extensions/generate_voronoi.py deleted file mode 100755 index 4cf541aa2..000000000 --- a/share/extensions/generate_voronoi.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -""" -Copyright (C) 2010 Alvin Penner, penner@vaxxine.com - -- Voronoi Diagram algorithm and C code by Steven Fortune, 1987, http://ect.bell-labs.com/who/sjf/ -- Python translation to file voronoi.py by Bill Simons, 2005, http://www.oxfish.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -# standard library -import random -# local library -import inkex -import simplestyle, simpletransform -import voronoi - -try: - from subprocess import Popen, PIPE -except: - inkex.errormsg(_("Failed to import the subprocess module. Please report this as a bug at: https://bugs.launchpad.net/inkscape.")) - inkex.errormsg(_("Python version is: ") + str(inkex.sys.version_info)) - exit() - -def clip_line(x1, y1, x2, y2, w, h): - if x1 < 0 and x2 < 0: - return [0, 0, 0, 0] - if x1 > w and x2 > w: - return [0, 0, 0, 0] - if x1 < 0: - y1 = (y1*x2 - y2*x1)/(x2 - x1) - x1 = 0 - if x2 < 0: - y2 = (y1*x2 - y2*x1)/(x2 - x1) - x2 = 0 - if x1 > w: - y1 = y1 + (w - x1)*(y2 - y1)/(x2 - x1) - x1 = w - if x2 > w: - y2 = y1 + (w - x1)*(y2 - y1)/(x2 - x1) - x2 = w - if y1 < 0 and y2 < 0: - return [0, 0, 0, 0] - if y1 > h and y2 > h: - return [0, 0, 0, 0] - if x1 == x2 and y1 == y2: - return [0, 0, 0, 0] - if y1 < 0: - x1 = (x1*y2 - x2*y1)/(y2 - y1) - y1 = 0 - if y2 < 0: - x2 = (x1*y2 - x2*y1)/(y2 - y1) - y2 = 0 - if y1 > h: - x1 = x1 + (h - y1)*(x2 - x1)/(y2 - y1) - y1 = h - if y2 > h: - x2 = x1 + (h - y1)*(x2 - x1)/(y2 - y1) - y2 = h - return [x1, y1, x2, y2] - -class Pattern(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--size", - action="store", type="int", - dest="size", default=10, - help="Average size of cell (px)") - self.OptionParser.add_option("--border", - 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: - inkex.errormsg(_("Please select an object")) - exit() - scale = self.unittouu('1px') # convert to document units - self.options.size *= scale - self.options.border *= scale - q = {'x':0,'y':0,'width':0,'height':0} # query the bounding box of ids[0] - for query in q.keys(): - p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query, self.options.ids[0], self.args[-1]), shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - q[query] = scale*float(p.stdout.read()) - mat = simpletransform.composeParents(self.selected[self.options.ids[0]], [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - defs = self.xpathSingle('/svg:svg//svg:defs') - pattern = inkex.etree.SubElement(defs ,inkex.addNS('pattern','svg')) - pattern.set('id', 'Voronoi' + str(random.randint(1, 9999))) - pattern.set('width', str(q['width'])) - pattern.set('height', str(q['height'])) - pattern.set('patternTransform', 'translate(%s,%s)' % (q['x'] - mat[0][2], q['y'] - mat[1][2])) - pattern.set('patternUnits', 'userSpaceOnUse') - - # generate random pattern of points - c = voronoi.Context() - pts = [] - b = float(self.options.border) # width of border - for i in range(int(q['width']*q['height']/self.options.size/self.options.size)): - x = random.random()*q['width'] - y = random.random()*q['height'] - if b > 0: # duplicate border area - pts.append(voronoi.Site(x, y)) - if x < b: - pts.append(voronoi.Site(x + q['width'], y)) - if y < b: - pts.append(voronoi.Site(x + q['width'], y + q['height'])) - if y > q['height'] - b: - pts.append(voronoi.Site(x + q['width'], y - q['height'])) - if x > q['width'] - b: - pts.append(voronoi.Site(x - q['width'], y)) - if y < b: - pts.append(voronoi.Site(x - q['width'], y + q['height'])) - if y > q['height'] - b: - pts.append(voronoi.Site(x - q['width'], y - q['height'])) - if y < b: - pts.append(voronoi.Site(x, y + q['height'])) - if y > q['height'] - b: - pts.append(voronoi.Site(x, y - q['height'])) - elif x > -b and y > -b and x < q['width'] + b and y < q['height'] + b: - pts.append(voronoi.Site(x, y)) # leave border area blank - # dot = inkex.etree.SubElement(pattern, inkex.addNS('rect','svg')) - # dot.set('x', str(x-1)) - # dot.set('y', str(y-1)) - # dot.set('width', '2') - # dot.set('height', '2') - if len(pts) < 3: - inkex.errormsg("Please choose a larger object, or smaller cell size") - exit() - - # plot Voronoi diagram - sl = voronoi.SiteList(pts) - voronoi.voronoi(sl, c) - path = "" - for edge in c.edges: - if edge[1] >= 0 and edge[2] >= 0: # two vertices - [x1, y1, x2, y2] = clip_line(c.vertices[edge[1]][0], c.vertices[edge[1]][1], c.vertices[edge[2]][0], c.vertices[edge[2]][1], q['width'], q['height']) - elif edge[1] >= 0: # only one vertex - if c.lines[edge[0]][1] == 0: # vertical line - xtemp = c.lines[edge[0]][2]/c.lines[edge[0]][0] - if c.vertices[edge[1]][1] > q['height']/2: - ytemp = q['height'] - else: - ytemp = 0 - else: - xtemp = q['width'] - ytemp = (c.lines[edge[0]][2] - q['width']*c.lines[edge[0]][0])/c.lines[edge[0]][1] - [x1, y1, x2, y2] = clip_line(c.vertices[edge[1]][0], c.vertices[edge[1]][1], xtemp, ytemp, q['width'], q['height']) - elif edge[2] >= 0: # only one vertex - if c.lines[edge[0]][1] == 0: # vertical line - xtemp = c.lines[edge[0]][2]/c.lines[edge[0]][0] - if c.vertices[edge[2]][1] > q['height']/2: - ytemp = q['height'] - else: - ytemp = 0 - else: - xtemp = 0 - ytemp = c.lines[edge[0]][2]/c.lines[edge[0]][1] - [x1, y1, x2, y2] = clip_line(xtemp, ytemp, c.vertices[edge[2]][0], c.vertices[edge[2]][1], q['width'], q['height']) - if x1 or x2 or y1 or y2: - path += 'M %.3f,%.3f %.3f,%.3f ' % (x1, y1, x2, y2) - - patternstyle = {'stroke': '#000000', 'stroke-width': str(scale)} - attribs = {'d': path, 'style': simplestyle.formatStyle(patternstyle)} - inkex.etree.SubElement(pattern, inkex.addNS('path', 'svg'), attribs) - - # link selected object to pattern - obj = self.selected[self.options.ids[0]] - style = {} - if obj.attrib.has_key('style'): - style = simplestyle.parseStyle(obj.attrib['style']) - style['fill'] = 'url(#%s)' % pattern.get('id') - obj.attrib['style'] = simplestyle.formatStyle(style) - if obj.tag == inkex.addNS('g', 'svg'): - for node in obj: - style = {} - if node.attrib.has_key('style'): - style = simplestyle.parseStyle(node.attrib['style']) - style['fill'] = 'url(#%s)' % pattern.get('id') - node.attrib['style'] = simplestyle.formatStyle(style) - -if __name__ == '__main__': - e = Pattern() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/genpofiles.sh b/share/extensions/genpofiles.sh deleted file mode 100755 index 5106c525a..000000000 --- a/share/extensions/genpofiles.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -OLDPATH=`pwd` - -cd ../.. -find share/extensions -name "*.inx" | sort | xargs -n 1 printf "[type: gettext/xml] %s\n" -cd ${OLDPATH} diff --git a/share/extensions/gimp_xcf.inx b/share/extensions/gimp_xcf.inx deleted file mode 100644 index 30406b62d..000000000 --- a/share/extensions/gimp_xcf.inx +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>GIMP XCF</_name> - <id>org.ekips.output.gimp_xcf</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <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="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> - <param name="dpi" type="int" min="1" max="3000" _gui-text="File Resolution:">96</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. - * File Resolution: XCF file resolution, in DPI. - -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> - <_filetypename>GIMP XCF maintaining layers (*.xcf)</_filetypename> - <_filetypetooltip>GIMP XCF maintaining layers (*.xcf)</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">gimp_xcf.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/gimp_xcf.py b/share/extensions/gimp_xcf.py deleted file mode 100755 index c8096b1e3..000000000 --- a/share/extensions/gimp_xcf.py +++ /dev/null @@ -1,330 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Aaron Spike, aaron@ekips.org -Copyright (C) 2010-2012 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 -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import os -import re -import shutil -from subprocess import Popen, PIPE -import sys -import tempfile -# local library -import inkex - -# Define extension exceptions -class GimpXCFError(Exception): pass - -class GimpXCFExpectedIOError(GimpXCFError): pass - -class GimpXCFInkscapeNotInstalled(GimpXCFError): - def __init__(self): - inkex.errormsg(_('Inkscape must be installed and set in your path variable.')) - -class GimpXCFGimpNotInstalled(GimpXCFError): - def __init__(self): - inkex.errormsg(_('Gimp must be installed and set in your path variable.')) - -class GimpXCFScriptFuError(GimpXCFError): - def __init__(self): - inkex.errormsg(_('An error occurred while processing the XCF file.')) - - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - 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") - self.OptionParser.add_option("-i", "--dpi", - action="store", type="string", - dest="resolution", default="96", - help="File resolution") - - def output(self): - pass - - def clear_tmp(self): - shutil.rmtree(self.tmp_dir) - - def getDocumentScale(self): - """Returns the ratio between the SVG width and viewBox attributes. - """ - documentscale = 1 # default to 1 - svgwidth = self.getDocumentWidth() - viewboxstr = self.document.getroot().get('viewBox') - if viewboxstr: - param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - p = param.match(svgwidth) - width = 100 # default - viewboxwidth = 100 # default - if p: - width = float(p.string[p.start():p.end()]) - else: - errormsg(_("SVG Width not set correctly! Assuming width = 100")) - - viewboxnumbers = [] - for t in viewboxstr.split(): - try: - viewboxnumbers.append(float(t)) - except ValueError: - pass - if len(viewboxnumbers) == 4: # check for correct number of numbers - viewboxwidth = viewboxnumbers[2] - - documentscale = self.unittouu(str(width / viewboxwidth)) - - return documentscale - - def effect(self): - svg_file = self.args[-1] - ttmp_orig = self.document.getroot() - docname = ttmp_orig.get(inkex.addNS('docname',u'sodipodi')) - if docname is None: docname = self.args[-1] - - doc_scale = self.getDocumentScale() - res_scale = eval(self.options.resolution) / 96.0 - scale = doc_scale * res_scale - - pageHeight = self.uutounit(self.unittouu(self.getDocumentHeight()), "px") - pageWidth = self.uutounit(self.unittouu(self.getDocumentWidth()), "px") - - # Create os temp dir (to store exported pngs and Gimp log file) - self.tmp_dir = tempfile.mkdtemp() - - # Guides - hGuides = [] - vGuides = [] - if self.options.saveGuides: - # Grab all guide tags in the namedview tag - guideXpath = "sodipodi:namedview/sodipodi:guide" - for guideNode in self.document.xpath(guideXpath, namespaces=inkex.NSS): - ori = guideNode.get('orientation') - if ori == '0,1': - # This is a horizontal guide - pos = self.uutounit(float(guideNode.get('position').split(',')[1]), "px") * doc_scale - # 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(int(round((pageHeight - pos) * res_scale)))) - elif ori == '1,0': - # This is a vertical guide - pos = self.uutounit(float(guideNode.get('position').split(',')[0]), "px") * doc_scale - # GIMP doesn't like guides that are outside of the image - if pos > 0 and pos < pageWidth: - vGuides.append(str(int(round(pos * res_scale)))) - - 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 nonexistent - spacingX = gridNode.get('spacingx') - if spacingX == None: - spacingX = 1 - else: - spacingX = self.uutounit(float(spacingX),"px") * scale - spacingY = gridNode.get('spacingy') - if spacingY == None: - spacingY = 1 - else: - spacingY = self.uutounit(float(spacingY),"px") * scale - originX = gridNode.get('originx') - if originX == None: - originX = 0 - else: - originX = self.uutounit(float(originX),"px") * scale - originY = gridNode.get('originy') - if originY == None: - originY = 0 - else: - originY = self.uutounit(float(originY),"px") * doc_scale - offsetY = pageHeight % (self.uutounit(float(spacingY),"px") * doc_scale) - originY = (pageHeight - originY) * res_scale - - gridSpacingFunc = '(gimp-image-grid-set-spacing img %s %s)' % (int(round(float(spacingX))), int(round(float(spacingY)))) - gridOriginFunc = '(gimp-image-grid-set-offset img %s %s)'% (int(round(float(originX))), int(round(float(originY)))) - - # Layers - area = '--export-area-page' - opacity = '--export-background-opacity=' - resolution = '--export-dpi=' + self.options.resolution - - if self.options.layerBackground: - opacity += "1" - else: - opacity += "0" - pngs = [] - names = [] - self.valid = 0 - path = "/svg:svg/*[name()='g' or @style][@id]" - for node in self.document.xpath(path, namespaces=inkex.NSS): - if len(node) > 0: # Get rid of empty layers - self.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 %s" % (id, area, opacity, filename, svg_file, resolution) - - p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) - return_code = p.wait() - f = p.stdout - err = p.stderr - stdin = p.stdin - f.read() - f.close() - err.close() - stdin.close() - - if return_code != 0: - self.clear_tmp() - raise GimpXCFInkscapeNotInstalled - - if os.name == 'nt': - filename = filename.replace("\\", "/") - pngs.append(filename) - names.append(name) - - if (self.valid == 0): - self.clear_tmp() - inkex.errormsg(_('This extension requires at least one non empty layer.')) - else: - filelist = '"%s"' % '" "'.join(pngs) - namelist = '"%s"' % '" "'.join(names) - xcf = os.path.join(self.tmp_dir, "%s.xcf" % docname) - if os.name == 'nt': - xcf = xcf.replace("\\", "/") - script_fu = """ -(tracing 1) -(define - (png-to-layer img png_filename layer_name) - (let* - ( - (png (car (file-png-load RUN-NONINTERACTIVE png_filename png_filename))) - (png_layer (car (gimp-image-get-active-layer png))) - (xcf_layer (car (gimp-layer-new-from-drawable png_layer img))) - ) - (gimp-image-add-layer img xcf_layer -1) - (gimp-drawable-set-name xcf_layer layer_name) - ) -) -(let* - ( - (img (car (gimp-image-new 200 200 RGB))) - ) - (gimp-image-set-resolution img %s %s) - (gimp-image-undo-disable img) - (for-each - (lambda (names) - (png-to-layer img (car names) (cdr names)) - ) - (map cons '(%s) '(%s)) - ) - - (gimp-image-resize-to-layers img) - - (for-each - (lambda (hGuide) - (gimp-image-add-hguide img hGuide) - ) - '(%s) - ) - - (for-each - (lambda (vGuide) - (gimp-image-add-vguide img vGuide) - ) - '(%s) - ) - - %s - %s - - (gimp-image-undo-enable img) - (gimp-file-save RUN-NONINTERACTIVE img (car (gimp-image-get-active-layer img)) "%s" "%s")) -(gimp-quit 0) - """ % (self.options.resolution, self.options.resolution, filelist, namelist, hGList, vGList, gridSpacingFunc, gridOriginFunc, xcf, xcf) - - junk = os.path.join(self.tmp_dir, 'junk_from_gimp.txt') - command = 'gimp -i --batch-interpreter plug-in-script-fu-eval -b - > %s 2>&1' % junk - - p = Popen(command, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) - f = p.stdin - out = p.stdout - err = p.stderr - f.write(script_fu.encode('utf-8')) - return_code = p.wait() - - if p.returncode != 0: - self.clear_tmp() - raise GimpXCFGimpNotInstalled - - f.close() - err.close() - out.close() - # Uncomment these lines to see the output from gimp - #err = open(junk, 'r') - #inkex.debug(err.read()) - #err.close() - - try: - x = open(xcf, 'rb') - except: - self.clear_tmp() - raise GimpXCFScriptFuError - - if os.name == 'nt': - try: - import msvcrt - msvcrt.setmode(1, os.O_BINARY) - except: - pass - try: - sys.stdout.write(x.read()) - finally: - x.close() - self.clear_tmp() - - -if __name__ == '__main__': - e = MyEffect() - e.affect() - diff --git a/share/extensions/grid_cartesian.inx b/share/extensions/grid_cartesian.inx deleted file mode 100644 index f053d80bb..000000000 --- a/share/extensions/grid_cartesian.inx +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Cartesian Grid</_name> - <id>grid.cartesian</id> - <dependency type="executable" location="extensions">grid_cartesian.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="border_th" type="float" min="0" max="1000" _gui-text="Border Thickness (px):">3</param> - <param name="tab" type="notebook"> - <page name="x_tab" _gui-text="X Axis"> - <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> - </page> - <page name="y_tab" _gui-text="Y Axis"> - <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> - </page> - </param> - - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu name="Grids"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">grid_cartesian.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/grid_cartesian.py b/share/extensions/grid_cartesian.py deleted file mode 100755 index e192e8dc2..000000000 --- a/share/extensions/grid_cartesian.py +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Beard john.j.beard@gmail.com - -##This extension allows you to draw a Cartesian grid in Inkscape. -##There is a wide range of options including subdivision, subsubdivions -## and logarithmic scales. Custom line widths are also possible. -##All elements are grouped with similar elements (eg all x-subdivs) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle, sys -from math import * -from simpletransform import computePointInNode - -def draw_SVG_line(x1, y1, x2, y2, width, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' } - line_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -def draw_SVG_rect(x,y,w,h, width, fill, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill':fill} - rect_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)} - inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs ) - -class Grid_Polar(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", default="x_tab") - self.OptionParser.add_option("--x_divs", - action="store", type="int", - dest="x_divs", default=5, - help="Major X Divisions") - self.OptionParser.add_option("--dx", - action="store", type="float", - dest="dx", default=100.0, - help="Major X division Spacing") - self.OptionParser.add_option("--x_subdivs", - action="store", type="int", - dest="x_subdivs", default=2, - help="Subdivisions per Major X division") - self.OptionParser.add_option("--x_log", - action="store", type="inkbool", - dest="x_log", default=False, - help="Logarithmic x subdivisions if true") - self.OptionParser.add_option("--x_subsubdivs", - action="store", type="int", - dest="x_subsubdivs", default=5, - help="Subsubdivisions per Minor X division") - self.OptionParser.add_option("--x_half_freq", - action="store", type="int", - dest="x_half_freq", default=4, - help="Halve Subsubdiv. Frequency after 'n' Subdivs. (log only)") - self.OptionParser.add_option("--x_divs_th", - action="store", type="float", - dest="x_divs_th", default=2, - help="Major X Division Line thickness") - self.OptionParser.add_option("--x_subdivs_th", - action="store", type="float", - dest="x_subdivs_th", default=1, - help="Minor X Division Line thickness") - self.OptionParser.add_option("--x_subsubdivs_th", - action="store", type="float", - dest="x_subsubdivs_th", default=1, - help="Subminor X Division Line thickness") - self.OptionParser.add_option("--y_divs", - action="store", type="int", - dest="y_divs", default=6, - help="Major Y Divisions") - self.OptionParser.add_option("--dy", - action="store", type="float", - dest="dy", default=100.0, - help="Major Gridline Increment") - self.OptionParser.add_option("--y_subdivs", - action="store", type="int", - dest="y_subdivs", default=2, - help="Minor Divisions per Major Y division") - self.OptionParser.add_option("--y_log", - action="store", type="inkbool", - dest="y_log", default=False, - help="Logarithmic y subdivisions if true") - self.OptionParser.add_option("--y_subsubdivs", - action="store", type="int", - dest="y_subsubdivs", default=5, - help="Subsubdivisions per Minor Y division") - self.OptionParser.add_option("--y_half_freq", - action="store", type="int", - dest="y_half_freq", default=4, - help="Halve Y Subsubdiv. Frequency after 'n' Subdivs. (log only)") - self.OptionParser.add_option("--y_divs_th", - action="store", type="float", - dest="y_divs_th", default=2, - help="Major Y Division Line thickness") - self.OptionParser.add_option("--y_subdivs_th", - action="store", type="float", - dest="y_subdivs_th", default=1, - help="Minor Y Division Line thickness") - self.OptionParser.add_option("--y_subsubdivs_th", - action="store", type="float", - dest="y_subsubdivs_th", default=1, - help="Subminor Y Division Line thickness") - self.OptionParser.add_option("--border_th", - action="store", type="float", - dest="border_th", default=3, - help="Border Line thickness") - - - def effect(self): - - self.options.border_th = self.unittouu(str(self.options.border_th) + 'px') - self.options.dx = self.unittouu(str(self.options.dx) + 'px') - self.options.x_divs_th = self.unittouu(str(self.options.x_divs_th) + 'px') - self.options.x_subdivs_th = self.unittouu(str(self.options.x_subdivs_th) + 'px') - self.options.x_subsubdivs_th = self.unittouu(str(self.options.x_subsubdivs_th) + 'px') - self.options.dy = self.unittouu(str(self.options.dy) + 'px') - self.options.y_divs_th = self.unittouu(str(self.options.y_divs_th) + 'px') - self.options.y_subdivs_th = self.unittouu(str(self.options.y_subdivs_th) + 'px') - self.options.y_subsubdivs_th = self.unittouu(str(self.options.y_subsubdivs_th) + 'px') - - #find the pixel dimensions of the overall grid - ymax = self.options.dy * self.options.y_divs - xmax = self.options.dx * self.options.x_divs - - # Embed grid in group - #Put in in the centre of the current view - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str( view_center[0]- xmax/2.0) + ',' + \ - str( view_center[1]- ymax/2.0) + ')' - g_attribs = {inkex.addNS('label','inkscape'):'Grid_Polar:X' + \ - str( self.options.x_divs )+':Y'+str( self.options.y_divs ), - 'transform':t } - grid = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - #Group for major x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MajorXGridlines'} - majglx = inkex.etree.SubElement(grid, 'g', g_attribs) - - #Group for major y gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MajorYGridlines'} - majgly = inkex.etree.SubElement(grid, 'g', g_attribs) - - #Group for minor x gridlines - if self.options.x_subdivs > 1:#if there are any minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MinorXGridlines'} - minglx = inkex.etree.SubElement(grid, 'g', g_attribs) - - #Group for subminor x gridlines - if self.options.x_subsubdivs > 1:#if there are any minor minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'SubMinorXGridlines'} - mminglx = inkex.etree.SubElement(grid, 'g', g_attribs) - - #Group for minor y gridlines - if self.options.y_subdivs > 1:#if there are any minor y gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MinorYGridlines'} - mingly = inkex.etree.SubElement(grid, 'g', g_attribs) - - #Group for subminor y gridlines - if self.options.y_subsubdivs > 1:#if there are any minor minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'SubMinorYGridlines'} - mmingly = inkex.etree.SubElement(grid, 'g', g_attribs) - - - draw_SVG_rect(0, 0, xmax, ymax, self.options.border_th, - 'none', 'Border', grid) #border rectangle - - #DO THE X DIVISIONS====================================== - sd = self.options.x_subdivs #sub divs per div - ssd = self.options.x_subsubdivs #subsubdivs per subdiv - - for i in range(0, self.options.x_divs): #Major x divisions - if i>0: #don't draw first line (we made a proper border) - draw_SVG_line(self.options.dx*i, 0, - self.options.dx*i,ymax, - self.options.x_divs_th, - 'MajorXDiv'+str(i), majglx) - - if self.options.x_log: #log x subdivs - for j in range (1, sd): - if j>1: #the first loop is only for subsubdivs - draw_SVG_line(self.options.dx*(i+log(j, sd)), 0, - self.options.dx*(i+log(j, sd)), ymax, - self.options.x_subdivs_th, - 'MinorXDiv'+str(i)+':'+str(j), minglx) - - for k in range (1, ssd): #subsub divs - if (j <= self.options.x_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point - if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs, - ssd2 = ssd+1 #make even - else: - ssd2 = ssd #no change - draw_SVG_line(self.options.dx*(i+log(j+k/float(ssd2),sd )), 0, - self.options.dx*(i+log(j+k/float(ssd2),sd )), ymax, - self.options.x_subsubdivs_th,'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx) - - else: #linear x subdivs - for j in range (0, sd): - if j>0: #not for the first loop (this loop is for the subsubdivs before the first subdiv) - draw_SVG_line(self.options.dx*(i+j/float(sd)), 0, - self.options.dx*(i+j/float(sd)), ymax, - self.options.x_subdivs_th, - 'MinorXDiv'+str(i)+':'+str(j), minglx) - - for k in range (1, ssd): #subsub divs - draw_SVG_line(self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , 0, - self.options.dx*(i+(j*ssd+k)/((float(sd)*ssd))) , ymax, - self.options.x_subsubdivs_th, - 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mminglx) - - #DO THE Y DIVISIONS======================================== - sd = self.options.y_subdivs #sub divs per div - ssd = self.options.y_subsubdivs #subsubdivs per subdiv - - for i in range(0, self.options.y_divs): #Major y divisions - if i>0:#don't draw first line (we will make a border) - draw_SVG_line(0, self.options.dy*i, - xmax, self.options.dy*i, - self.options.y_divs_th, - 'MajorYDiv'+str(i), majgly) - - if self.options.y_log: #log y subdivs - for j in range (1, sd): - if j>1: #the first loop is only for subsubdivs - draw_SVG_line(0, self.options.dy*(i+1-log(j,sd)), - xmax, self.options.dy*(i+1-log(j,sd)), - self.options.y_subdivs_th, - 'MinorXDiv'+str(i)+':'+str(j), mingly) - - for k in range (1, ssd): #subsub divs - if (j <= self.options.y_half_freq) or (k%2 == 0):#only draw half the subsubdivs past the half-freq point - if (ssd%2 > 0) and (j > self.options.y_half_freq): #half frequency won't work with odd numbers of subsubdivs, - ssd2 = ssd+1 - else: - ssd2 = ssd #no change - draw_SVG_line(0, self.options.dx*(i+1-log(j+k/float(ssd2),sd )), - xmax, self.options.dx*(i+1-log(j+k/float(ssd2),sd )), - self.options.y_subsubdivs_th, - 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly) - else: #linear y subdivs - for j in range (0, self.options.y_subdivs): - if j>0:#not for the first loop (this loop is for the subsubdivs before the first subdiv) - draw_SVG_line(0, self.options.dy*(i+j/float(sd)), - xmax, self.options.dy*(i+j/float(sd)), - self.options.y_subdivs_th, - 'MinorXYiv'+str(i)+':'+str(j), mingly) - - for k in range (1, ssd): #subsub divs - draw_SVG_line(0, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))), - xmax, self.options.dy*(i+(j*ssd+k)/((float(sd)*ssd))), - self.options.y_subsubdivs_th, - 'SubminorXDiv'+str(i)+':'+str(j)+':'+str(k), mmingly) - - - -if __name__ == '__main__': - e = Grid_Polar() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/grid_isometric.inx b/share/extensions/grid_isometric.inx deleted file mode 100644 index bda671f18..000000000 --- a/share/extensions/grid_isometric.inx +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Isometric Grid</_name> - <id>grid.iso_grid</id> - <dependency type="executable" location="extensions">grid_isometric.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="x_divs" type="int" min="1" max="1000" _gui-text="X Divisions [x2]:">5</param> - <param name="y_divs" type="int" min="1" max="1000" _gui-text="Y Divisions [x2] [> 1/2 X Div]:">5</param> - <param name="dx" type="float" min="1" max="1000" _gui-text="Division Spacing (px):">50.0</param> - <param name="subdivs" type="int" min="1" max="1000" _gui-text="Subdivisions per Major Division:">2</param> - <param name="subsubdivs" type="int" min="1" max="1000" _gui-text="Subsubdivs per Subdivision:">5</param> - <param name="divs_th" type="float" min="0" max="1000" _gui-text="Major Division Thickness (px):">2</param> - <param name="subdivs_th" type="float" min="0" max="1000" _gui-text="Minor Division Thickness (px):">0.5</param> - <param name="subsubdivs_th" type="float" min="0" max="1000" _gui-text="Subminor Division Thickness (px):">0.1</param> - <param name="border_th" type="float" min="0" max="1000" _gui-text="Border Thickness (px):">3</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu name="Grids"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">grid_isometric.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/grid_isometric.py b/share/extensions/grid_isometric.py deleted file mode 100755 index d92b2d7a2..000000000 --- a/share/extensions/grid_isometric.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python - -#Copyright (C) 2010 Jean-Luc JOULIN "JeanJouX" jean-luc.joulin@laposte.net - -#This extension allow you to draw a isometric grid with inkscape -#There is some options including subdivision, subsubdivions and custom line width -#All elements are grouped with similar elements -#These grid are used for isometric view in mechanical drawing or piping schematic -#!!! Y Divisions can't be smaller than half the X Divions - -#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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -import inkex -import simplestyle, sys -from math import * -from simpletransform import computePointInNode - - -def draw_SVG_line(x1, y1, x2, y2, width, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' } - line_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -def draw_SVG_rect(x,y,w,h, width, fill, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill':fill} - rect_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'x':str(x), 'y':str(y), 'width':str(w), 'height':str(h)} - inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), rect_attribs ) - -class Grid_Polar(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--x_divs", - action="store", type="int", - dest="x_divs", default=5, - help="Major X Divisions") - self.OptionParser.add_option("--y_divs", - action="store", type="int", - dest="y_divs", default=5, - help="Major X Divisions") - self.OptionParser.add_option("--dx", - action="store", type="float", - dest="dx", default=10.0, - help="Major X division Spacing") - self.OptionParser.add_option("--subdivs", - action="store", type="int", - dest="subdivs", default=2, - help="Subdivisions per Major X division") - self.OptionParser.add_option("--subsubdivs", - action="store", type="int", - dest="subsubdivs", default=5, - help="Subsubdivisions per Minor X division") - self.OptionParser.add_option("--divs_th", - action="store", type="float", - dest="divs_th", default=2, - help="Major X Division Line thickness") - self.OptionParser.add_option("--subdivs_th", - action="store", type="float", - dest="subdivs_th", default=1, - help="Minor X Division Line thickness") - self.OptionParser.add_option("--subsubdivs_th", - action="store", type="float", - dest="subsubdivs_th", default=0.3, - help="Subminor X Division Line thickness") - self.OptionParser.add_option("--border_th", - action="store", type="float", - dest="border_th", default=3, - help="Border Line thickness") - - def effect(self): - - self.options.dx = self.unittouu(str(self.options.dx) + 'px') - self.options.divs_th = self.unittouu(str(self.options.divs_th) + 'px') - self.options.subdivs_th = self.unittouu(str(self.options.subdivs_th) + 'px') - self.options.subsubdivs_th = self.unittouu(str(self.options.subsubdivs_th) + 'px') - self.options.border_th = self.unittouu(str(self.options.border_th) + 'px') - - #Can't generate a grid too flat - #If the Y dimension is smallest than half the X dimension, fix it. - if self.options.y_divs<((self.options.x_divs+1)/2): - self.options.y_divs=int((self.options.x_divs+1)/2) - - #Find the pixel dimensions of the overall grid - xmax = self.options.dx * (2*self.options.x_divs) - ymax = self.options.dx * (2*self.options.y_divs) / 0.866025 - - #Embed grid in group - #Put in in the centre of the current view - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str( view_center[0]- xmax/2.0) + ',' + \ - str( view_center[1]- ymax/2.0) + ')' - g_attribs = {inkex.addNS('label','inkscape'):'Grid_Polar:X' + \ - str( self.options.x_divs )+':Y'+str( self.options.y_divs ), - 'transform':t } - grid = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - #Group for major x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MajorXGridlines'} - majglx = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for major y gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MajorYGridlines'} - majgly = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for major z gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MajorZGridlines'} - majglz = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for minor x gridlines - if self.options.subdivs > 1:#if there are any minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MinorXGridlines'} - minglx = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for subminor x gridlines - if self.options.subsubdivs > 1:#if there are any minor minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'SubMinorXGridlines'} - mminglx = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for minor y gridlines - if self.options.subdivs > 1:#if there are any minor y gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MinorYGridlines'} - mingly = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for subminor y gridlines - if self.options.subsubdivs > 1:#if there are any minor minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'SubMinorYGridlines'} - mmingly = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for minor z gridlines - if self.options.subdivs > 1:#if there are any minor y gridlines - g_attribs = {inkex.addNS('label','inkscape'):'MinorZGridlines'} - minglz = inkex.etree.SubElement(grid, 'g', g_attribs) - #Group for subminor z gridlines - if self.options.subsubdivs > 1:#if there are any minor minor x gridlines - g_attribs = {inkex.addNS('label','inkscape'):'SubMinorZGridlines'} - mminglz = inkex.etree.SubElement(grid, 'g', g_attribs) - - - draw_SVG_rect(0, 0, xmax, ymax, self.options.border_th, - 'none', 'Border', grid) #Border of grid - - #X DIVISION - #Shortcuts for divisions - sd = self.options.subdivs - ssd = self.options.subsubdivs - - #Initializing variable - cpt_div=0 - cpt_subdiv=0 - cpt_subsubdiv=0 - com_div=0 - com_subdiv=0 - com_subsubdiv=0 - - for i in range(1, (2*self.options.x_divs*sd*ssd)): - cpt_subsubdiv=cpt_subsubdiv+1 - com_subsubdiv=1 - if cpt_subsubdiv==self.options.subsubdivs: - cpt_subsubdiv=0 - cpt_subdiv=cpt_subdiv+1 - com_subsubdiv=0 - com_subdiv=1 - com_div=0 - - if cpt_subdiv==self.options.subdivs: - cpt_subdiv=0 - com_subsubdiv=0 - com_subdiv=0 - com_div=1 - - if com_subsubdiv==1: - draw_SVG_line(self.options.dx*i/sd/ssd, 0, - self.options.dx*i/sd/ssd,ymax, - self.options.subsubdivs_th, - 'MajorXDiv'+str(i), mminglx) - if com_subdiv==1: - com_subdiv=0 - draw_SVG_line(self.options.dx*i/sd/ssd, 0, - self.options.dx*i/sd/ssd,ymax, - self.options.subdivs_th, - 'MajorXDiv'+str(i), minglx) - if com_div==1: - com_div=0 - draw_SVG_line(self.options.dx*i/sd/ssd, 0, - self.options.dx*i/sd/ssd,ymax, - self.options.divs_th, - 'MajorXDiv'+str(i), majglx) - - - #Y DIVISIONS - #Shortcuts for divisions - sd = self.options.subdivs - ssd = self.options.subsubdivs - - taille=self.options.dx/sd/ssd #Size of unity - nb_ligne=(self.options.x_divs+self.options.y_divs)*self.options.subdivs*self.options.subsubdivs #Global number of lines - nb_ligne_x=self.options.x_divs*self.options.subdivs*self.options.subsubdivs #Number of lines X - nb_ligne_y=self.options.y_divs*self.options.subdivs*self.options.subsubdivs #Number of lines Y - - #Initializing variable - cpt_div=0 - cpt_subdiv=0 - cpt_subsubdiv=0 - com_div=0 - com_subdiv=0 - com_subsubdiv=0 - - - for l in range(1, int(nb_ligne*4)): - cpt_subsubdiv=cpt_subsubdiv+1 - com_subsubdiv=1 - if cpt_subsubdiv==self.options.subsubdivs: - cpt_subsubdiv=0 - cpt_subdiv=cpt_subdiv+1 - com_subsubdiv=0 - com_subdiv=1 - com_div=0 - - if cpt_subdiv==self.options.subdivs: - cpt_subdiv=0 - com_subsubdiv=0 - com_subdiv=0 - com_div=1 - - if ((2*l)-1)< (2*nb_ligne_x): - txa=taille*((2*l)-1) - tya=ymax - txb=0 - tyb=ymax-(taille)/(2*0.866025)-(taille*((l-1))/(0.866025)) - - if com_subsubdiv==1: - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subsubdivs_th, - 'MajorYDiv'+str(i), mmingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subsubdivs_th, - 'MajorZDiv'+str(l), mminglz) - if com_subdiv==1: - com_subdiv=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subdivs_th, - 'MajorYDiv'+str(i), mingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subdivs_th, - 'MajorZDiv'+str(l), minglz) - if com_div==1: - com_div=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.divs_th, - 'MajorYDiv'+str(i), majgly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.divs_th, - 'MajorZDiv'+str(l), majglz) - - if ((2*l)-1)==(2*nb_ligne_x): - txa=taille*((2*l)-1) - tya=ymax - txb=0 - tyb=ymax-(taille)/(2*0.866025)-(taille*((l-1))/(0.866025)) - - if com_subsubdiv==1: - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subsubdivs_th, - 'MajorYDiv'+str(i), mmingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subsubdivs_th, - 'MajorZDiv'+str(l), mminglz) - if com_subdiv==1: - com_subdiv=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subdivs_th, - 'MajorYDiv'+str(i), mingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subdivs_th, - 'MajorZDiv'+str(l), minglz) - if com_div==1: - com_div=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.divs_th, - 'MajorYDiv'+str(i), majgly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.divs_th, - 'MajorZDiv'+str(l), majglz) - - if ((2*l)-1)> (2*nb_ligne_x): - txa=xmax - tya=ymax-(taille)/(2*0.866025)-(taille*((l-1-((2*nb_ligne_x)/2)))/(0.866025)) - txb=0 - tyb=ymax-(taille)/(2*0.866025)-(taille*((l-1))/(0.866025)) - - if tyb<=0: - txa=xmax - tya=ymax-(taille)/(2*0.866025)-(taille*((l-1-((2*nb_ligne_x)/2)))/(0.866025)) - txb=taille*((2*(l-(2*nb_ligne_y))-1)) - tyb=0 - - if txb<xmax: - if com_subsubdiv==1: - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subsubdivs_th, - 'MajorYDiv'+str(i), mmingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subsubdivs_th, - 'MajorZDiv'+str(l), mminglz) - if com_subdiv==1: - com_subdiv=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subdivs_th, - 'MajorYDiv'+str(i), mingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subdivs_th, - 'MajorZDiv'+str(l), minglz) - if com_div==1: - com_div=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.divs_th, - 'MajorYDiv'+str(i), majgly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.divs_th, - 'MajorZDiv'+str(l), majglz) - - else: - if txb<xmax: - if com_subsubdiv==1: - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subsubdivs_th, - 'MajorYDiv'+str(i), mmingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subsubdivs_th, - 'MajorZDiv'+str(l), mminglz) - if com_subdiv==1: - com_subdiv=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.subdivs_th, - 'MajorYDiv'+str(i), mingly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.subdivs_th, - 'MajorZDiv'+str(l), minglz) - if com_div==1: - com_div=0 - draw_SVG_line(txa, tya, - txb,tyb, - self.options.divs_th, - 'MajorYDiv'+str(i), majgly) - draw_SVG_line(xmax-txa, tya, - xmax-txb,tyb, - self.options.divs_th, - 'MajorZDiv'+str(l), majglz) - - - -if __name__ == '__main__': - e = Grid_Polar() - e.affect() - -#End of file - - diff --git a/share/extensions/grid_polar.inx b/share/extensions/grid_polar.inx deleted file mode 100644 index 2fbd190e5..000000000 --- a/share/extensions/grid_polar.inx +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Polar Grid</_name> - <id>grids.polar</id> - <dependency type="executable" location="extensions">grid_polar.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <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 msgctxt="Label" 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="tab" type="notebook"> - <page name="circular_div" _gui-text="Circular Divisions"> - <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> - </page> - <page name="angular_div" _gui-text="Angular Divisions"> - <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> - </page> - </param> - - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu name="Grids"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">grid_polar.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/grid_polar.py b/share/extensions/grid_polar.py deleted file mode 100755 index 81ee3f049..000000000 --- a/share/extensions/grid_polar.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Beard john.j.beard@gmail.com - -##This extension allows you to draw a polar grid in Inkscape. -##There is a wide range of options including subdivision and labels. - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle, sys -from math import * -from simpletransform import computePointInNode - -def draw_SVG_circle(r, cx, cy, width, fill, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': fill } - circ_attribs = {'style':simplestyle.formatStyle(style), - 'cx':str(cx), 'cy':str(cy), - 'r':str(r), - inkex.addNS('label','inkscape'):name} - circle = inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs ) - -def draw_SVG_line(x1, y1, x2, y2, width, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' } - line_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -def draw_SVG_label_centred(x, y, string, font_size, name, parent): - style = {'text-align': 'center', 'vertical-align': 'top', - 'text-anchor': 'middle', 'font-size': str(font_size)+'px', - 'fill-opacity': '1.0', 'stroke': 'none', - 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'} - label_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'x':str(x), 'y':str(y)} - label = inkex.etree.SubElement(parent, inkex.addNS('text','svg'), label_attribs) - label.text = string - -class Grid_Polar(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", default="circular_div") - self.OptionParser.add_option("--r_divs", - action="store", type="int", - dest="r_divs", default=5, - help="Circular Divisions") - self.OptionParser.add_option("--dr", - action="store", type="float", - dest="dr", default=50, - help="Circular Division Spacing") - self.OptionParser.add_option("--r_subdivs", - action="store", type="int", - dest="r_subdivs", default=3, - help="Circular Subdivisions per Major division") - self.OptionParser.add_option("--r_log", - action="store", type="inkbool", - dest="r_log", default=False, - help="Logarithmic subdivisions if true") - self.OptionParser.add_option("--r_divs_th", - action="store", type="float", - dest="r_divs_th", default=2, - help="Major Circular Division Line thickness") - self.OptionParser.add_option("--r_subdivs_th", - action="store", type="float", - dest="r_subdivs_th", default=1, - help="Minor Circular Division Line thickness") - self.OptionParser.add_option("--a_divs", - action="store", type="int", - dest="a_divs", default=24, - help="Angle Divisions") - self.OptionParser.add_option("--a_divs_cent", - action="store", type="int", - dest="a_divs_cent", default=4, - help="Angle Divisions at Centre") - self.OptionParser.add_option("--a_subdivs", - action="store", type="int", - dest="a_subdivs", default=1, - help="Angcular Subdivisions per Major division") - self.OptionParser.add_option("--a_subdivs_cent", - action="store", type="int", - dest="a_subdivs_cent", default=1, - help="Angular Subdivisions end 'n' major circular divisions before the centre") - self.OptionParser.add_option("--a_divs_th", - action="store", type="float", - dest="a_divs_th", default=2, - help="Major Angular Division Line thickness") - self.OptionParser.add_option("--a_subdivs_th", - action="store", type="float", - dest="a_subdivs_th", default=1, - help="Minor Angular Division Line thickness") - self.OptionParser.add_option("--c_dot_dia", - action="store", type="float", - dest="c_dot_dia", default=5.0, - help="Diameter of Centre Dot") - self.OptionParser.add_option("--a_labels", - action="store", type="string", - dest="a_labels", default='deg', - help="The kind of labels to apply") - self.OptionParser.add_option("--a_label_size", - action="store", type="int", - dest="a_label_size", default=18, - help="The nominal pixel size of the circumferential labels") - self.OptionParser.add_option("--a_label_outset", - action="store", type="float", - dest="a_label_outset", default=24, - help="The radial outset of the circumferential labels") - - def effect(self): - - self.options.dr = self.unittouu(str(self.options.dr) + 'px') - self.options.r_divs_th = self.unittouu(str(self.options.r_divs_th) + 'px') - self.options.r_subdivs_th = self.unittouu(str(self.options.r_subdivs_th) + 'px') - self.options.a_divs_th = self.unittouu(str(self.options.a_divs_th) + 'px') - self.options.a_subdivs_th = self.unittouu(str(self.options.a_subdivs_th) + 'px') - self.options.c_dot_dia = self.unittouu(str(self.options.c_dot_dia) + 'px') - self.options.a_label_size = self.unittouu(str(self.options.a_label_size) + 'px') - self.options.a_label_outset = self.unittouu(str(self.options.a_label_outset) + 'px') - - # Embed grid in group - #Put in in the centre of the current view - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str( view_center[0] ) + ',' + str( view_center[1] ) + ')' - g_attribs = {inkex.addNS('label','inkscape'):'Grid_Polar:R' + - str( self.options.r_divs )+':A'+str( self.options.a_divs ), - 'transform':t } - grid = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - dr = self.options.dr #Distance between neighbouring circles - dtheta = 2 * pi / self.options.a_divs_cent #Angular change between adjacent radial lines at centre - rmax = self.options.r_divs * dr - - #Create SVG circles - for i in range(1, self.options.r_divs+1): - draw_SVG_circle(i*dr, 0, 0, #major div circles - self.options.r_divs_th, 'none', - 'MajorDivCircle'+str(i)+':R'+str(i*dr), grid) - - if self.options.r_log: #logarithmic subdivisions - for j in range (2, self.options.r_subdivs): - draw_SVG_circle(i*dr-(1-log(j, self.options.r_subdivs))*dr, #minor div circles - 0, 0, self.options.r_subdivs_th, 'none', - 'MinorDivCircle'+str(i)+':Log'+str(j), grid) - else: #linear subdivs - for j in range (1, self.options.r_subdivs): - draw_SVG_circle(i*dr-j*dr/self.options.r_subdivs, #minor div circles - 0, 0, self.options.r_subdivs_th, 'none', - 'MinorDivCircle'+str(i)+':R'+str(i*dr), grid) - - if self.options.a_divs == self.options.a_divs_cent: #the lines can go from the centre to the edge - for i in range(0, self.options.a_divs): - draw_SVG_line(0, 0, rmax*sin(i*dtheta), rmax*cos(i*dtheta), - self.options.a_divs_th, 'RadialGridline'+str(i), grid) - - else: #we need separate lines - for i in range(0, self.options.a_divs_cent): #lines that go to the first circle - draw_SVG_line(0, 0, dr*sin(i*dtheta), dr*cos(i*dtheta), - self.options.a_divs_th, 'RadialGridline'+str(i), grid) - - dtheta = 2 * pi / self.options.a_divs #work out the angle change for outer lines - - for i in range(0, self.options.a_divs): #lines that go from there to the edge - draw_SVG_line( dr*sin(i*dtheta+pi/2.0), dr*cos(i*dtheta+pi/2.0), - rmax*sin(i*dtheta+pi/2.0), rmax*cos(i*dtheta+pi/2.0), - self.options.a_divs_th, 'RadialGridline'+str(i), grid) - - if self.options.a_subdivs > 1: #draw angular subdivs - for i in range(0, self.options.a_divs): #for each major division - for j in range(1, self.options.a_subdivs): #draw the subdivisions - angle = i*dtheta-j*dtheta/self.options.a_subdivs+pi/2.0 # the angle of the subdivion line - draw_SVG_line(dr*self.options.a_subdivs_cent*sin(angle), - dr*self.options.a_subdivs_cent*cos(angle), - rmax*sin(angle), rmax*cos(angle), - self.options.a_subdivs_th, 'RadialMinorGridline'+str(i), grid) - - if self.options.c_dot_dia <> 0: #if a non-zero diameter, draw the centre dot - draw_SVG_circle(self.options.c_dot_dia /2.0, - 0, 0, 0, '#000000', 'CentreDot', grid) - - if self.options.a_labels == 'deg': - label_radius = rmax+self.options.a_label_outset #radius of label centres - label_size = self.options.a_label_size - numeral_size = 0.73*label_size #numerals appear to be 0.73 the height of the nominal pixel size of the font in "Sans" - - for i in range(0, self.options.a_divs):#self.options.a_divs): #radial line labels - draw_SVG_label_centred(sin(i*dtheta+pi/2.0)*label_radius, #0 at the RHS, mathematical style - cos(i*dtheta+pi/2.0)*label_radius+ numeral_size/2.0, #centre the text vertically - str(i*360/self.options.a_divs), - label_size, 'Label'+str(i), grid) - -if __name__ == '__main__': - e = Grid_Polar() - e.affect() - - -# 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 deleted file mode 100644 index baaa093c3..000000000 --- a/share/extensions/guides_creator.inx +++ /dev/null @@ -1,96 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Guides creator</_name> - <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="tab" type="notebook"> - <page name="regular_guides" _gui-text="Regular guides"> - <param name="guides_preset" type="enum" appearance="minimal" _gui-text="Guides 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="int" min="1" max="1000" _gui-text="Columns:">2</param> - <param name="horizontal_guides" type="int" min="1" max="1000" _gui-text="Rows:">3</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> - </page> - <page name="diagonal_guides" _gui-text="Diagonal guides"> - <param name="ul" type="boolean" _gui-text="Upper left corner">false</param> - <param name="ur" type="boolean" _gui-text="Upper right corner">false</param> - <param name="ll" type="boolean" _gui-text="Lower left corner">false</param> - <param name="lr" type="boolean" _gui-text="Lower right corner">false</param> - <param name="delete_existing_guides2" type="boolean" _gui-text="Delete existing guides">false</param> - </page> - <page name="margins" _gui-text="Margins"> - <param name="margins_preset" type="enum" appearance="minimal" _gui-text="Margins preset:"> - <_item value="custom">Custom...</_item> - <_item value="book_left">Left book page</_item> - <_item value="book_right">Right book page</_item> - </param> - <param name="header_margin" type="enum" appearance="minimal" _gui-text="Header margin:"> - <item value="10">1/10</item> - <item value="9">1/9</item> - <item value="8">1/8</item> - <item value="7">1/7</item> - <item value="6">1/6</item> - <item value="5">1/5</item> - <item value="4">1/4</item> - <item value="3">1/3</item> - <item value="2">1/2</item> - <_item msgctxt="Margin" value="0">None</_item> - </param> - <param name="footer_margin" type="enum" appearance="minimal" _gui-text="Footer margin:"> - <item value="10">1/10</item> - <item value="9">1/9</item> - <item value="8">1/8</item> - <item value="7">1/7</item> - <item value="6">1/6</item> - <item value="5">1/5</item> - <item value="4">1/4</item> - <item value="3">1/3</item> - <item value="2">1/2</item> - <_item msgctxt="Margin" value="0">None</_item> - </param> - <param name="left_margin" type="enum" appearance="minimal" _gui-text="Left margin:"> - <item value="10">1/10</item> - <item value="9">1/9</item> - <item value="8">1/8</item> - <item value="7">1/7</item> - <item value="6">1/6</item> - <item value="5">1/5</item> - <item value="4">1/4</item> - <item value="3">1/3</item> - <item value="2">1/2</item> - <_item msgctxt="Margin" value="0">None</_item> - </param> - <param name="right_margin" type="enum" appearance="minimal" _gui-text="Right margin:"> - <item value="10">1/10</item> - <item value="9">1/9</item> - <item value="8">1/8</item> - <item value="7">1/7</item> - <item value="6">1/6</item> - <item value="5">1/5</item> - <item value="4">1/4</item> - <item value="3">1/3</item> - <item value="2">1/2</item> - <_item msgctxt="Margin" value="0">None</_item> - </param> - <param name="vertical_subdivisions" type="int" min="1" max="1000" _gui-text="Columns:">2</param> - <param name="horizontal_subdivisions" type="int" min="1" max="1000" _gui-text="Rows:">3</param> - <param name="start_from_edges2" type="boolean" _gui-text="Start from edges">false</param> - <param name="delete_existing_guides3" type="boolean" _gui-text="Delete existing guides">false</param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">guides_creator.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/guides_creator.py b/share/extensions/guides_creator.py deleted file mode 100755 index 0c3a91c77..000000000 --- a/share/extensions/guides_creator.py +++ /dev/null @@ -1,493 +0,0 @@ -#!/usr/bin/env python -''' -Guides Creator v2.31 (05/07/2009) -http://code.google.com/p/inkscape-guides-creator/ - -Copyright (C) 2008 Jonas Termeau - jonas.termeau **AT** gmail.com - -Thanks to: - -Bernard Gray - bernard.gray **AT** gmail.com (python helping) -Jamie Heames (english translation issues) -~suv (bug report in v2.3) -http://www.gutenberg.eu.org/publications/ (9x9 margins settings) - -## This basic extension allows you to automatically draw guides in inkscape. - -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; version 2 of the License. - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# Inspired by hello_world turorial by Blackhex and Rubikcube -# (http://wiki.inkscape.org/wiki/index.php/PythonEffectTutorial) - -# Making an .INX file : http://wiki.inkscape.org/wiki/index.php/MakingAnINX -# see also http://codespeak.net/lxml/dev/tutorial.html#namespaces for XML namespaces manipulation - -# # # # # # # # -# TODO: See http://code.google.com/p/inkscape-guides-creator/wiki/Roadmap -# # # # # # # # - - -# # # extension's beginning # # # - -# These two lines are only needed if you don't put the script directly into -# the installation directory -import sys -sys.path.append('/usr/share/inkscape/extensions') - -from xml.etree import ElementTree as ET -# for golden number formulae -from math import sqrt - -# We will use the inkex module with the predefined Effect base class. -import inkex -from simplestyle import * - -from xml.etree import ElementTree as ET - -# for golden number formula and diagonal guides -from math import sqrt -from math import cos -from math import sin - -# for printing debugging output -import gettext -_ = gettext.gettext - -def printDebug(string): - inkex.errormsg(_(str(string))) - -def drawVerticalGuides(division,w,h,edges,parent,vertical_shift=0): - if (division > 0): - if (edges): - var = 1 - else: - var = 0 - - for v in range(0,division-1+2*var): - # setting up the guide's attributes (id is generated automatically) - position = str(round((w / division) + (v - var) * (w / division) + vertical_shift,4)) + ",0" - orientation = str(round(h,4)) + ",0" - - createGuide(position,orientation,parent) - -def drawHorizontalGuides(division,w,h,edges,parent,horizontal_shift=0): - if (division > 0): - if (edges): - var = 1 - else: - var = 0 - - for x in range(0,division-1+2*var): - # setting up the guide's attributes (id is generated automatically) - position = "0," + str(round((h / division) + (x - var) * (h / division) + horizontal_shift,4)) - orientation = "0," + str(round(w,4)) - - createGuide(position,orientation,parent) - -def createGuide(position,orientation,parent): - # Create a sodipodi:guide node - # (look into inkex's namespaces to find 'sodipodi' value in order to make a "sodipodi:guide" tag) - # see NSS array in file inkex.py for the other namespaces - inkex.etree.SubElement(parent,'{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}guide',{'position':position,'orientation':orientation}) - -def getVerticalDivisionsFromPreset(preset): - # take a "string1;string2" preset - # and return "string1" - str_array = preset.split(';') - result = int(str_array[0]) - - return result - -def getHorizontalDivisionsFromPreset(preset): - # take a "string1;string2" preset - # and return "string2" - str_array = preset.split(';') - result = int(str_array[1]) - - return result - -def deleteAllGuides(document): - # getting the parent's tag of the guides - nv = document.xpath('/svg:svg/sodipodi:namedview',namespaces=inkex.NSS)[0] - - # getting all the guides - children = document.xpath('/svg:svg/sodipodi:namedview/sodipodi:guide',namespaces=inkex.NSS) - - # removing each guides - for element in children: - nv.remove(element) - -class Guides_Creator(inkex.Effect): - - def __init__(self): - """ - Constructor. - Defines options of the script. - """ - # Call the base class constructor. - inkex.Effect.__init__(self) - - # Define option for the tab. - self.OptionParser.add_option("--tab", - action="store",type="string", - dest="tab", default="regular_guides", - help="") - - # Define string option "--preset" with default value 'custom'. - self.OptionParser.add_option('--guides_preset', - action = 'store',type = 'string', - dest = 'guides_preset',default = 'custom', - help = 'Preset') - - # Define string option "--vertical_guides" with default value '0'. - self.OptionParser.add_option('--vertical_guides', - action = 'store',type = 'string', - dest = 'vertical_guides',default = 0, - help = 'Vertical guides each:') - - # Define string option "--horizontal_guides" with default value '0'. - self.OptionParser.add_option('--horizontal_guides', - action = 'store',type = 'string', - dest = 'horizontal_guides',default = 0, - help = 'Horizontal guides each:') - - # Define boolean option "--start_from_edges" with default value False. - self.OptionParser.add_option('--start_from_edges', - action = 'store',type = 'inkbool', - dest = 'start_from_edges',default = False, - help = 'Start from edges') - - # Define boolean option "--delete_existing_guides" with default value False. - self.OptionParser.add_option('--delete_existing_guides', - action = 'store',type = 'inkbool', - dest = 'delete_existing_guides',default = False, - help = 'Delete existing guides') - - # Define boolean option "--upper_left_corner" with default value False. - self.OptionParser.add_option('--ul', - action = 'store',type = 'inkbool', - dest = 'ul',default = False, - help = 'Upper left corner') - - # Define boolean option "--upper_right_corner" with default value False. - self.OptionParser.add_option('--ur', - action = 'store',type = 'inkbool', - dest = 'ur',default = False, - help = 'Upper right corner') - - # Define boolean option "--lower_left_corner" with default value False. - self.OptionParser.add_option('--ll', - action = 'store',type = 'inkbool', - dest = 'll',default = False, - help = 'Lower left corner') - - # Define boolean option "--upper_left_corner" with default value False. - self.OptionParser.add_option('--lr', - action = 'store',type = 'inkbool', - dest = 'lr',default = False, - help = 'Lower right corner') - - # Define boolean option "--delete_existing_guides2" with default value False. - self.OptionParser.add_option('--delete_existing_guides2', - action = 'store',type = 'inkbool', - dest = 'delete_existing_guides2',default = False, - help = 'Delete existing guides') - - # Define string option "--margins_preset" with default value 'custom'. - self.OptionParser.add_option('--margins_preset', - action = 'store',type = 'string', - dest = 'margins_preset',default = 'custom', - help = 'Margins preset') - - # Define boolean option "--delete_existing_guides3" with default value False. - self.OptionParser.add_option('--delete_existing_guides3', - action = 'store',type = 'inkbool', - dest = 'delete_existing_guides3',default = False, - help = 'Delete existing guides') - - # Define string option "--vertical_subdivisions" with default value '0'. - self.OptionParser.add_option('--vertical_subdivisions', - action = 'store',type = 'string', - dest = 'vertical_subdivisions',default = 0, - help = 'Vertical subdivisions') - - # Define string option "--horizontal_subdivisions" with default value '0'. - self.OptionParser.add_option('--horizontal_subdivisions', - action = 'store',type = 'string', - dest = 'horizontal_subdivisions',default = 0, - help = 'Horizontal subdivisions') - - # Define string option "--header_margin" with default value '6'. - self.OptionParser.add_option('--header_margin', - action = 'store',type = 'string', - dest = 'header_margin',default = 6, - help = 'Header margin') - - # Define string option "--footer_margin" with default value '6'. - self.OptionParser.add_option('--footer_margin', - action = 'store',type = 'string', - dest = 'footer_margin',default = 6, - help = 'Footer margin') - - # Define string option "--left_margin" with default value '6'. - self.OptionParser.add_option('--left_margin', - action = 'store',type = 'string', - dest = 'left_margin',default = 6, - help = 'Left margin') - - # Define string option "--right_margin" with default value '6'. - self.OptionParser.add_option('--right_margin', - action = 'store',type = 'string', - dest = 'right_margin',default = 6, - help = 'Right margin') - - # Define boolean option "--start_from_edges2" with default value False. - self.OptionParser.add_option('--start_from_edges2', - action = 'store',type = 'inkbool', - dest = 'start_from_edges2',default = False, - help = 'Start from edges') - - def effect(self): - - # Get script's options value. - - tab = self.options.tab - - # first tab - guides_preset = self.options.guides_preset - h_division = int(self.options.horizontal_guides) - v_division = int(self.options.vertical_guides) - from_edges = self.options.start_from_edges - delete_existing = self.options.delete_existing_guides - - # second tab - upper_left = self.options.ul - upper_right = self.options.ur - lower_left = self.options.ll - lower_right = self.options.lr - delete_existing2 = self.options.delete_existing_guides2 - - # third tab - margins_preset = self.options.margins_preset - header_margin = int(self.options.header_margin) - footer_margin = int(self.options.footer_margin) - left_margin = int(self.options.left_margin) - right_margin = int(self.options.right_margin) - h_subdiv = int(self.options.horizontal_subdivisions) - v_subdiv = int(self.options.vertical_subdivisions) - from_edges2 = self.options.start_from_edges2 - delete_existing3 = self.options.delete_existing_guides3 - - # getting the main SVG document element (canvas) - svg = self.document.getroot() - - # getting the width and height attributes of the canvas - width = self.unittouu(svg.get('width')) - height = self.unittouu(svg.get('height')) - - # getting edges coordinates - h_orientation = '0,' + str(round(width,4)) - v_orientation = str(round(height,4)) + ',0' - - # getting parent tag of the guides - nv = self.document.find(inkex.addNS('namedview', 'sodipodi')) - - if (tab == "\"regular_guides\""): - - if (delete_existing): - deleteAllGuides(self.document) - - if (guides_preset == 'custom'): - - if ((v_division == 0) and (from_edges)): - v_division = 1 - - if ((h_division == 0) and (from_edges)): - h_division = 1 - - # creating vertical guides - drawVerticalGuides(v_division,width,height,from_edges,nv) - - # creating horizontal guides - drawHorizontalGuides(h_division,width,height,from_edges,nv) - - elif (guides_preset == 'golden'): - - gold = (1 + sqrt(5)) / 2 - - # horizontal golden guides - position1 = '0,' + str(height / gold) - position2 = '0,'+ str(height - (height / gold)) - - createGuide(position1,h_orientation,nv) - createGuide(position2,h_orientation,nv) - - # vertical golden guides - position1 = str(width / gold) + ',0' - position2 = str(width - (width / gold)) + ',0' - - createGuide(position1,v_orientation,nv) - createGuide(position2,v_orientation,nv) - - if (from_edges): - # horizontal borders - createGuide('0,' + str(height),h_orientation,nv) - createGuide(str(height) + ',0',h_orientation,nv) - - # vertical borders - createGuide('0,' + str(width),v_orientation,nv) - createGuide(str(width) + ',0',v_orientation,nv) - - - else: - - v_division = getVerticalDivisionsFromPreset(guides_preset) - h_division = getHorizontalDivisionsFromPreset(guides_preset) - - drawVerticalGuides(v_division,width,height,from_edges,nv) - drawHorizontalGuides(h_division,width,height,from_edges,nv) - - elif (tab == "\"diagonal_guides\""): - - if (delete_existing2): - deleteAllGuides(self.document) - - # diagonal - angle = 45 - - # X axe - left = 0 - right = width - - # Y axe - down = 0 - up = height - - ul_corner = str(up) + ',' + str(left) - ur_corner = str(right) + ',' + str(up) - ll_corner = str(down) + ',' + str(left) - lr_corner = str(down) + ',' + str(right) - - from_ul_to_lr = str(cos(angle)) + ',' + str(cos(angle)) - from_ur_to_ll = str(-sin(angle)) + ',' + str(sin(angle)) - from_ll_to_ur = str(-cos(angle)) + ',' + str(cos(angle)) - from_lr_to_ul = str(-sin(angle)) + ',' + str(-sin(angle)) - - if (upper_left): - createGuide(ul_corner,from_ul_to_lr,nv) - - if (upper_right): - createGuide(ur_corner,from_ur_to_ll,nv) - - if (lower_left): - createGuide(ll_corner,from_ll_to_ur,nv) - if (lower_right): - createGuide(lr_corner,from_lr_to_ul,nv) - - elif (tab == "\"margins\""): - - if (delete_existing3): - deleteAllGuides(self.document) - - if (from_edges2): - - # horizontal borders - createGuide('0,' + str(height),h_orientation,nv) - createGuide(str(height) + ',0',h_orientation,nv) - - # vertical borders - createGuide('0,' + str(width),v_orientation,nv) - createGuide(str(width) + ',0',v_orientation,nv) - - if (margins_preset == 'custom'): - - y_header = height - y_footer = 0 - x_left = 0 - x_right = width - - if (header_margin != 0): - y_header = (height / header_margin) * (header_margin - 1) - createGuide('0,' + str(y_header),h_orientation,nv) - - if (footer_margin != 0): - y_footer = height / footer_margin - createGuide('0,' + str(y_footer),h_orientation,nv) - - if (left_margin != 0): - x_left = width / left_margin - createGuide(str(x_left) + ',0',v_orientation,nv) - - if (right_margin != 0): - x_right = (width / right_margin) * (right_margin - 1) - createGuide(str(x_right) + ',0',v_orientation,nv) - - elif (margins_preset == 'book_left'): - # 1/9th header - y_header = (height / 9) * 8 - createGuide('0,' + str(y_header),h_orientation,nv) - - # 2/9th footer - y_footer = (height / 9) * 2 - createGuide('0,' + str(y_footer),h_orientation,nv) - - # 2/9th left margin - x_left = (width / 9) * 2 - createGuide(str(x_left) + ',0',v_orientation,nv) - - # 1/9th right margin - x_right = (width / 9) * 8 - createGuide(str(x_right) + ',0',v_orientation,nv) - - elif (margins_preset == 'book_right'): - # 1/9th header - y_header = (height / 9) * 8 - createGuide('0,' + str(y_header),h_orientation,nv) - - # 2/9th footer - y_footer = (height / 9) * 2 - createGuide('0,' + str(y_footer),h_orientation,nv) - - # 2/9th left margin - x_left = (width / 9) - createGuide(str(x_left) + ',0',v_orientation,nv) - - # 1/9th right margin - x_right = (width / 9) * 7 - createGuide(str(x_right) + ',0',v_orientation,nv) - - - # setting up properties of the rectangle created between guides - rectangle_height = y_header - y_footer - rectangle_width = x_right - x_left - - if (h_subdiv != 0): - begin_from = y_footer - - # creating horizontal guides - drawHorizontalGuides(h_subdiv,rectangle_width,rectangle_height,0,nv,begin_from) - - if (v_subdiv != 0): - begin_from = x_left - - # creating vertical guides - drawVerticalGuides(v_subdiv,rectangle_width,rectangle_height,0,nv,begin_from) - -if __name__ == '__main__': - # Create effect instance and apply it. - effect = Guides_Creator() - effect.affect() - -## end of file guide_creator.py ## diff --git a/share/extensions/guillotine.inx b/share/extensions/guillotine.inx deleted file mode 100644 index 3cf34cc5e..000000000 --- a/share/extensions/guillotine.inx +++ /dev/null @@ -1,26 +0,0 @@ -<?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 deleted file mode 100755 index ee7ae39fa..000000000 --- a/share/extensions/guillotine.py +++ /dev/null @@ -1,256 +0,0 @@ -#!/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. - -''' -# standard library -import locale -import os -import sys -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False -# local library -import inkex -import simplestyle - -locale.setlocale(locale.LC_ALL, '') - -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'][:2] == '0,': - guide['orientation'] = 'horizontal' - guide['position'] = y - guides.append(guide) - elif g.attrib['orientation'][-2:] == ',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 = self.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 = self.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.inx b/share/extensions/handles.inx deleted file mode 100644 index 7513b383a..000000000 --- a/share/extensions/handles.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Draw Handles</_name> - <id>org.ekips.filter.handles</id> - <dependency type="executable" location="extensions">handles.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Visualize Path" /> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">handles.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/handles.py b/share/extensions/handles.py deleted file mode 100755 index 6987a3bb2..000000000 --- a/share/extensions/handles.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplepath, simplestyle - -class Handles(inkex.Effect): - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - p = simplepath.parsePath(node.get('d')) - a =[] - pen = None - subPathStart = None - for cmd,params in p: - if cmd == 'C': - a.extend([['M', params[:2]], ['L', pen], - ['M', params[2:4]], ['L', params[-2:]]]) - if cmd == 'Q': - a.extend([['M', params[:2]], ['L', pen], - ['M', params[:2]], ['L', params[-2:]]]) - - if cmd == 'M': - subPathStart = params - - if cmd == 'Z': - pen = subPathStart - else: - pen = params[-2:] - - if len(a) > 0: - s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px', - 'stroke-opacity': '1.0', 'fill-opacity': '1.0', - 'stroke': '#000000', 'stroke-linecap': 'butt', - 'fill': 'none'} - attribs = {'style':simplestyle.formatStyle(s),'d':simplepath.formatPath(a)} - inkex.etree.SubElement(node.getparent(), inkex.addNS('path','svg'), attribs) - -if __name__ == '__main__': - e = Handles() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hershey.inx b/share/extensions/hershey.inx deleted file mode 100644 index 4d923f046..000000000 --- a/share/extensions/hershey.inx +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Hershey Text</_name> - <id>org.evilmad.render.hershe</id> - <dependency type="executable" location="extensions">hershey.py</dependency> - <dependency type="executable" location="extensions">hersheydata.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="tab" type="notebook"> - <page name="splash" _gui-text="Render Text"> - <param name="text" type="string" _gui-text="Text:">Hershey Text for Inkscape</param> - - <param name="action" type="enum" _gui-text="Action: "> - <_item value="render">Typeset that text</_item> - <_item value="table" >Write glyph table</_item> - </param> - - <param name="fontface" type="enum" _gui-text="Font face: "> - <_item value="futural">Sans 1-stroke</_item> - <_item value="futuram">Sans bold</_item> - - <_item value="timesr">Serif medium</_item> - <_item value="timesi">Serif medium italic</_item> - <_item value="timesib">Serif bold italic</_item> - <_item value="timesrb">Serif bold</_item> - - <_item value="scripts">Script 1-stroke</_item> - <_item value="cursive">Script 1-stroke (alt)</_item> - <_item value="scriptc">Script medium</_item> - - <_item value="gothiceng">Gothic English</_item> - <_item value="gothicger">Gothic German</_item> - <_item value="gothicita">Gothic Italian</_item> - - <_item value="greek">Greek 1-stroke</_item> - <_item value="timesg">Greek medium</_item> - <_item value="cyrillic">Cyrillic</_item> - <_item value="japanese">Japanese</_item> - - <_item value="astrology">Astrology</_item> - <_item value="mathlow">Math (lower)</_item> - <_item value="mathupp">Math (upper)</_item> - <_item value="markers">Markers</_item> - <_item value="meteorology">Meteorology</_item> - <_item value="music">Music</_item> - <_item value="symbolic">Symbolic</_item> - - </param> - <_param name="emptyspace" type="description" xml:space="preserve"> - - - -</_param> - - </page> - <page name="info" _gui-text="About..."> - <_param name="aboutpage" type="description" xml:space="preserve"> -This extension renders a line of text using -"Hershey" fonts for plotters, derived from -NBS SP-424 1976-04, "A contribution to -computer typesetting techniques: Tables of -Coordinates for Hershey's Repertory of -Occidental Type Fonts and Graphic Symbols." - -These are not traditional "outline" fonts, -but are instead "single-stroke" fonts, or -"engraving" fonts where the character is -formed by the stroke (and not the fill). - -For additional information, please visit: - www.evilmadscientist.com/go/hershey</_param> - </page> - </param> - - <effect needs-live-preview="true" needs-document="true"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">hershey.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/hershey.py b/share/extensions/hershey.py deleted file mode 100755 index 471959b10..000000000 --- a/share/extensions/hershey.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Hershey Text - renders a line of text using "Hershey" fonts for plotters - -Copyright 2011, Windell H. Oskay, www.evilmadscientist.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" -import hersheydata #data file w/ Hershey font data -import inkex -import simplestyle -from simpletransform import computePointInNode - -Debug = False - -def draw_svg_text(char, face, offset, vertoffset, parent): - style = { 'stroke': '#000000', 'fill': 'none' } - pathString = face[char] - splitString = pathString.split() - midpoint = offset - int(splitString[0]) - pathString = pathString[pathString.find("M"):] #portion after first move - trans = 'translate(' + str(midpoint) + ',' + str(vertoffset) + ')' - text_attribs = {'style':simplestyle.formatStyle(style), 'd':pathString, 'transform':trans} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), text_attribs) - return midpoint + int(splitString[1]) #new offset value - - -class Hershey( inkex.Effect ): - def __init__( self ): - inkex.Effect.__init__( self ) - self.OptionParser.add_option( "--tab", #NOTE: value is not used. - action="store", type="string", - dest="tab", default="splash", - help="The active tab when Apply was pressed" ) - self.OptionParser.add_option( "--text", - action="store", type="string", - dest="text", default="Hershey Text for Inkscape", - help="The input text to render") - self.OptionParser.add_option( "--action", - action="store", type="string", - dest="action", default="render", - help="The active option when Apply was pressed" ) - self.OptionParser.add_option( "--fontface", - action="store", type="string", - dest="fontface", default="rowmans", - help="The selected font face when Apply was pressed" ) - - def effect( self ): - - # Embed text in group to make manipulation easier: - g_attribs = {inkex.addNS('label','inkscape'):'Hershey Text' } - g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - scale = self.unittouu('1px') # convert to document units - font = eval('hersheydata.' + str(self.options.fontface)) - clearfont = hersheydata.futural - #Baseline: modernized roman simplex from JHF distribution. - - w = 0 #Initial spacing offset - spacing = 3 # spacing between letters - - if self.options.action == "render": - #evaluate text string - letterVals = [ord(q) - 32 for q in self.options.text] - for q in letterVals: - if (q < 0) or (q > 95): - w += 2*spacing - else: - w = draw_svg_text(q, font, w, 0, g) - else: - #Generate glyph table - wmax = 0; - for p in range(0,10): - w = 0 - v = spacing * (15*p - 67 ) - for q in range(0,10): - r = p*10 + q - if (r < 0) or (r > 95): - w += 5*spacing - else: - w = draw_svg_text(r, clearfont, w, v, g) - w = draw_svg_text(r, font, w, v, g) - w += 5*spacing - if w > wmax: - wmax = w - w = wmax - - # Translate group to center of view, approximately - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str( view_center[0] - scale*w/2) + ',' + str( view_center[1] ) + ')' - if scale != 1: - t += ' scale(' + str(scale) + ')' - g.set( 'transform',t) - - - -if __name__ == '__main__': - e = Hershey() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hersheydata.py b/share/extensions/hersheydata.py deleted file mode 100644 index 2b732f9f0..000000000 --- a/share/extensions/hersheydata.py +++ /dev/null @@ -1,58 +0,0 @@ -## hersheydata.py -## -## This file prepared in 2011 by Windell H. Oskay, www.evilmadscientist.com -## -## -## Contents adapted from emergent.unpythonic.net/software/hershey -## by way of http://www.thingiverse.com/thing:6168 -## -##The Hershey Fonts are a set of vector fonts with a liberal license. -## -##USE RESTRICTION: -## This distribution of the Hershey Fonts may be used by anyone for -## any purpose, commercial or otherwise, providing that: -## 1. The following acknowledgements must be distributed with -## the font data: -## - The Hershey Fonts were originally created by Dr. -## A. V. Hershey while working at the U. S. -## National Bureau of Standards. -## - The format of the Font data in this distribution -## was originally created by -## James Hurt -## Cognition, Inc. -## 900 Technology Park Drive -## Billerica, MA 01821 -## (mit-eddie!ci-dandelion!hurt) -## 2. The font data in this distribution may be converted into -## any other format *EXCEPT* the format distributed by -## the U.S. NTIS (which organization holds the rights -## to the distribution and use of the font data in that -## particular format). Not that anybody would really -## *want* to use their format... each point is described -## in eight bytes as "xxx yyy:", where xxx and yyy are -## the coordinate values as ASCII numbers. - - -astrology = ["-8 8","-12 12 M -8 -10 L -4 -8 L -2 -6 L -1 -3 L -1 0 L -2 3 L -4 5 L -8 7 M -8 -10 L -5 -9 L -3 -8 L -1 -6 L 0 -3 M 0 0 L -1 3 L -3 5 L -5 6 L -8 7 M 8 -10 L 5 -9 L 3 -8 L 1 -6 L 0 -3 M 0 0 L 1 3 L 3 5 L 5 6 L 8 7 M 8 -10 L 4 -8 L 2 -6 L 1 -3 L 1 0 L 2 3 L 4 5 L 8 7 M -9 -2 L 9 -2 M -9 -1 L 9 -1","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-13 14 M -1 -12 L -4 -11 L -7 -9 L -9 -6 L -10 -3 L -10 0 L -9 3 L -7 6 L -4 8 L -1 9 L 2 9 L 5 8 L 8 6 L 10 3 L 11 0 L 11 -3 L 10 -6 L 8 -9 L 5 -11 L 2 -12 L -1 -12 M 0 -3 L -1 -2 L -1 -1 L 0 0 L 1 0 L 2 -1 L 2 -2 L 1 -3 L 0 -3 M 0 -2 L 0 -1 L 1 -1 L 1 -2 L 0 -2","-8 9 M -2 -12 L -4 -11 L -3 -9 L -1 -8 M -2 -12 L -3 -11 L -3 -9 M 3 -12 L 5 -11 L 4 -9 L 2 -8 M 3 -12 L 4 -11 L 4 -9 M -1 -8 L -3 -7 L -4 -6 L -5 -4 L -5 -1 L -4 1 L -3 2 L -1 3 L 2 3 L 4 2 L 5 1 L 6 -1 L 6 -4 L 5 -6 L 4 -7 L 2 -8 L -1 -8 M 0 3 L 0 9 M 1 3 L 1 9 M -4 6 L 5 6","-9 10 M 0 -12 L -3 -11 L -5 -9 L -6 -6 L -6 -5 L -5 -2 L -3 0 L 0 1 L 1 1 L 4 0 L 6 -2 L 7 -5 L 7 -6 L 6 -9 L 4 -11 L 1 -12 L 0 -12 M 0 1 L 0 9 M 1 1 L 1 9 M -4 5 L 5 5","-14 14 M -2 -12 L -5 -11 L -8 -9 L -10 -6 L -11 -3 L -11 1 L -10 4 L -8 7 L -5 9 L -2 10 L 2 10 L 5 9 L 8 7 L 10 4 L 11 1 L 11 -3 L 10 -6 L 8 -9 L 5 -11 L 2 -12 L -2 -12 M 0 -12 L 0 10 M -11 -1 L 11 -1","-11 14 M -2 -5 L -5 -4 L -7 -2 L -8 1 L -8 2 L -7 5 L -5 7 L -2 8 L -1 8 L 2 7 L 4 5 L 5 2 L 5 1 L 4 -2 L 2 -4 L -1 -5 L -2 -5 M 11 -11 L 5 -11 L 9 -10 L 3 -4 M 11 -11 L 11 -5 L 10 -9 L 4 -3 M 10 -10 L 4 -4","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16 M 2 -14 L 0 -10 L -1 -7 L -2 -2 L -2 2 L -1 7 L 0 10 L 2 14","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 M -2 -14 L 0 -10 L 1 -7 L 2 -2 L 2 2 L 1 7 L 0 10 L -2 14","-12 10 M -9 -9 L -8 -11 L -6 -12 L -3 -12 L -1 -11 L 0 -9 L 0 -6 L -1 -3 L -2 -1 L -4 1 L -7 3 M -3 -12 L -2 -11 L -1 -9 L -1 -5 L -2 -2 L -4 1 M 4 -12 L 2 9 M 5 -12 L 1 9 M -7 3 L 7 3","-9 10 M -5 -12 L -5 3 M -4 -12 L -5 -1 M -5 -1 L -4 -3 L -3 -4 L -1 -5 L 2 -5 L 5 -4 L 6 -2 L 6 0 L 5 2 L 3 4 M 2 -5 L 4 -4 L 5 -2 L 5 0 L 2 6 L 2 8 L 3 9 L 5 9 L 7 7 M -7 -12 L -4 -12","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-9 10 M 0 -4 L -3 -3 L -5 -1 L -6 2 L -6 3 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 M 0 -10 L -4 -8 L 0 -12 L 0 -4 M 1 -10 L 5 -8 L 1 -12 L 1 -4 M 0 1 L -1 2 L -1 3 L 0 4 L 1 4 L 2 3 L 2 2 L 1 1 L 0 1 M 0 2 L 0 3 L 1 3 L 1 2 L 0 2","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 12 M -1 -10 L 0 -12 L 0 9 M 2 -10 L 1 -12 L 1 9 M -8 -10 L -7 -12 L -7 -5 L -6 -2 L -4 0 L -1 1 L 0 1 M -5 -10 L -6 -12 L -6 -4 L -5 -1 M 9 -10 L 8 -12 L 8 -5 L 7 -2 L 5 0 L 2 1 L 1 1 M 6 -10 L 7 -12 L 7 -4 L 6 -1 M -4 5 L 5 5","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 M -1 -10 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 2 7 L 4 5 L 5 3 L 6 0 L 7 -4 L 7 -8 L 6 -10 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -3 9 M -1 9 L 1 8 L 3 5 L 4 3 L 5 0 L 6 -4 L 6 -9 L 5 -11 L 4 -12","-10 11 M 2 -8 L -3 9 L -1 9 M 5 -12 L 3 -8 L -2 9 M 5 -12 L -1 9 M 5 -12 L 2 -9 L -1 -7 L -3 -6 M 2 -8 L 0 -7 L -3 -6","-10 11 M -3 -7 L -3 -8 L -2 -8 L -2 -6 L -4 -6 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 5 -3 L -5 3 L -7 5 L -9 9 M 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 L 1 -1 M 4 -12 L 5 -11 L 6 -9 L 6 -7 L 5 -5 L 3 -3 L -5 3 M -8 7 L -7 6 L -5 6 L 0 7 L 5 7 L 6 6 M -5 6 L 0 8 L 5 8 M -5 6 L 0 9 L 3 9 L 5 8 L 6 6 L 6 5","-10 11 M -3 -7 L -3 -8 L -2 -8 L -2 -6 L -4 -6 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 L 1 -2 M 6 -11 L 7 -9 L 7 -7 L 6 -5 L 5 -4 M 4 -12 L 5 -11 L 6 -9 L 6 -7 L 5 -5 L 3 -3 L 1 -2 M -1 -2 L 1 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 3 8 L 0 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -6 3 L -6 5 L -7 5 L -7 4 M 4 0 L 5 2 L 5 5 L 4 7 M 1 -2 L 3 -1 L 4 1 L 4 5 L 3 7 L 2 8 L 0 9","-10 11 M 5 -8 L 0 9 L 2 9 M 8 -12 L 6 -8 L 1 9 M 8 -12 L 2 9 M 8 -12 L -8 3 L 8 3","-10 11 M -1 -12 L -6 -2 M -1 -12 L 9 -12 M -1 -11 L 7 -11 M -2 -10 L 3 -10 L 7 -11 L 9 -12 M -6 -2 L -5 -3 L -2 -4 L 1 -4 L 4 -3 L 5 -2 L 6 0 L 6 3 L 5 6 L 3 8 L -1 9 L -4 9 L -6 8 L -7 7 L -8 5 L -8 3 L -6 3 L -6 5 L -7 5 L -7 4 M 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 M 1 -4 L 3 -3 L 4 -1 L 4 3 L 3 6 L 1 8 L -1 9","-10 11 M 7 -8 L 7 -9 L 6 -9 L 6 -7 L 8 -7 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 L -1 -3 L -3 -2 L -4 -1 L -5 1 M -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 4 6 L 5 4 L 5 1 L 4 -1 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -3 9 M 0 9 L 2 8 L 3 7 L 4 4 L 4 0 L 3 -2 L 2 -3","-10 11 M -4 -12 L -6 -6 M 9 -12 L 8 -9 L 6 -6 L 2 -1 L 0 2 L -1 5 L -2 9 M 0 1 L -2 5 L -3 9 M 6 -6 L 0 0 L -2 3 L -3 5 L -4 9 L -2 9 M -5 -9 L -2 -12 L 0 -12 L 5 -9 M -3 -11 L 0 -11 L 5 -9 M -5 -9 L -3 -10 L 0 -10 L 5 -9 L 7 -9 L 8 -10 L 9 -12","-10 11 M 1 -12 L -2 -11 L -3 -10 L -4 -8 L -4 -5 L -3 -3 L -1 -2 L 2 -2 L 5 -3 L 7 -4 L 8 -6 L 8 -9 L 7 -11 L 5 -12 L 1 -12 M 3 -12 L -2 -11 M -2 -10 L -3 -8 L -3 -4 L -2 -3 M -3 -3 L 0 -2 M 1 -2 L 5 -3 M 6 -4 L 7 -6 L 7 -9 L 6 -11 M 7 -11 L 3 -12 M 1 -12 L -1 -10 L -2 -8 L -2 -4 L -1 -2 M 2 -2 L 4 -3 L 5 -4 L 6 -6 L 6 -10 L 5 -12 M -1 -2 L -5 -1 L -7 1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 4 8 L 5 7 L 6 5 L 6 2 L 5 0 L 4 -1 L 2 -2 M 0 -2 L -5 -1 M -4 -1 L -6 1 L -7 3 L -7 6 L -6 8 M -7 8 L -2 9 L 4 8 M 4 7 L 5 5 L 5 2 L 4 0 M 4 -1 L 1 -2 M -1 -2 L -3 -1 L -5 1 L -6 3 L -6 6 L -5 8 L -4 9 M 0 9 L 2 8 L 3 7 L 4 5 L 4 1 L 3 -1 L 2 -2","-10 11 M 6 -4 L 5 -2 L 4 -1 L 2 0 L -1 0 L -3 -1 L -4 -2 L -5 -4 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 4 -12 L 6 -11 L 7 -10 L 8 -7 L 8 -4 L 7 0 L 6 3 L 4 6 L 2 8 L -1 9 L -4 9 L -6 8 L -7 6 L -7 4 L -5 4 L -5 6 L -6 6 L -6 5 M -3 -2 L -4 -4 L -4 -7 L -3 -9 M 6 -10 L 7 -8 L 7 -4 L 6 0 L 5 3 L 3 6 M -1 0 L -2 -1 L -3 -3 L -3 -7 L -2 -10 L -1 -11 L 1 -12 M 4 -12 L 5 -11 L 6 -9 L 6 -4 L 5 0 L 4 3 L 3 5 L 1 8 L -1 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -5 -1 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 3 -1 M -9 9 L 7 9 L 7 4 L 6 9","-10 9 M 7 -11 L 3 -11 L -1 -10 L -4 -8 L -6 -5 L -7 -2 L -7 1 L -6 4 L -4 7 L -1 9 L 3 10 L 7 10 M 7 -11 L 4 -10 L 1 -8 L -1 -5 L -2 -2 L -2 1 L -1 4 L 1 7 L 4 9 L 7 10","-12 13 M -3 -1 L -5 -1 L -7 0 L -8 1 L -9 3 L -9 5 L -8 7 L -7 8 L -5 9 L -3 9 L -1 8 L 0 7 L 1 5 L 1 3 L 0 1 L -1 0 L -3 -1 M 1 -10 L -2 -1 M 8 -8 L 0 0 M 10 -1 L 1 2","-10 10 M -3 -7 L 3 7 M 3 -7 L -3 7 M -7 -3 L 7 3 M 7 -3 L -7 3","-12 12 M -4 4 L -6 3 L -7 3 L -9 4 L -10 6 L -10 7 L -9 9 L -7 10 L -6 10 L -4 9 L -3 7 L -3 6 L -4 4 L -7 0 L -8 -3 L -8 -5 L -7 -8 L -5 -10 L -2 -11 L 2 -11 L 5 -10 L 7 -8 L 8 -5 L 8 -3 L 7 0 L 4 4 L 3 6 L 3 7 L 4 9 L 6 10 L 7 10 L 9 9 L 10 7 L 10 6 L 9 4 L 7 3 L 6 3 L 4 4 M -8 -5 L -7 -7 L -5 -9 L -2 -10 L 2 -10 L 5 -9 L 7 -7 L 8 -5","-12 12 M -4 -5 L -6 -4 L -7 -4 L -9 -5 L -10 -7 L -10 -8 L -9 -10 L -7 -11 L -6 -11 L -4 -10 L -3 -8 L -3 -7 L -4 -5 L -7 -1 L -8 2 L -8 4 L -7 7 L -5 9 L -2 10 L 2 10 L 5 9 L 7 7 L 8 4 L 8 2 L 7 -1 L 4 -5 L 3 -7 L 3 -8 L 4 -10 L 6 -11 L 7 -11 L 9 -10 L 10 -8 L 10 -7 L 9 -5 L 7 -4 L 6 -4 L 4 -5 M -8 4 L -7 6 L -5 8 L -2 9 L 2 9 L 5 8 L 7 6 L 8 4","-12 13 M -8 -5 L -9 -6 L -9 -8 L -8 -10 L -6 -11 L -4 -11 L -2 -10 L -1 -9 L 0 -7 L 1 -2 M -9 -8 L -7 -10 L -5 -10 L -3 -9 L -2 -8 L -1 -6 L 0 -2 L 0 9 M 9 -5 L 10 -6 L 10 -8 L 9 -10 L 7 -11 L 5 -11 L 3 -10 L 2 -9 L 1 -7 L 0 -2 M 10 -8 L 8 -10 L 6 -10 L 4 -9 L 3 -8 L 2 -6 L 1 -2 L 1 9","-10 10 M 0 -12 L -7 8 M -1 -9 L 5 9 M 0 -9 L 6 9 M 0 -12 L 7 9 M -5 3 L 4 3 M -9 9 L -3 9 M 2 9 L 9 9 M -7 8 L -8 9 M -7 8 L -5 9 M 5 8 L 3 9 M 5 7 L 4 9 M 6 7 L 8 9","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 M 6 -10 L 7 -8 L 7 -6 L 6 -4 M 3 -12 L 5 -11 L 6 -9 L 6 -5 L 5 -3 L 3 -2 M -4 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 6 0 L 7 2 L 7 5 L 6 7 M 3 -2 L 5 -1 L 6 1 L 6 6 L 5 8 L 3 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 10 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 4 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -9 9 M 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 M 1 -12 L 3 -11 L 5 -8 L 6 -4 L 6 1 L 5 5 L 3 8 L 1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 10 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 7 -12 L 7 -6 M -4 -2 L 2 -2 M 2 -6 L 2 2 M -9 9 L 7 9 L 7 3 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M 2 -12 L 7 -11 M 4 -12 L 7 -10 M 5 -12 L 7 -9 M 6 -12 L 7 -6 M 2 -6 L 1 -2 L 2 2 M 2 -4 L 0 -2 L 2 0 M 2 -3 L -2 -2 L 2 -1 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9 M 2 9 L 7 8 M 4 9 L 7 7 M 5 9 L 7 6 M 6 9 L 7 3","-11 9 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 7 -12 L 7 -6 M -4 -2 L 2 -2 M 2 -6 L 2 2 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M 2 -12 L 7 -11 M 4 -12 L 7 -10 M 5 -12 L 7 -9 M 6 -12 L 7 -6 M 2 -6 L 1 -2 L 2 2 M 2 -4 L 0 -2 L 2 0 M 2 -3 L -2 -2 L 2 -1 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 12 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 2 9 L 4 8 L 6 8 L 7 9 L 7 1 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 6 2 L 6 7 M 5 1 L 5 7 L 4 8 M 2 1 L 10 1 M 3 1 L 5 2 M 4 1 L 5 3 M 8 1 L 7 3 M 9 1 L 7 2","-12 12 M -7 -12 L -7 9 M -6 -11 L -6 8 M -5 -12 L -5 9 M 5 -12 L 5 9 M 6 -11 L 6 8 M 7 -12 L 7 9 M -10 -12 L -2 -12 M 2 -12 L 10 -12 M -5 -2 L 5 -2 M -10 9 L -2 9 M 2 9 L 10 9 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 3 -12 L 5 -11 M 4 -12 L 5 -10 M 8 -12 L 7 -10 M 9 -12 L 7 -11 M -7 8 L -9 9 M -7 7 L -8 9 M -5 7 L -4 9 M -5 8 L -3 9 M 5 8 L 3 9 M 5 7 L 4 9 M 7 7 L 8 9 M 7 8 L 9 9","-6 6 M -1 -12 L -1 9 M 0 -11 L 0 8 M 1 -12 L 1 9 M -4 -12 L 4 -12 M -4 9 L 4 9 M -3 -12 L -1 -11 M -2 -12 L -1 -10 M 2 -12 L 1 -10 M 3 -12 L 1 -11 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-8 8 M 1 -12 L 1 5 L 0 8 L -1 9 M 2 -11 L 2 5 L 1 8 M 3 -12 L 3 5 L 2 8 L -1 9 L -3 9 L -5 8 L -6 6 L -6 4 L -5 3 L -4 3 L -3 4 L -3 5 L -4 6 L -5 6 M -5 4 L -5 5 L -4 5 L -4 4 L -5 4 M -2 -12 L 6 -12 M -1 -12 L 1 -11 M 0 -12 L 1 -10 M 4 -12 L 3 -10 M 5 -12 L 3 -11","-12 10 M -7 -12 L -7 9 M -6 -11 L -6 8 M -5 -12 L -5 9 M 6 -11 L -5 0 M -2 -2 L 5 9 M -1 -2 L 6 9 M -1 -4 L 7 9 M -10 -12 L -2 -12 M 3 -12 L 9 -12 M -10 9 L -2 9 M 2 9 L 9 9 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 6 -11 M 8 -12 L 6 -11 M -7 8 L -9 9 M -7 7 L -8 9 M -5 7 L -4 9 M -5 8 L -3 9 M 5 7 L 3 9 M 5 7 L 8 9","-9 9 M -4 -12 L -4 9 M -3 -11 L -3 8 M -2 -12 L -2 9 M -7 -12 L 1 -12 M -7 9 L 8 9 L 8 3 M -6 -12 L -4 -11 M -5 -12 L -4 -10 M -1 -12 L -2 -10 M 0 -12 L -2 -11 M -4 8 L -6 9 M -4 7 L -5 9 M -2 7 L -1 9 M -2 8 L 0 9 M 3 9 L 8 8 M 5 9 L 8 7 M 6 9 L 8 6 M 7 9 L 8 3","-13 13 M -8 -12 L -8 8 M -8 -12 L -1 9 M -7 -12 L -1 6 M -6 -12 L 0 6 M 6 -12 L -1 9 M 6 -12 L 6 9 M 7 -11 L 7 8 M 8 -12 L 8 9 M -11 -12 L -6 -12 M 6 -12 L 11 -12 M -11 9 L -5 9 M 3 9 L 11 9 M -10 -12 L -8 -11 M 9 -12 L 8 -10 M 10 -12 L 8 -11 M -8 8 L -10 9 M -8 8 L -6 9 M 6 8 L 4 9 M 6 7 L 5 9 M 8 7 L 9 9 M 8 8 L 10 9","-12 12 M -7 -12 L -7 8 M -7 -12 L 7 9 M -6 -12 L 6 6 M -5 -12 L 7 6 M 7 -11 L 7 9 M -10 -12 L -5 -12 M 4 -12 L 10 -12 M -10 9 L -4 9 M -9 -12 L -7 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11 M -7 8 L -9 9 M -7 8 L -5 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M 5 6 L 6 4 L 7 1 L 7 -4 L 6 -7 L 5 -9 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 1 9 L 3 8 L 5 5 L 6 1 L 6 -4 L 5 -8 L 3 -11 L 1 -12","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -4 -1 M 6 -10 L 7 -8 L 7 -5 L 6 -3 M 3 -12 L 5 -11 L 6 -9 L 6 -4 L 5 -2 L 3 -1 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M 5 6 L 6 4 L 7 1 L 7 -4 L 6 -7 L 5 -9 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 1 9 L 3 8 L 5 5 L 6 1 L 6 -4 L 5 -8 L 3 -11 L 1 -12 M -4 6 L -3 4 L -1 3 L 0 3 L 2 4 L 3 6 L 4 12 L 5 14 L 7 14 L 8 12 L 8 10 M 4 10 L 5 12 L 6 13 L 7 13 M 3 6 L 5 11 L 6 12 L 7 12 L 8 11","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 L -4 -2 M 6 -10 L 7 -8 L 7 -6 L 6 -4 M 3 -12 L 5 -11 L 6 -9 L 6 -5 L 5 -3 L 3 -2 M 0 -2 L 2 -1 L 3 1 L 5 7 L 6 9 L 8 9 L 9 7 L 9 5 M 5 5 L 6 7 L 7 8 L 8 8 M 2 -1 L 3 0 L 6 6 L 7 7 L 8 7 L 9 6 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-10 10 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 1 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -1 9 L -4 8 L -6 6 L -7 3 L -7 9 L -6 6","-10 10 M -8 -12 L -8 -6 M -1 -12 L -1 9 M 0 -11 L 0 8 M 1 -12 L 1 9 M 8 -12 L 8 -6 M -8 -12 L 8 -12 M -4 9 L 4 9 M -7 -12 L -8 -6 M -6 -12 L -8 -9 M -5 -12 L -8 -10 M -3 -12 L -8 -11 M 3 -12 L 8 -11 M 5 -12 L 8 -10 M 6 -12 L 8 -9 M 7 -12 L 8 -6 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-12 12 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -11 M -6 -11 L -6 4 L -5 6 M -5 -12 L -5 4 L -4 7 L -3 8 L -1 9 M -10 -12 L -2 -12 M 4 -12 L 10 -12 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11","-10 10 M -7 -12 L 0 9 M -6 -12 L 0 6 L 0 9 M -5 -12 L 1 6 M 7 -11 L 0 9 M -9 -12 L -2 -12 M 3 -12 L 9 -12 M -8 -12 L -6 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 7 -11 M 8 -12 L 7 -11","-12 12 M -8 -12 L -4 9 M -7 -12 L -4 4 L -4 9 M -6 -12 L -3 4 M 0 -12 L -3 4 L -4 9 M 0 -12 L 4 9 M 1 -12 L 4 4 L 4 9 M 2 -12 L 5 4 M 8 -11 L 5 4 L 4 9 M -11 -12 L -3 -12 M 0 -12 L 2 -12 M 5 -12 L 11 -12 M -10 -12 L -7 -11 M -9 -12 L -7 -10 M -5 -12 L -6 -10 M -4 -12 L -6 -11 M 6 -12 L 8 -11 M 10 -12 L 8 -11","-10 10 M -7 -12 L 5 9 M -6 -12 L 6 9 M -5 -12 L 7 9 M 6 -11 L -6 8 M -9 -12 L -2 -12 M 3 -12 L 9 -12 M -9 9 L -3 9 M 2 9 L 9 9 M -8 -12 L -5 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 4 -12 L 6 -11 M 8 -12 L 6 -11 M -6 8 L -8 9 M -6 8 L -4 9 M 5 8 L 3 9 M 5 7 L 4 9 M 5 7 L 8 9","-11 11 M -8 -12 L -1 -1 L -1 9 M -7 -12 L 0 -1 L 0 8 M -6 -12 L 1 -1 L 1 9 M 7 -11 L 1 -1 M -10 -12 L -3 -12 M 4 -12 L 10 -12 M -4 9 L 4 9 M -9 -12 L -7 -11 M -4 -12 L -6 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-10 10 M 7 -12 L -7 -12 L -7 -6 M 5 -12 L -7 9 M 6 -12 L -6 9 M 7 -12 L -5 9 M -7 9 L 7 9 L 7 3 M -6 -12 L -7 -6 M -5 -12 L -7 -9 M -4 -12 L -7 -10 M -2 -12 L -7 -11 M 2 9 L 7 8 M 4 9 L 7 7 M 5 9 L 7 6 M 6 9 L 7 3","-12 12 M -9 -11 L -8 -7 L -7 -5 L -5 -3 L -2 -2 L 2 -2 L 5 -3 L 7 -5 L 8 -7 L 9 -11 M -9 -11 L -8 -8 L -7 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 7 -6 L 8 -8 L 9 -11 M -2 -3 L -4 -2 L -5 -1 L -6 1 L -6 4 L -5 6 L -3 8 L -1 9 L 1 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 M -2 -2 L -4 -1 L -5 1 L -5 4 L -4 7 M 4 7 L 5 4 L 5 1 L 4 -1 L 2 -2","-7 7 M -7 -12 L 7 12","-12 12 M -5 -8 L -5 4 M -4 -7 L -4 3 M 4 -7 L 4 3 M 5 -8 L 5 4 M -9 -11 L -7 -9 L -5 -8 L -2 -7 L 2 -7 L 5 -8 L 7 -9 L 9 -11 M -9 7 L -7 5 L -5 4 L -2 3 L 2 3 L 5 4 L 7 5 L 9 7","-12 12 M 9 -9 L -6 -9 L -8 -8 L -9 -6 L -9 -4 L -8 -2 L -6 -1 L -4 -1 L -2 -2 L -1 -4 L -1 -6 L -2 -8 L 9 -8 M -9 -5 L -8 -3 L -7 -2 L -5 -1 M -1 -5 L -2 -7 L -3 -8 L -5 -9 M -9 6 L 6 6 L 8 5 L 9 3 L 9 1 L 8 -1 L 6 -2 L 4 -2 L 2 -1 L 1 1 L 1 3 L 2 5 L -9 5 M 9 2 L 8 0 L 7 -1 L 5 -2 M 1 2 L 2 4 L 3 5 L 5 6","-12 11 M -3 3 L -5 2 L -6 2 L -8 3 L -9 5 L -9 6 L -8 8 L -6 9 L -5 9 L -3 8 L -2 6 L -2 5 L -3 3 L -8 -2 L -9 -4 L -9 -7 L -8 -9 L -6 -10 L -3 -11 L 1 -11 L 5 -10 L 7 -8 L 8 -6 L 8 -3 L 7 0 L 4 3 L 3 5 L 3 7 L 4 9 L 6 9 L 7 8 L 8 6 M -5 1 L -7 -2 L -8 -4 L -8 -7 L -7 -9 L -6 -10 M 1 -11 L 4 -10 L 6 -8 L 7 -6 L 7 -3 L 6 0 L 4 3","-11 13 M -10 -7 L -7 -10 L -5 -7 L -5 4 M -8 -9 L -6 -6 L -6 4 M -5 -7 L -2 -10 L 0 -7 L 0 3 M -3 -9 L -1 -6 L -1 3 M 0 -7 L 3 -10 L 5 -7 L 5 9 M 2 -9 L 4 -6 L 4 9 M 5 -7 L 8 -10 L 9 -8 L 10 -5 L 10 -2 L 9 1 L 8 3 L 6 5 L 3 7 L -2 9 M 7 -9 L 8 -8 L 9 -5 L 9 -2 L 8 1 L 7 3 L 5 5 L 2 7 L -2 9","-11 11 M 5 -5 L 3 2 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M 6 -5 L 4 2 L 4 8 M 5 -5 L 7 -5 L 5 2 L 4 6 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9","-9 10 M -2 -12 L -4 -5 L -5 1 L -5 5 L -4 7 L -3 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 2 L 7 0 L 6 -3 L 5 -4 L 3 -5 L 1 -5 L -1 -4 L -2 -3 L -3 -1 L -4 2 M -1 -12 L -3 -5 L -4 -1 L -4 5 L -3 8 M 4 7 L 5 5 L 6 2 L 6 -1 L 5 -3 M -5 -12 L 0 -12 L -2 -5 L -4 2 M 1 9 L 3 7 L 4 5 L 5 2 L 5 -1 L 4 -4 L 3 -5 M -4 -12 L -1 -11 M -3 -12 L -2 -10","-9 9 M 5 -1 L 5 -2 L 4 -2 L 4 0 L 6 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 M -3 -3 L -4 -1 L -5 2 L -5 5 L -4 7 M 0 -5 L -2 -3 L -3 -1 L -4 2 L -4 5 L -3 8 L -2 9","-11 11 M 7 -12 L 4 -1 L 3 3 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M 8 -12 L 5 -1 L 4 3 L 4 8 M 4 -12 L 9 -12 L 5 2 L 4 6 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -5 -3 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9 M 5 -12 L 8 -11 M 6 -12 L 7 -10","-9 9 M -5 4 L -1 3 L 2 2 L 5 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 M -3 -3 L -4 -1 L -5 2 L -5 5 L -4 7 M 0 -5 L -2 -3 L -3 -1 L -4 2 L -4 5 L -3 8 L -2 9","-8 8 M 8 -10 L 8 -11 L 7 -11 L 7 -9 L 9 -9 L 9 -11 L 8 -12 L 6 -12 L 4 -11 L 2 -9 L 1 -7 L 0 -4 L -1 0 L -3 9 L -4 12 L -5 14 L -7 16 M 2 -8 L 1 -5 L 0 0 L -2 9 L -3 12 M 6 -12 L 4 -10 L 3 -8 L 2 -5 L 1 0 L -1 8 L -2 11 L -3 13 L -5 15 L -7 16 L -9 16 L -10 15 L -10 13 L -8 13 L -8 15 L -9 15 L -9 14 M -4 -5 L 7 -5","-10 11 M 6 -5 L 2 9 L 1 12 L -1 15 L -3 16 M 7 -5 L 3 9 L 1 13 M 6 -5 L 8 -5 L 4 9 L 2 13 L 0 15 L -3 16 L -6 16 L -8 15 L -9 14 L -9 12 L -7 12 L -7 14 L -8 14 L -8 13 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 L 3 5 L 4 2 M -4 -3 L -5 -1 L -6 2 L -6 5 L -5 7 M -1 -5 L -3 -3 L -4 -1 L -5 2 L -5 5 L -4 8 L -3 9","-11 11 M -3 -12 L -9 9 L -7 9 M -2 -12 L -8 9 M -6 -12 L -1 -12 L -7 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -2 L 6 1 L 4 6 M 5 -4 L 5 0 L 4 4 L 4 8 M 5 -2 L 3 3 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M -5 -12 L -2 -11 M -4 -12 L -3 -10","-7 6 M 1 -12 L 1 -10 L 3 -10 L 3 -12 L 1 -12 M 2 -12 L 2 -10 M 1 -11 L 3 -11 M -6 -1 L -5 -3 L -3 -5 L -1 -5 L 0 -4 L 1 -2 L 1 1 L -1 6 M 0 -4 L 0 0 L -1 4 L -1 8 M 0 -2 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5","-7 6 M 3 -12 L 3 -10 L 5 -10 L 5 -12 L 3 -12 M 4 -12 L 4 -10 M 3 -11 L 5 -11 M -5 -1 L -4 -3 L -2 -5 L 0 -5 L 1 -4 L 2 -2 L 2 1 L 0 8 L -1 11 L -2 13 L -4 15 L -6 16 L -8 16 L -9 15 L -9 13 L -7 13 L -7 15 L -8 15 L -8 14 M 1 -4 L 1 1 L -1 8 L -2 11 L -3 13 M 1 -2 L 0 2 L -2 9 L -3 12 L -4 14 L -6 16","-11 11 M -3 -12 L -9 9 L -7 9 M -2 -12 L -8 9 M -6 -12 L -1 -12 L -7 9 M 7 -3 L 7 -4 L 6 -4 L 6 -2 L 8 -2 L 8 -4 L 7 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 M -5 1 L -3 1 L -1 2 L 0 3 L 2 7 L 3 8 L 5 8 M -1 3 L 1 7 L 2 8 M -3 1 L -2 2 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 M -5 -12 L -2 -11 M -4 -12 L -3 -10","-6 6 M 2 -12 L -1 -1 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5 M 3 -12 L 0 -1 L -1 3 L -1 8 M -1 -12 L 4 -12 L 0 2 L -1 6 M 0 -12 L 3 -11 M 1 -12 L 2 -10","-18 17 M -17 -1 L -16 -3 L -14 -5 L -12 -5 L -11 -4 L -10 -2 L -10 1 L -12 9 M -11 -4 L -11 1 L -13 9 M -11 -2 L -12 2 L -14 9 L -12 9 M -10 1 L -8 -2 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -2 L 1 1 L -1 9 M 0 -4 L 0 1 L -2 9 M 0 -2 L -1 2 L -3 9 L -1 9 M 1 1 L 3 -2 L 5 -4 L 7 -5 L 9 -5 L 11 -4 L 12 -2 L 12 1 L 10 6 M 11 -4 L 11 0 L 10 4 L 10 8 M 11 -2 L 9 3 L 9 6 L 10 8 L 11 9 L 13 9 L 15 7 L 16 5","-12 12 M -11 -1 L -10 -3 L -8 -5 L -6 -5 L -5 -4 L -4 -2 L -4 1 L -6 9 M -5 -4 L -5 1 L -7 9 M -5 -2 L -6 2 L -8 9 L -6 9 M -4 1 L -2 -2 L 0 -4 L 2 -5 L 4 -5 L 6 -4 L 7 -2 L 7 1 L 5 6 M 6 -4 L 6 0 L 5 4 L 5 8 M 6 -2 L 4 3 L 4 6 L 5 8 L 6 9 L 8 9 L 10 7 L 11 5","-10 10 M -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 4 L -6 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 5 L 7 2 L 7 0 L 6 -3 L 5 -4 L 2 -5 L -1 -5 M -4 -3 L -5 -1 L -6 2 L -6 5 L -5 7 M 4 7 L 5 5 L 6 2 L 6 -1 L 5 -3 M -1 -5 L -3 -3 L -4 -1 L -5 2 L -5 5 L -4 8 L -2 9 M 1 9 L 3 7 L 4 5 L 5 2 L 5 -1 L 4 -4 L 2 -5","-11 11 M -10 -1 L -9 -3 L -7 -5 L -5 -5 L -4 -4 L -3 -2 L -3 1 L -4 5 L -7 16 M -4 -4 L -4 1 L -5 5 L -8 16 M -4 -2 L -5 2 L -9 16 M -3 2 L -2 -1 L -1 -3 L 0 -4 L 2 -5 L 4 -5 L 6 -4 L 7 -3 L 8 0 L 8 2 L 7 5 L 5 8 L 2 9 L 0 9 L -2 8 L -3 5 L -3 2 M 6 -3 L 7 -1 L 7 2 L 6 5 L 5 7 M 4 -5 L 5 -4 L 6 -1 L 6 2 L 5 5 L 4 7 L 2 9 M -12 16 L -4 16 M -8 15 L -11 16 M -8 14 L -10 16 M -7 14 L -6 16 M -8 15 L -5 16","-11 10 M 5 -5 L -1 16 M 6 -5 L 0 16 M 5 -5 L 7 -5 L 1 16 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -5 -3 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9 M -4 16 L 4 16 M 0 15 L -3 16 M 0 14 L -2 16 M 1 14 L 2 16 M 0 15 L 3 16","-9 9 M -8 -1 L -7 -3 L -5 -5 L -3 -5 L -2 -4 L -1 -2 L -1 2 L -3 9 M -2 -4 L -2 2 L -4 9 M -2 -2 L -3 2 L -5 9 L -3 9 M 7 -3 L 7 -4 L 6 -4 L 6 -2 L 8 -2 L 8 -4 L 7 -5 L 5 -5 L 3 -4 L 1 -2 L -1 2","-8 9 M 6 -2 L 6 -3 L 5 -3 L 5 -1 L 7 -1 L 7 -3 L 6 -4 L 3 -5 L 0 -5 L -3 -4 L -4 -3 L -4 -1 L -3 1 L -1 2 L 2 3 L 4 4 L 5 6 M -3 -4 L -4 -1 M -3 0 L -1 1 L 2 2 L 4 3 M 5 4 L 4 8 M -4 -3 L -3 -1 L -1 0 L 2 1 L 4 2 L 5 4 L 5 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -6 5 L -4 5 L -4 7 L -5 7 L -5 6","-7 7 M 2 -12 L -1 -1 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5 M 3 -12 L 0 -1 L -1 3 L -1 8 M 2 -12 L 4 -12 L 0 2 L -1 6 M -4 -5 L 6 -5","-12 12 M -11 -1 L -10 -3 L -8 -5 L -6 -5 L -5 -4 L -4 -2 L -4 1 L -6 6 M -5 -4 L -5 0 L -6 4 L -6 8 M -5 -2 L -7 3 L -7 6 L -6 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 3 M 6 -5 L 4 3 L 4 6 L 5 8 L 6 9 L 8 9 L 10 7 L 11 5 M 7 -5 L 5 3 L 5 8 M 6 -5 L 8 -5 L 6 2 L 5 6","-10 10 M -9 -1 L -8 -3 L -6 -5 L -4 -5 L -3 -4 L -2 -2 L -2 1 L -4 6 M -3 -4 L -3 0 L -4 4 L -4 8 M -3 -2 L -5 3 L -5 6 L -4 8 L -2 9 L 0 9 L 2 8 L 4 6 L 6 3 L 7 -1 L 7 -5 L 6 -5 L 6 -4 L 7 -2","-15 15 M -14 -1 L -13 -3 L -11 -5 L -9 -5 L -8 -4 L -7 -2 L -7 1 L -9 6 M -8 -4 L -8 0 L -9 4 L -9 8 M -8 -2 L -10 3 L -10 6 L -9 8 L -7 9 L -5 9 L -3 8 L -1 6 L 0 3 M 2 -5 L 0 3 L 0 6 L 1 8 L 3 9 L 5 9 L 7 8 L 9 6 L 11 3 L 12 -1 L 12 -5 L 11 -5 L 11 -4 L 12 -2 M 3 -5 L 1 3 L 1 8 M 2 -5 L 4 -5 L 2 2 L 1 6","-11 11 M -8 -1 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -2 L 1 0 M -2 -5 L -1 -4 L -1 0 L -2 4 L -3 6 L -5 8 L -7 9 L -9 9 L -10 8 L -10 6 L -8 6 L -8 8 L -9 8 L -9 7 M 0 -3 L 0 0 L -1 4 L -1 7 M 8 -3 L 8 -4 L 7 -4 L 7 -2 L 9 -2 L 9 -4 L 8 -5 L 6 -5 L 4 -4 L 2 -2 L 1 0 L 0 4 L 0 8 L 1 9 M -2 4 L -2 6 L -1 8 L 1 9 L 3 9 L 5 8 L 7 5","-11 11 M -10 -1 L -9 -3 L -7 -5 L -5 -5 L -4 -4 L -3 -2 L -3 1 L -5 6 M -4 -4 L -4 0 L -5 4 L -5 8 M -4 -2 L -6 3 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 3 6 L 5 2 M 7 -5 L 3 9 L 2 12 L 0 15 L -2 16 M 8 -5 L 4 9 L 2 13 M 7 -5 L 9 -5 L 5 9 L 3 13 L 1 15 L -2 16 L -5 16 L -7 15 L -8 14 L -8 12 L -6 12 L -6 14 L -7 14 L -7 13","-10 10 M 7 -5 L 6 -3 L 4 -1 L -4 5 L -6 7 L -7 9 M 6 -3 L -3 -3 L -5 -2 L -6 0 M 4 -3 L 0 -4 L -3 -4 L -4 -3 M 4 -3 L 0 -5 L -3 -5 L -5 -3 L -6 0 M -6 7 L 3 7 L 5 6 L 6 4 M -4 7 L 0 8 L 3 8 L 4 7 M -4 7 L 0 9 L 3 9 L 5 7 L 6 4","-12 13 M -11 -6 L -8 -9 L -5 -6 L -5 6 M -9 -8 L -6 -5 L -6 6 M -5 -6 L -2 -9 L 1 -6 L 1 6 M -3 -8 L 0 -5 L 0 6 M 1 -6 L 4 -9 L 7 -6 L 7 5 L 9 7 M 3 -8 L 6 -5 L 6 6 L 8 8 L 11 5","-11 11 M 8 -9 L -8 7 M 8 -9 L 5 -8 L -1 -8 M 6 -7 L 3 -7 L -1 -8 M 8 -9 L 7 -6 L 7 0 M 6 -7 L 6 -4 L 7 0 M -1 0 L -8 0 M -2 1 L -5 1 L -8 0 M -1 0 L -1 7 M -2 1 L -2 4 L -1 7","-12 12 M -10 -3 L -8 -7 L -3 3 M -8 -5 L -3 5 L 0 -2 L 5 -2 L 8 -3 L 9 -5 L 9 -7 L 8 -9 L 6 -10 L 5 -10 L 3 -9 L 2 -7 L 2 -5 L 3 -2 L 4 0 L 5 3 L 5 6 L 3 8 M 5 -10 L 4 -9 L 3 -7 L 3 -5 L 5 -1 L 6 2 L 6 5 L 5 7 L 3 8","-12 12 M -9 -3 L -6 -6 L -2 -4 M -7 -5 L -3 -3 L 0 -6 L 3 -4 M -1 -5 L 2 -3 L 5 -6 L 7 -4 M 4 -5 L 6 -3 L 9 -6 M -9 3 L -6 0 L -2 2 M -7 1 L -3 3 L 0 0 L 3 2 M -1 1 L 2 3 L 5 0 L 7 2 M 4 1 L 6 3 L 9 0","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -cursive = ["-8 8","-5 5 M 0 -12 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -4 -12 L -4 -5 M 4 -12 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -6 9 L -8 8 L -9 7 L -10 5 L -10 3 L -9 1 L -8 0 L -1 -4 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 7 9 L 9 9 L 10 8 L 10 7","-2 2 M 0 -5 L 0 -1","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-11 9 M -11 9 L -9 8 L -6 5 L -3 1 L 1 -6 L 4 -12 L 4 9 L 3 6 L 1 3 L -1 1 L -4 -1 L -6 -1 L -7 0 L -7 2 L -6 4 L -4 6 L -1 8 L 2 9 L 7 9","-12 11 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 6 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 5 -3 L 2 -2 M 1 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9 L 0 9 L -2 8 L -3 6","-10 10 M 2 -6 L 2 -5 L 3 -4 L 5 -4 L 7 -5 L 8 -7 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -4 L -7 0 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 5 4","-11 12 M 2 -12 L 0 -11 L -1 -9 L -2 -5 L -3 1 L -4 4 L -5 6 L -7 8 L -9 9 L -11 9 L -12 8 L -12 6 L -11 5 L -9 5 L -7 6 L -5 8 L -2 9 L 1 9 L 4 8 L 6 6 L 8 2 L 9 -3 L 9 -7 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L 0 -10 L 0 -8 L 1 -5 L 3 -2 L 5 0 L 8 2 L 10 3","-10 10 M 4 -8 L 4 -7 L 5 -6 L 7 -6 L 8 -7 L 8 -9 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -4 -9 L -4 -6 L -3 -4 L -2 -3 L 1 -2 L -2 -2 L -5 -1 L -6 0 L -7 2 L -7 5 L -6 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 6 L 7 4","-10 10 M 0 -6 L -2 -6 L -4 -7 L -5 -9 L -4 -11 L -1 -12 L 2 -12 L 6 -11 L 9 -11 L 11 -12 M 6 -11 L 4 -4 L 2 2 L 0 6 L -2 8 L -4 9 L -6 9 L -8 8 L -9 6 L -9 4 L -8 3 L -6 3 L -4 4 M -1 -2 L 8 -2","-11 12 M -11 9 L -9 8 L -5 4 L -2 -1 L -1 -4 L 0 -8 L 0 -11 L -1 -12 L -2 -12 L -3 -11 L -4 -9 L -4 -6 L -3 -4 L -1 -3 L 3 -3 L 6 -4 L 7 -5 L 8 -7 L 8 -1 L 7 4 L 6 6 L 4 8 L 1 9 L -3 9 L -6 8 L -8 6 L -9 4 L -9 2","-12 12 M -5 -5 L -7 -6 L -8 -8 L -8 -9 L -7 -11 L -5 -12 L -4 -12 L -2 -11 L -1 -9 L -1 -7 L -2 -3 L -4 3 L -6 7 L -8 9 L -10 9 L -11 8 L -11 6 M -5 0 L 4 -3 L 6 -4 L 9 -6 L 11 -8 L 12 -10 L 12 -11 L 11 -12 L 10 -12 L 8 -10 L 6 -6 L 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-9 8 M 5 4 L 3 2 L 1 -1 L 0 -3 L -1 -6 L -1 -9 L 0 -11 L 1 -12 L 3 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -1 L 2 4 L 1 6 L -1 8 L -3 9 L -5 9 L -7 8 L -8 6 L -8 4 L -7 3 L -5 3 L -3 4","-8 7 M 2 12 L 0 9 L -2 4 L -3 -2 L -3 -8 L -2 -11 L 0 -12 L 2 -12 L 3 -11 L 4 -8 L 4 -5 L 3 0 L 0 9 L -2 15 L -3 18 L -4 20 L -6 21 L -7 20 L -7 18 L -6 15 L -4 12 L -2 10 L 1 8 L 5 6","-12 12 M -5 -5 L -7 -6 L -8 -8 L -8 -9 L -7 -11 L -5 -12 L -4 -12 L -2 -11 L -1 -9 L -1 -7 L -2 -3 L -4 3 L -6 7 L -8 9 L -10 9 L -11 8 L -11 6 M 12 -9 L 12 -11 L 11 -12 L 10 -12 L 8 -11 L 6 -9 L 4 -6 L 2 -4 L 0 -3 L -2 -3 M 0 -3 L 1 -1 L 1 6 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-9 10 M -5 0 L -3 0 L 1 -1 L 4 -3 L 6 -5 L 7 -7 L 7 -10 L 6 -12 L 4 -12 L 3 -11 L 2 -9 L 1 -4 L 0 1 L -1 4 L -2 6 L -4 8 L -6 9 L -8 9 L -9 8 L -9 6 L -8 5 L -6 5 L -4 6 L -1 8 L 2 9 L 4 9 L 7 8 L 9 6","-18 15 M -13 -5 L -15 -6 L -16 -8 L -16 -9 L -15 -11 L -13 -12 L -12 -12 L -10 -11 L -9 -9 L -9 -7 L -10 -2 L -11 2 L -13 9 M -11 2 L -8 -6 L -6 -10 L -5 -11 L -3 -12 L -2 -12 L 0 -11 L 1 -9 L 1 -7 L 0 -2 L -1 2 L -3 9 M -1 2 L 2 -6 L 4 -10 L 5 -11 L 7 -12 L 8 -12 L 10 -11 L 11 -9 L 11 -7 L 10 -2 L 8 5 L 8 8 L 9 9 L 10 9 L 12 8 L 13 7 L 15 4","-13 11 M -8 -5 L -10 -6 L -11 -8 L -11 -9 L -10 -11 L -8 -12 L -7 -12 L -5 -11 L -4 -9 L -4 -7 L -5 -2 L -6 2 L -8 9 M -6 2 L -3 -6 L -1 -10 L 0 -11 L 2 -12 L 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -2 L 4 5 L 4 8 L 5 9 L 6 9 L 8 8 L 9 7 L 11 4","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -4 L -7 0 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 1 L 8 -3 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 L 0 -10 L 0 -7 L 1 -4 L 3 -1 L 5 1 L 8 3 L 10 4","-12 13 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 8 -12 L 10 -11 L 11 -10 L 12 -8 L 12 -5 L 11 -3 L 10 -2 L 8 -1 L 5 -1 L 3 -2 L 2 -3","-10 12 M 3 -6 L 2 -4 L 1 -3 L -1 -2 L -3 -2 L -4 -4 L -4 -6 L -3 -9 L -1 -11 L 2 -12 L 5 -12 L 7 -11 L 8 -9 L 8 -5 L 7 -2 L 5 1 L 1 5 L -2 7 L -4 8 L -7 9 L -9 9 L -10 8 L -10 6 L -9 5 L -7 5 L -5 6 L -2 8 L 1 9 L 4 9 L 7 8 L 9 6","-12 13 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 7 -12 L 9 -11 L 10 -10 L 11 -8 L 11 -5 L 10 -3 L 9 -2 L 7 -1 L 4 -1 L 1 -2 L 2 -1 L 3 1 L 3 6 L 4 8 L 6 9 L 8 8 L 9 7 L 11 4","-10 10 M -10 9 L -8 8 L -6 6 L -3 2 L -1 -1 L 1 -5 L 2 -8 L 2 -11 L 1 -12 L 0 -12 L -1 -11 L -2 -9 L -2 -7 L -1 -5 L 1 -3 L 4 -1 L 6 1 L 7 3 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6 L -8 4 L -8 2","-10 9 M 0 -6 L -2 -6 L -4 -7 L -5 -9 L -4 -11 L -1 -12 L 2 -12 L 6 -11 L 9 -11 L 11 -12 M 6 -11 L 4 -4 L 2 2 L 0 6 L -2 8 L -4 9 L -6 9 L -8 8 L -9 6 L -9 4 L -8 3 L -6 3 L -4 4","-13 11 M -8 -5 L -10 -6 L -11 -8 L -11 -9 L -10 -11 L -8 -12 L -7 -12 L -5 -11 L -4 -9 L -4 -7 L -5 -3 L -6 0 L -7 4 L -7 6 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 3 3 L 6 -5 L 8 -12 M 6 -5 L 5 -1 L 4 5 L 4 8 L 5 9 L 6 9 L 8 8 L 9 7 L 11 4","-12 11 M -7 -5 L -9 -6 L -10 -8 L -10 -9 L -9 -11 L -7 -12 L -6 -12 L -4 -11 L -3 -9 L -3 -7 L -4 -3 L -5 0 L -6 4 L -6 7 L -5 9 L -3 9 L -1 8 L 2 5 L 4 2 L 6 -2 L 7 -5 L 8 -9 L 8 -11 L 7 -12 L 6 -12 L 5 -11 L 4 -9 L 4 -7 L 5 -4 L 7 -2 L 9 -1","-15 13 M -10 -5 L -12 -6 L -13 -8 L -13 -9 L -12 -11 L -10 -12 L -9 -12 L -7 -11 L -6 -9 L -6 -6 L -7 9 M 3 -12 L -7 9 M 3 -12 L 1 9 M 15 -12 L 13 -11 L 10 -8 L 7 -4 L 4 2 L 1 9","-12 12 M -4 -6 L -6 -6 L -7 -7 L -7 -9 L -6 -11 L -4 -12 L -2 -12 L 0 -11 L 1 -9 L 1 -6 L -1 3 L -1 6 L 0 8 L 2 9 L 4 9 L 6 8 L 7 6 L 7 4 L 6 3 L 4 3 M 11 -9 L 11 -11 L 10 -12 L 8 -12 L 6 -11 L 4 -9 L 2 -6 L -2 3 L -4 6 L -6 8 L -8 9 L -10 9 L -11 8 L -11 6","-12 11 M -7 -5 L -9 -6 L -10 -8 L -10 -9 L -9 -11 L -7 -12 L -6 -12 L -4 -11 L -3 -9 L -3 -7 L -4 -3 L -5 0 L -6 4 L -6 6 L -5 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 3 L 5 1 L 7 -5 M 9 -12 L 7 -5 L 4 5 L 2 11 L 0 16 L -2 20 L -4 21 L -5 20 L -5 18 L -4 15 L -2 12 L 1 9 L 4 7 L 9 4","-10 11 M 3 -6 L 2 -4 L 1 -3 L -1 -2 L -3 -2 L -4 -4 L -4 -6 L -3 -9 L -1 -11 L 2 -12 L 5 -12 L 7 -11 L 8 -9 L 8 -5 L 7 -2 L 5 2 L 2 5 L -2 8 L -4 9 L -7 9 L -8 8 L -8 6 L -7 5 L -4 5 L -2 6 L -1 7 L 0 9 L 0 12 L -1 15 L -2 17 L -4 20 L -6 21 L -7 20 L -7 18 L -6 15 L -4 12 L -1 9 L 2 7 L 8 4","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-8 8 M 0 -14 L -8 0 M 0 -14 L 8 0","-11 9 M -11 16 L 9 16","-4 4 M 1 -7 L -1 -5 L -1 -3 L 0 -2 L 1 -3 L 0 -4 L -1 -3","-6 10 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 L 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-5 9 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 2 L -4 8 L -3 9 L -2 9 L 0 8 L 2 6 L 3 3 L 3 0 L 4 4 L 5 5 L 7 5 L 9 4","-5 6 M 2 2 L 2 1 L 1 0 L -1 0 L -3 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9 L 1 9 L 4 7 L 6 4","-6 10 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 L 8 -12 M 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-4 6 M -3 7 L -1 6 L 0 5 L 1 3 L 1 1 L 0 0 L -1 0 L -3 1 L -4 3 L -4 6 L -3 8 L -1 9 L 1 9 L 3 8 L 4 7 L 6 4","-3 5 M -3 4 L 1 -1 L 3 -4 L 4 -6 L 5 -9 L 5 -11 L 4 -12 L 2 -11 L 1 -9 L -1 -1 L -4 8 L -7 15 L -8 18 L -8 20 L -7 21 L -5 20 L -4 17 L -3 8 L -2 9 L 0 9 L 2 8 L 3 7 L 5 4","-6 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 M 4 0 L 2 7 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 3 9 L 6 7 L 9 4","-5 10 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 1 L -5 9 M -5 9 L -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-2 5 M 1 -5 L 1 -4 L 2 -4 L 2 -5 L 1 -5 M -2 4 L 0 0 L -2 6 L -2 8 L -1 9 L 0 9 L 2 8 L 3 7 L 5 4","-2 5 M 1 -5 L 1 -4 L 2 -4 L 2 -5 L 1 -5 M -2 4 L 0 0 L -6 18 L -7 20 L -9 21 L -10 20 L -10 18 L -9 15 L -6 12 L -3 10 L -1 9 L 2 7 L 5 4","-5 9 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 1 L -5 9 M -5 9 L -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 2 4 L -1 4 M -1 4 L 1 5 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-3 5 M -3 4 L -1 1 L 2 -4 L 3 -6 L 4 -9 L 4 -11 L 3 -12 L 1 -11 L 0 -9 L -1 -5 L -2 2 L -2 8 L -1 9 L 0 9 L 2 8 L 3 7 L 5 4","-13 12 M -13 4 L -11 1 L -9 0 L -8 1 L -8 2 L -9 6 L -10 9 M -9 6 L -8 4 L -6 1 L -4 0 L -2 0 L -1 1 L -1 2 L -2 6 L -3 9 M -2 6 L -1 4 L 1 1 L 3 0 L 5 0 L 6 1 L 6 3 L 5 6 L 5 8 L 6 9 L 7 9 L 9 8 L 10 7 L 12 4","-8 10 M -8 4 L -6 1 L -4 0 L -3 1 L -3 2 L -4 6 L -5 9 M -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-6 8 M 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 L 3 5 L 3 3 L 2 1 L 0 0 L -1 1 L -1 3 L 0 5 L 2 6 L 5 6 L 7 5 L 8 4","-7 8 M -7 4 L -5 1 L -4 -1 L -5 3 L -11 21 M -5 3 L -4 1 L -2 0 L 0 0 L 2 1 L 3 3 L 3 5 L 2 7 L 1 8 L -1 9 M -5 8 L -3 9 L 0 9 L 3 8 L 5 7 L 8 4","-6 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 M 4 0 L 3 3 L 1 8 L -2 15 L -3 18 L -3 20 L -2 21 L 0 20 L 1 17 L 1 10 L 3 9 L 6 7 L 9 4","-5 8 M -5 4 L -3 1 L -2 -1 L -2 1 L 1 1 L 2 2 L 2 4 L 1 7 L 1 8 L 2 9 L 3 9 L 5 8 L 6 7 L 8 4","-4 7 M -4 4 L -2 1 L -1 -1 L -1 1 L 1 4 L 2 6 L 2 8 L 0 9 M -4 8 L -2 9 L 2 9 L 4 8 L 5 7 L 7 4","-3 6 M -3 4 L -1 1 L 1 -3 M 4 -12 L -2 6 L -2 8 L -1 9 L 1 9 L 3 8 L 4 7 L 6 4 M -2 -4 L 5 -4","-6 9 M -6 4 L -4 0 L -6 6 L -6 8 L -5 9 L -3 9 L -1 8 L 1 6 L 3 3 M 4 0 L 2 6 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-6 9 M -6 4 L -4 0 L -5 5 L -5 8 L -4 9 L -3 9 L 0 8 L 2 6 L 3 3 L 3 0 M 3 0 L 4 4 L 5 5 L 7 5 L 9 4","-9 12 M -6 0 L -8 2 L -9 5 L -9 7 L -8 9 L -6 9 L -4 8 L -2 6 M 0 0 L -2 6 L -2 8 L -1 9 L 1 9 L 3 8 L 5 6 L 6 3 L 6 0 M 6 0 L 7 4 L 8 5 L 10 5 L 12 4","-8 8 M -8 4 L -6 1 L -4 0 L -2 0 L -1 1 L -1 8 L 0 9 L 3 9 L 6 7 L 8 4 M 5 1 L 4 0 L 2 0 L 1 1 L -3 8 L -4 9 L -6 9 L -7 8","-6 9 M -6 4 L -4 0 L -6 6 L -6 8 L -5 9 L -3 9 L -1 8 L 1 6 L 3 3 M 4 0 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 3 9 L 6 7 L 9 4","-6 8 M -6 4 L -4 1 L -2 0 L 0 0 L 2 2 L 2 4 L 1 6 L -1 8 L -4 9 L -2 10 L -1 12 L -1 15 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 5 7 L 8 4","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -cyrillic = ["-8 8","-5 5 M 0 -12 L -1 -10 L 0 2 L 1 -10 L 0 -12 M 0 -10 L 0 -4 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -4 -12 L -5 -5 M -3 -12 L -5 -5 M 4 -12 L 3 -5 M 5 -12 L 3 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-15 15 M -10 -12 L -10 9 M -9 -12 L -9 9 M -13 -12 L -6 -12 M -9 -2 L -2 -2 L 1 -1 L 2 0 L 3 2 L 3 5 L 2 7 L 1 8 L -2 9 L -13 9 M -2 -2 L 0 -1 L 1 0 L 2 2 L 2 5 L 1 7 L 0 8 L -2 9 M 9 -12 L 9 9 M 10 -12 L 10 9 M 6 -12 L 13 -12 M 6 9 L 13 9","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -2 -5 M 2 -5 L 9 -5 M -9 9 L 9 9 L 9 14 L 8 9","-13 13 M -8 -5 L -8 9 M -7 -5 L -7 9 M -11 -5 L -4 -5 M -7 2 L -3 2 L 0 3 L 1 5 L 1 6 L 0 8 L -3 9 L -11 9 M -3 2 L -1 3 L 0 5 L 0 6 L -1 8 L -3 9 M 7 -5 L 7 9 M 8 -5 L 8 9 M 4 -5 L 11 -5 M 4 9 L 11 9","-4 4 M 0 -12 L -1 -5 M 1 -12 L -1 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 L 4 16 M 3 -16 L 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 L -3 16 M -4 -16 L -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -4 -10 L -5 -8 L -6 -3 L -6 0 L -5 5 L -4 7 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 5 L 6 0 L 6 -3 L 5 -8 L 4 -10 L 3 -11 L 1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9 M 0 -11 L 0 9 M -4 9 L 5 9","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 3 -2 L -2 0 L -4 1 L -6 3 L -7 6 L -7 9 M 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 2 -2 L -2 0 M -7 7 L -6 6 L -4 6 L 1 8 L 4 8 L 6 7 L 7 6 M -4 6 L 1 9 L 5 9 L 6 8 L 7 6 L 7 4","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 L -1 -3 M 2 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -4 L 2 -3 M 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 5 -1 L 6 2 L 6 5 L 5 7 L 4 8 L 2 9","-10 10 M 2 -10 L 2 9 M 3 -12 L 3 9 M 3 -12 L -8 3 L 8 3 M -1 9 L 6 9","-10 10 M -5 -12 L -7 -2 M -7 -2 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -5 -12 L 5 -12 M -5 -11 L 0 -11 L 5 -12","-10 10 M 5 -9 L 4 -8 L 5 -7 L 6 -8 L 6 -9 L 5 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2 M 0 -12 L -2 -11 L -4 -9 L -5 -7 L -6 -3 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 2 L 5 -1 L 3 -3 L 1 -4","-10 10 M -7 -12 L -7 -6 M -7 -8 L -6 -10 L -4 -12 L -2 -12 L 3 -9 L 5 -9 L 6 -10 L 7 -12 M -6 -10 L -4 -11 L -2 -11 L 3 -9 M 7 -12 L 7 -9 L 6 -6 L 2 -1 L 1 1 L 0 4 L 0 9 M 6 -6 L 1 -1 L 0 1 L -1 4 L -1 9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 6 -6 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -2 -12 L -4 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -3 M 2 -3 L 4 -4 L 5 -6 L 5 -9 L 4 -11 L 2 -12 M -2 -3 L -5 -2 L -6 -1 L -7 1 L -7 5 L -6 7 L -5 8 L -2 9 L 2 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 2 -3 M -2 -3 L -4 -2 L -5 -1 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 M 2 9 L 4 8 L 5 7 L 6 5 L 6 1 L 5 -1 L 4 -2 L 2 -3","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 0 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 5 L -5 6 M -1 1 L -3 0 L -5 -2 L -6 -5 L -6 -6 L -5 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 5 -9 L 6 -6 L 6 0 L 5 4 L 4 6 L 2 8 L 0 9","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -5 -8 L -4 -7 L -5 -6 L -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 1 -12 L 3 -11 L 4 -10 L 5 -8 L 5 -6 L 4 -4 L 2 -2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 0 -12 L -7 9 M 0 -12 L 7 9 M 0 -9 L 6 9 M -5 3 L 4 3 M -9 9 L -3 9 M 3 9 L 9 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 7 -12 L 7 -6 L 6 -12 M -5 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 3 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9","-10 11 M -6 -9 L -7 -12 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 1 9 M -2 -2 L 7 -2","-12 12 M -4 -12 L -4 -6 L -5 2 L -6 6 L -7 8 L -8 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -7 -12 L 10 -12 M -11 9 L 10 9 M -11 9 L -11 16 M -10 9 L -11 16 M 9 9 L 10 16 M 10 9 L 10 16","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M 6 -10 L -6 7 M -10 9 L -3 9 M 3 9 L 10 9","-12 13 M 0 -12 L 0 9 M 1 -12 L 1 9 M -3 -12 L 4 -12 M -2 -9 L -6 -8 L -8 -6 L -9 -3 L -9 0 L -8 3 L -6 5 L -2 6 L 3 6 L 7 5 L 9 3 L 10 0 L 10 -3 L 9 -6 L 7 -8 L 3 -9 L -2 -9 M -2 -9 L -5 -8 L -7 -6 L -8 -3 L -8 0 L -7 3 L -5 5 L -2 6 M 3 6 L 6 5 L 8 3 L 9 0 L 9 -3 L 8 -6 L 6 -8 L 3 -9 M -3 9 L 4 9","-9 9 M -4 -12 L -4 9 M -3 -12 L -3 9 M -7 -12 L 8 -12 L 8 -6 L 7 -12 M -7 9 L 0 9","-15 16 M 0 -12 L 0 9 M 1 -12 L 1 9 M -3 -12 L 4 -12 M -11 -11 L -10 -10 L -11 -9 L -12 -10 L -12 -11 L -11 -12 L -10 -12 L -9 -11 L -8 -9 L -7 -5 L -6 -3 L -4 -2 L 5 -2 L 7 -3 L 8 -5 L 9 -9 L 10 -11 L 11 -12 L 12 -12 L 13 -11 L 13 -10 L 12 -9 L 11 -10 L 12 -11 M -4 -2 L -6 -1 L -7 1 L -8 6 L -9 8 L -10 9 M -4 -2 L -5 -1 L -6 1 L -7 6 L -8 8 L -9 9 L -11 9 L -12 8 L -13 6 M 5 -2 L 7 -1 L 8 1 L 9 6 L 10 8 L 11 9 M 5 -2 L 6 -1 L 7 1 L 8 6 L 9 8 L 10 9 L 12 9 L 13 8 L 14 6 M -3 9 L 4 9","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M 6 -10 L -6 7 M -10 9 L -3 9 M 3 9 L 10 9","-12 11 M -7 -12 L -7 -1 L -6 1 L -3 2 L 0 2 L 3 1 L 5 -1 M -6 -12 L -6 -1 L -5 1 L -3 2 M 5 -12 L 5 9 M 6 -12 L 6 9 M -10 -12 L -3 -12 M 2 -12 L 9 -12 M 2 9 L 9 9","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M -10 -12 L -3 -12 M -6 -2 L 1 -2 L 3 -3 L 4 -5 L 5 -9 L 6 -11 L 7 -12 L 8 -12 L 9 -11 L 9 -10 L 8 -9 L 7 -10 L 8 -11 M 1 -2 L 3 -1 L 4 1 L 5 6 L 6 8 L 7 9 M 1 -2 L 2 -1 L 3 1 L 4 6 L 5 8 L 6 9 L 8 9 L 9 8 L 10 6 M -10 9 L -3 9","-13 12 M -5 -12 L -5 -6 L -6 2 L -7 6 L -8 8 L -9 9 L -10 9 L -11 8 L -11 7 L -10 6 L -9 7 L -10 8 M 6 -12 L 6 9 M 7 -12 L 7 9 M -8 -12 L 10 -12 M 3 9 L 10 9","-12 13 M -7 -12 L -7 9 M -6 -12 L 0 6 M -7 -12 L 0 9 M 7 -12 L 0 9 M 7 -12 L 7 9 M 8 -12 L 8 9 M -10 -12 L -6 -12 M 7 -12 L 11 -12 M -10 9 L -4 9 M 4 9 L 11 9","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M -6 -2 L 6 -2 M -10 9 L -3 9 M 3 9 L 10 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 0 L -6 4 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 4 L 7 0 L 7 -3 L 6 -7 L 5 -9 L 3 -11 L 1 -12","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L 10 -12 M -10 9 L -3 9 M 3 9 L 10 9","-16 17 M -11 -12 L -11 9 M -10 -12 L -10 9 M 0 -12 L 0 9 M 1 -12 L 1 9 M 11 -12 L 11 9 M 12 -12 L 12 9 M -14 -12 L -7 -12 M -3 -12 L 4 -12 M 8 -12 L 15 -12 M -14 9 L 15 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -5 -1 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 3 -1 M -9 9 L -2 9","-11 10 M 6 -9 L 7 -6 L 7 -12 L 6 -9 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9","-9 10 M 0 -12 L 0 9 M 1 -12 L 1 9 M -6 -12 L -7 -6 L -7 -12 L 8 -12 L 8 -6 L 7 -12 M -3 9 L 4 9","-15 16 M -10 -12 L -10 9 M -9 -12 L -9 9 M -13 -12 L -6 -12 M -13 9 L -6 9 M 4 -12 L 1 -11 L -1 -9 L -2 -7 L -3 -3 L -3 0 L -2 4 L -1 6 L 1 8 L 4 9 L 6 9 L 9 8 L 11 6 L 12 4 L 13 0 L 13 -3 L 12 -7 L 11 -9 L 9 -11 L 6 -12 L 4 -12 M 4 -12 L 2 -11 L 0 -9 L -1 -7 L -2 -3 L -2 0 L -1 4 L 0 6 L 2 8 L 4 9 M 6 9 L 8 8 L 10 6 L 11 4 L 12 0 L 12 -3 L 11 -7 L 10 -9 L 8 -11 L 6 -12 M -9 -2 L -3 -2","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 3 -2 M -5 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 3 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9","-16 17 M -11 -12 L -11 9 M -10 -12 L -10 9 M 0 -12 L 0 9 M 1 -12 L 1 9 M 11 -12 L 11 9 M 12 -12 L 12 9 M -14 -12 L -7 -12 M -3 -12 L 4 -12 M 8 -12 L 15 -12 M -14 9 L 15 9 M 14 9 L 15 16 M 15 9 L 15 16","-10 10 M -7 -12 L 6 9 M -6 -12 L 7 9 M 7 -12 L -7 9 M -9 -12 L -3 -12 M 3 -12 L 9 -12 M -9 9 L -3 9 M 3 9 L 9 9","-10 11 M -7 -12 L 0 4 M -6 -12 L 1 4 M 8 -12 L 1 4 L -1 7 L -2 8 L -4 9 L -5 9 L -6 8 L -6 7 L -5 6 L -4 7 L -5 8 M -9 -12 L -3 -12 M 4 -12 L 10 -12","-10 10 M -6 -9 L -7 -12 L -7 -6 L -6 -9 L -4 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 L -1 -3 M 2 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -4 L 2 -3 M 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -3 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 5 -1 L 6 2 L 6 5 L 5 7 L 4 8 L 2 9","-11 10 M -6 -12 L -6 9 M -5 -12 L -5 9 M 1 -6 L 1 2 M -9 -12 L 7 -12 L 7 -6 L 6 -12 M -5 -2 L 1 -2 M -9 9 L 7 9 L 7 3 L 6 9","-7 7 M -7 -12 L 7 12","-12 14 M -2 -12 L -2 9 M -1 -12 L -1 9 M -9 -12 L -10 -6 L -10 -12 L 2 -12 M -1 -2 L 6 -2 L 9 -1 L 10 0 L 11 2 L 11 5 L 10 7 L 9 8 L 6 9 L -5 9 M 6 -2 L 8 -1 L 9 0 L 10 2 L 10 5 L 9 7 L 8 8 L 6 9","-11 11 M 5 -12 L 5 9 M 6 -12 L 6 9 M 9 -12 L -3 -12 L -6 -11 L -7 -10 L -8 -8 L -8 -6 L -7 -4 L -6 -3 L -3 -2 L 5 -2 M -3 -12 L -5 -11 L -6 -10 L -7 -8 L -7 -6 L -6 -4 L -5 -3 L -3 -2 M 0 -2 L -2 -1 L -3 0 L -6 7 L -7 8 L -8 8 L -9 7 M -2 -1 L -3 1 L -5 8 L -6 9 L -8 9 L -9 7 L -9 6 M 2 9 L 9 9","-10 11 M -5 -12 L -5 9 M -4 -12 L -4 9 M -8 -12 L -1 -12 M -4 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -8 9 M 3 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M -10 9 L 10 9 M 9 9 L 10 16 M 10 9 L 10 16","-9 11 M -4 -3 L -4 -2 L -5 -2 L -5 -3 L -4 -4 L -2 -5 L 2 -5 L 4 -4 L 5 -3 L 6 -1 L 6 6 L 7 8 L 8 9 M 5 -3 L 5 6 L 6 8 L 8 9 L 9 9 M 5 -1 L 4 0 L -2 1 L -5 2 L -6 4 L -6 6 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 M -2 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9","-10 10 M 6 -12 L 5 -11 L -1 -9 L -4 -7 L -6 -4 L -7 -1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 M 6 -12 L 5 -10 L 3 -9 L -1 -8 L -4 -6 L -6 -4 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 1 L 5 -2 L 3 -4 L 1 -5","-10 11 M -6 -9 L -7 -12 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 1 9 M -2 -2 L 7 -2","-12 11 M -4 -5 L -4 -1 L -5 5 L -6 8 L -7 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -7 -5 L 9 -5 M -9 9 L -10 14 L -10 9 L 9 9 L 9 14 L 8 9","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -2 -5 M 2 -5 L 9 -5 M -9 9 L -2 9 M 2 9 L 9 9 M 5 -4 L -5 8 M -3 -11 L -3 -12 L -4 -12 L -4 -11 L -3 -9 L -1 -8 L 1 -8 L 3 -9 L 4 -11","-10 11 M 0 -12 L 0 16 M 1 -12 L 1 16 M -3 -12 L 1 -12 M 0 -2 L -1 -4 L -2 -5 L -4 -5 L -6 -4 L -7 -1 L -7 5 L -6 8 L -4 9 L -2 9 L -1 8 L 0 6 M -4 -5 L -5 -4 L -6 -1 L -6 5 L -5 8 L -4 9 M 5 -5 L 6 -4 L 7 -1 L 7 5 L 6 8 L 5 9 M 1 -2 L 2 -4 L 3 -5 L 5 -5 L 7 -4 L 8 -1 L 8 5 L 7 8 L 5 9 L 3 9 L 2 8 L 1 6 M -3 16 L 4 16","-10 8 M -5 -5 L -5 9 M -4 -5 L -4 9 M -8 -5 L 6 -5 L 6 0 L 5 -5 M -8 9 L -1 9","-13 14 M 0 -5 L 0 9 M 1 -5 L 1 9 M -3 -5 L 4 -5 M -8 -4 L -9 -3 L -10 -4 L -9 -5 L -8 -5 L -7 -4 L -5 0 L -4 1 L -2 2 L 3 2 L 5 1 L 6 0 L 8 -4 L 9 -5 L 10 -5 L 11 -4 L 10 -3 L 9 -4 M -2 2 L -4 3 L -5 4 L -7 8 L -8 9 M -2 2 L -4 4 L -6 8 L -7 9 L -9 9 L -10 8 L -11 6 M 3 2 L 5 3 L 6 4 L 8 8 L 9 9 M 3 2 L 5 4 L 7 8 L 8 9 L 10 9 L 11 8 L 12 6 M -3 9 L 4 9","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -2 -5 M 2 -5 L 9 -5 M -9 9 L -2 9 M 2 9 L 9 9 M 5 -4 L -5 8","-11 11 M -6 -5 L -6 2 L -5 4 L -2 5 L 0 5 L 3 4 L 5 2 M -5 -5 L -5 2 L -4 4 L -2 5 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -2 -5 M 2 -5 L 9 -5 M 2 9 L 9 9","-10 10 M -5 -5 L -5 9 M -4 -5 L -4 9 M -8 -5 L -1 -5 M -4 2 L -2 2 L 1 1 L 2 0 L 4 -4 L 5 -5 L 6 -5 L 7 -4 L 6 -3 L 5 -4 M -2 2 L 1 3 L 2 4 L 4 8 L 5 9 M -2 2 L 0 3 L 1 4 L 3 8 L 4 9 L 6 9 L 7 8 L 8 6 M -8 9 L -1 9","-11 11 M -4 -5 L -4 -1 L -5 5 L -6 8 L -7 9 L -8 9 L -9 8 L -8 7 L -7 8 M 5 -5 L 5 9 M 6 -5 L 6 9 M -7 -5 L 9 -5 M 2 9 L 9 9","-11 12 M -6 -5 L -6 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M 6 -5 L 0 9 M 6 -5 L 6 9 M 7 -5 L 7 9 M -9 -5 L -5 -5 M 6 -5 L 10 -5 M -9 9 L -3 9 M 3 9 L 10 9","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -2 -5 M 2 -5 L 9 -5 M -5 2 L 5 2 M -9 9 L -2 9 M 2 9 L 9 9","-10 10 M -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 1 -5 L -1 -5 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 1 L 5 -2 L 3 -4 L 1 -5","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L 9 -5 M -9 9 L -2 9 M 2 9 L 9 9","-15 16 M -10 -5 L -10 9 M -9 -5 L -9 9 M 0 -5 L 0 9 M 1 -5 L 1 9 M 10 -5 L 10 9 M 11 -5 L 11 9 M -13 -5 L -6 -5 M -3 -5 L 4 -5 M 7 -5 L 14 -5 M -13 9 L 14 9","-11 10 M -6 -5 L -6 16 M -5 -5 L -5 16 M -5 -2 L -3 -4 L -1 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -1 9 L -3 8 L -5 6 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -9 -5 L -5 -5 M -9 16 L -2 16","-10 9 M 5 -2 L 4 -1 L 5 0 L 6 -1 L 6 -2 L 4 -4 L 2 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9","-9 10 M 0 -5 L 0 9 M 1 -5 L 1 9 M -5 -5 L -6 0 L -6 -5 L 7 -5 L 7 0 L 6 -5 M -3 9 L 4 9","-14 15 M -9 -5 L -9 9 M -8 -5 L -8 9 M -12 -5 L -5 -5 M -12 9 L -5 9 M 4 -5 L 1 -4 L -1 -2 L -2 1 L -2 3 L -1 6 L 1 8 L 4 9 L 6 9 L 9 8 L 11 6 L 12 3 L 12 1 L 11 -2 L 9 -4 L 6 -5 L 4 -5 M 4 -5 L 2 -4 L 0 -2 L -1 1 L -1 3 L 0 6 L 2 8 L 4 9 M 6 9 L 8 8 L 10 6 L 11 3 L 11 1 L 10 -2 L 8 -4 L 6 -5 M -8 2 L -2 2","-10 10 M -5 -5 L -5 9 M -4 -5 L -4 9 M -8 -5 L 3 -5 L 6 -4 L 7 -2 L 7 -1 L 6 1 L 3 2 M 3 -5 L 5 -4 L 6 -2 L 6 -1 L 5 1 L 3 2 M -4 2 L 3 2 L 6 3 L 7 5 L 7 6 L 6 8 L 3 9 L -8 9 M 3 2 L 5 3 L 6 5 L 6 6 L 5 8 L 3 9","-15 16 M -10 -5 L -10 9 M -9 -5 L -9 9 M 0 -5 L 0 9 M 1 -5 L 1 9 M 10 -5 L 10 9 M 11 -5 L 11 9 M -13 -5 L -6 -5 M -3 -5 L 4 -5 M 7 -5 L 14 -5 M -13 9 L 14 9 L 14 14 L 13 9","-10 10 M -6 -5 L 5 9 M -5 -5 L 6 9 M 6 -5 L -6 9 M -8 -5 L -2 -5 M 2 -5 L 8 -5 M -8 9 L -2 9 M 2 9 L 8 9","-9 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M 6 -5 L 0 9 L -2 13 L -4 15 L -6 16 L -7 16 L -8 15 L -7 14 L -6 15 M -8 -5 L -2 -5 M 2 -5 L 8 -5","-9 9 M -5 -3 L -6 -5 L -6 -1 L -5 -3 L -4 -4 L -2 -5 L 2 -5 L 5 -4 L 6 -2 L 6 -1 L 5 1 L 2 2 M 2 -5 L 4 -4 L 5 -2 L 5 -1 L 4 1 L 2 2 M -1 2 L 2 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -2 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 5 L -5 6 M 2 2 L 4 3 L 5 5 L 5 6 L 4 8 L 2 9","-10 9 M -6 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M 5 1 L 5 -2 L 4 -4 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9","-10 11 M -1 -5 L -1 9 M 0 -5 L 0 9 M -6 -5 L -7 0 L -7 -5 L 3 -5 M 0 2 L 4 2 L 7 3 L 8 5 L 8 6 L 7 8 L 4 9 L -4 9 M 4 2 L 6 3 L 7 5 L 7 6 L 6 8 L 4 9","-11 10 M 4 -5 L 4 9 M 5 -5 L 5 9 M 8 -5 L -3 -5 L -6 -4 L -7 -2 L -7 -1 L -6 1 L -3 2 L 4 2 M -3 -5 L -5 -4 L -6 -2 L -6 -1 L -5 1 L -3 2 M 2 2 L -1 3 L -2 4 L -4 8 L -5 9 M 2 2 L 0 3 L -1 4 L -3 8 L -4 9 L -6 9 L -7 8 L -8 6 M 1 9 L 8 9","-8 9 M -3 -5 L -3 9 M -2 -5 L -2 9 M -6 -5 L 1 -5 M -2 2 L 2 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -6 9 M 2 2 L 4 3 L 5 5 L 5 6 L 4 8 L 2 9","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -futural = ["-8 8","-5 5 M 0 -12 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -4 -12 L -4 -5 M 4 -12 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -6 9 L -8 8 L -9 7 L -10 5 L -10 3 L -9 1 L -8 0 L -1 -4 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 7 9 L 9 9 L 10 8 L 10 7","-5 5 M 0 -10 L -1 -11 L 0 -12 L 1 -11 L 1 -9 L 0 -7 L -1 -6","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9 M -5 2 L 5 2","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 M -7 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -7 9","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4","-11 10 M -7 -12 L -7 9 M -7 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 0 9 L -7 9","-10 9 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2 M -6 9 L 7 9","-10 8 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4 L 8 1 M 3 1 L 8 1","-11 11 M -7 -12 L -7 9 M 7 -12 L 7 9 M -7 -2 L 7 -2","-4 4 M 0 -12 L 0 9","-8 8 M 4 -12 L 4 4 L 3 7 L 2 8 L 0 9 L -2 9 L -4 8 L -5 7 L -6 4 L -6 2","-11 10 M -7 -12 L -7 9 M 7 -12 L -7 2 M -2 -3 L 7 9","-10 7 M -6 -12 L -6 9 M -6 9 L 6 9","-12 12 M -8 -12 L -8 9 M -8 -12 L 0 9 M 8 -12 L 0 9 M 8 -12 L 8 9","-11 11 M -7 -12 L -7 9 M -7 -12 L 7 9 M 7 -12 L 7 9","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 L -7 -1","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M 1 5 L 7 11","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 L -7 -2 M 0 -2 L 7 9","-10 10 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-8 8 M 0 -12 L 0 9 M -7 -12 L 7 -12","-11 11 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -12","-9 9 M -8 -12 L 0 9 M 8 -12 L 0 9","-12 12 M -10 -12 L -5 9 M 0 -12 L -5 9 M 0 -12 L 5 9 M 10 -12 L 5 9","-10 10 M -7 -12 L 7 9 M 7 -12 L -7 9","-9 9 M -8 -12 L 0 -2 L 0 9 M 8 -12 L 0 -2","-10 10 M 7 -12 L -7 9 M -7 -12 L 7 -12 M -7 9 L 7 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-8 8 M 0 -14 L -8 0 M 0 -14 L 8 0","-9 9 M -9 16 L 9 16","-4 4 M 1 -7 L -1 -5 L -1 -3 L 0 -2 L 1 -3 L 0 -4 L -1 -3","-9 10 M 6 -5 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-10 9 M -6 -12 L -6 9 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M 6 -12 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 9 M -6 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-5 7 M 5 -12 L 3 -12 L 1 -11 L 0 -8 L 0 9 M -3 -5 L 4 -5","-9 10 M 6 -5 L 6 11 L 5 14 L 4 15 L 2 16 L -1 16 L -3 15 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M -5 -12 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-4 4 M -1 -12 L 0 -11 L 1 -12 L 0 -13 L -1 -12 M 0 -5 L 0 9","-5 5 M 0 -12 L 1 -11 L 2 -12 L 1 -13 L 0 -12 M 1 -5 L 1 12 L 0 15 L -2 16 L -4 16","-9 8 M -5 -12 L -5 9 M 5 -5 L -5 5 M -1 1 L 6 9","-4 4 M 0 -12 L 0 9","-15 15 M -11 -5 L -11 9 M -11 -1 L -8 -4 L -6 -5 L -3 -5 L -1 -4 L 0 -1 L 0 9 M 0 -1 L 3 -4 L 5 -5 L 8 -5 L 10 -4 L 11 -1 L 11 9","-9 10 M -5 -5 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-9 10 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 2 -5 L -1 -5","-10 9 M -6 -5 L -6 16 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 10 M 6 -5 L 6 16 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-7 6 M -3 -5 L -3 9 M -3 1 L -2 -2 L 0 -4 L 2 -5 L 5 -5","-8 9 M 6 -2 L 5 -4 L 2 -5 L -1 -5 L -4 -4 L -5 -2 L -4 0 L -2 1 L 3 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -1 9 L -4 8 L -5 6","-5 7 M 0 -12 L 0 5 L 1 8 L 3 9 L 5 9 M -3 -5 L 4 -5","-9 10 M -5 -5 L -5 5 L -4 8 L -2 9 L 1 9 L 3 8 L 6 5 M 6 -5 L 6 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9","-11 11 M -8 -5 L -4 9 M 0 -5 L -4 9 M 0 -5 L 4 9 M 8 -5 L 4 9","-8 9 M -5 -5 L 6 9 M 6 -5 L -5 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9 L -2 13 L -4 15 L -6 16 L -7 16","-8 9 M 6 -5 L -5 9 M -5 -5 L 6 -5 M -5 9 L 6 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -futuram = ["-8 8","-5 6 M 0 -12 L 0 2 L 1 2 M 0 -12 L 1 -12 L 1 2 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-9 10 M 0 -16 L 0 13 L 1 13 M 0 -16 L 1 -16 L 1 13 M 5 -9 L 7 -9 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -9 L -6 -7 L -5 -5 L -4 -4 L 4 0 L 5 1 L 6 3 L 6 5 L 5 7 L 2 8 L -1 8 L -3 7 L -4 6 M 5 -9 L 4 -10 L 2 -11 L -1 -11 L -4 -10 L -5 -9 L -5 -7 L -4 -5 L 4 -1 L 6 1 L 7 3 L 7 5 L 6 7 L 5 8 L 2 9 L -1 9 L -4 8 L -6 6 L -4 6 M 6 6 L 3 8","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 13 M 9 -4 L 8 -3 L 9 -2 L 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -5 9 L -8 8 L -9 6 L -9 3 L -8 1 L -2 -3 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 8 9 L 9 9 L 10 8 L 10 7 M -5 9 L -7 8 L -8 6 L -8 3 L -7 1 L -5 -1 M -5 -7 L -4 -5 L 4 6 L 6 8 L 8 9","-4 5 M 1 -12 L 0 -11 L 0 -5 M 1 -11 L 0 -5 M 1 -12 L 2 -11 L 0 -5","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16 M 2 -14 L 0 -10 L -1 -7 L -2 -2 L -2 2 L -1 7 L 0 10 L 2 14","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 M -2 -14 L 0 -10 L 1 -7 L 2 -2 L 2 2 L 1 7 L 0 10 L -2 14","-8 8 M 0 -12 L -1 -11 L 1 -1 L 0 0 M 0 -12 L 0 0 M 0 -12 L 1 -11 L -1 -1 L 0 0 M -5 -9 L -4 -9 L 4 -3 L 5 -3 M -5 -9 L 5 -3 M -5 -9 L -5 -8 L 5 -4 L 5 -3 M 5 -9 L 4 -9 L -4 -3 L -5 -3 M 5 -9 L -5 -3 M 5 -9 L 5 -8 L -5 -4 L -5 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-5 6 M 2 8 L 1 9 L 0 9 L -1 8 L -1 7 L 0 6 L 1 6 L 2 7 L 2 10 L 1 12 L -1 13 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7 M 1 9 L 2 10 M 2 8 L 1 12","-13 13 M -9 0 L 9 0","-5 6 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -3 -11 L -5 -8 L -6 -3 L -6 0 L -5 5 L -3 8 M -4 7 L -1 8 L 1 8 L 4 7 M 3 8 L 5 5 L 6 0 L 6 -3 L 5 -8 L 3 -11 M 4 -10 L 1 -11 L -1 -11 L -4 -10","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9 M -4 -8 L -4 -7 L -2 -8 L 0 -10 L 0 9 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -6 9 M -6 -7 L -5 -7 L -5 -8 L -4 -10 L -2 -11 L 2 -11 L 4 -10 L 5 -8 L 5 -6 L 4 -4 L 2 -1 L -7 9 M -6 8 L 7 8 L 7 9 M -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L -1 -3 M -5 -12 L -5 -11 L 5 -11 M 5 -12 L -2 -3 M -1 -4 L 1 -4 L 4 -3 L 6 -1 L 7 2 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -6 5 M -2 -3 L 1 -3 L 4 -2 L 6 1 M 2 -3 L 5 -1 L 6 2 L 6 3 L 5 6 L 2 8 M 6 4 L 4 7 L 1 8 L -2 8 L -5 7 L -6 5 M -3 8 L -6 6","-10 10 M 3 -9 L 3 9 L 4 9 M 4 -12 L 4 9 M 4 -12 L -7 4 L 8 4 M 3 -9 L -6 4 M -6 3 L 8 3 L 8 4","-10 10 M -5 -12 L -6 -3 M -4 -11 L -5 -4 M -5 -12 L 5 -12 L 5 -11 M -4 -11 L 5 -11 M -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -6 5 M -6 -3 L -5 -3 L -3 -4 L 1 -4 L 4 -3 L 6 0 M 2 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 2 8 M 6 4 L 4 7 L 1 8 L -2 8 L -5 7 L -6 5 M -3 8 L -6 6","-10 10 M 4 -11 L 5 -9 L 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 M 5 -10 L 2 -11 L 0 -11 L -3 -10 M -2 -11 L -4 -8 L -5 -3 L -5 2 L -4 6 L -1 8 M -5 4 L -3 7 L 0 8 L 1 8 L 4 7 L 6 4 M 2 8 L 5 6 L 6 3 L 6 2 L 5 -1 L 2 -3 M 6 1 L 4 -2 L 1 -3 L 0 -3 L -3 -2 L -5 1 M -1 -3 L -4 -1 L -5 2","-10 10 M -7 -12 L 7 -12 L -3 9 M -7 -12 L -7 -11 L 6 -11 M 6 -12 L -4 9 L -3 9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -4 -4 L -2 -3 L 2 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 2 8 L -2 8 L -5 7 L -6 5 L -6 2 L -5 0 L -4 -1 L -2 -2 L 2 -3 L 4 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -4 -11 L -5 -9 L -5 -7 L -4 -5 L -2 -4 L 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -2 -3 L 2 -4 L 4 -5 L 5 -7 L 5 -9 L 4 -11 M 5 -10 L 2 -11 L -2 -11 L -5 -10 M -6 6 L -3 8 M 3 8 L 6 6","-10 10 M 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6 L -5 6 L -4 8 M 5 -5 L 4 -2 L 1 0 M 5 -4 L 3 -1 L 0 0 L -1 0 L -4 -1 L -6 -4 M -2 0 L -5 -2 L -6 -5 L -6 -6 L -5 -9 L -2 -11 M -6 -7 L -4 -10 L -1 -11 L 0 -11 L 3 -10 L 5 -7 M 1 -11 L 4 -9 L 5 -5 L 5 0 L 4 5 L 2 8 M 3 7 L 0 8 L -2 8 L -5 7","-5 6 M 0 -5 L -1 -4 L -1 -3 L 0 -2 L 1 -2 L 2 -3 L 2 -4 L 1 -5 L 0 -5 M 0 -4 L 0 -3 L 1 -3 L 1 -4 L 0 -4 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-5 6 M 0 -5 L -1 -4 L -1 -3 L 0 -2 L 1 -2 L 2 -3 L 2 -4 L 1 -5 L 0 -5 M 0 -4 L 0 -3 L 1 -3 L 1 -4 L 0 -4 M 2 8 L 1 9 L 0 9 L -1 8 L -1 7 L 0 6 L 1 6 L 2 7 L 2 10 L 1 12 L -1 13 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7 M 1 9 L 2 10 M 2 8 L 1 12","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-9 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -1 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 3 -2 L 0 -1 M -6 -7 L -5 -7 L -5 -8 L -4 -10 L -1 -11 L 2 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -3 L 0 -2 M -5 -9 L -2 -11 M 3 -11 L 6 -9 M 6 -5 L 2 -2 M 0 -2 L 0 2 L 1 2 L 1 -2 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 0 -12 L -8 9 M 0 -9 L -7 9 L -8 9 M 0 -9 L 7 9 L 8 9 M 0 -12 L 8 9 M -5 3 L 5 3 M -6 4 L 6 4","-10 10 M -6 -12 L -6 9 M -5 -11 L -5 8 M -6 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 M -5 -11 L 2 -11 L 5 -10 L 6 -8 L 6 -5 L 5 -3 L 2 -2 M -5 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -6 9 M -5 -1 L 2 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 2 8 L -5 8","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4 M 8 -7 L 7 -7 L 6 -9 L 5 -10 L 3 -11 L -1 -11 L -3 -10 L -5 -7 L -6 -4 L -6 1 L -5 4 L -3 7 L -1 8 L 3 8 L 5 7 L 6 6 L 7 4 L 8 4","-10 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -6 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -6 9 M -5 -11 L 1 -11 L 4 -10 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 4 7 L 1 8 L -5 8","-9 10 M -5 -12 L -5 9 M -4 -11 L -4 8 M -5 -12 L 7 -12 M -4 -11 L 7 -11 L 7 -12 M -4 -2 L 2 -2 L 2 -1 M -4 -1 L 2 -1 M -4 8 L 7 8 L 7 9 M -5 9 L 7 9","-9 9 M -5 -12 L -5 9 M -4 -11 L -4 9 L -5 9 M -5 -12 L 7 -12 M -4 -11 L 7 -11 L 7 -12 M -4 -2 L 2 -2 L 2 -1 M -4 -1 L 2 -1","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4 L 8 0 L 3 0 M 8 -7 L 7 -7 L 6 -9 L 5 -10 L 3 -11 L -1 -11 L -3 -10 L -4 -9 L -5 -7 L -6 -4 L -6 1 L -5 4 L -4 6 L -3 7 L -1 8 L 3 8 L 5 7 L 6 6 L 7 4 L 7 1 L 3 1 L 3 0","-11 11 M -7 -12 L -7 9 M -7 -12 L -6 -12 L -6 9 L -7 9 M 7 -12 L 6 -12 L 6 9 L 7 9 M 7 -12 L 7 9 M -6 -2 L 6 -2 M -6 -1 L 6 -1","-4 5 M 0 -12 L 0 9 L 1 9 M 0 -12 L 1 -12 L 1 9","-8 9 M 4 -12 L 4 4 L 3 7 L 1 8 L -1 8 L -3 7 L -4 4 L -5 4 M 4 -12 L 5 -12 L 5 4 L 4 7 L 3 8 L 1 9 L -1 9 L -3 8 L -4 7 L -5 4","-10 11 M -6 -12 L -6 9 L -5 9 M -6 -12 L -5 -12 L -5 9 M 8 -12 L 7 -12 L -5 0 M 8 -12 L -5 1 M -2 -3 L 7 9 L 8 9 M -1 -3 L 8 9","-9 8 M -5 -12 L -5 9 M -5 -12 L -4 -12 L -4 8 M -4 8 L 7 8 L 7 9 M -5 9 L 7 9","-12 12 M -8 -12 L -8 9 M -7 -7 L -7 9 L -8 9 M -7 -7 L 0 9 M -8 -12 L 0 6 M 8 -12 L 0 6 M 7 -7 L 0 9 M 7 -7 L 7 9 L 8 9 M 8 -12 L 8 9","-11 11 M -7 -12 L -7 9 M -6 -9 L -6 9 L -7 9 M -6 -9 L 7 9 M -7 -12 L 6 6 M 6 -12 L 6 6 M 6 -12 L 7 -12 L 7 9","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M -1 -11 L -4 -10 L -6 -7 L -7 -4 L -7 1 L -6 4 L -4 7 L -1 8 L 1 8 L 4 7 L 6 4 L 7 1 L 7 -4 L 6 -7 L 4 -10 L 1 -11 L -1 -11","-10 10 M -6 -12 L -6 9 M -5 -11 L -5 9 L -6 9 M -6 -12 L 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 3 -1 L -5 -1 M -5 -11 L 3 -11 L 5 -10 L 6 -8 L 6 -5 L 5 -3 L 3 -2 L -5 -2","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M -1 -11 L -4 -10 L -6 -7 L -7 -4 L -7 1 L -6 4 L -4 7 L -1 8 L 1 8 L 4 7 L 6 4 L 7 1 L 7 -4 L 6 -7 L 4 -10 L 1 -11 L -1 -11 M 1 6 L 6 11 L 7 11 M 1 6 L 2 6 L 7 11","-10 10 M -6 -12 L -6 9 M -5 -11 L -5 9 L -6 9 M -6 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 L -5 -1 M -5 -11 L 2 -11 L 5 -10 L 6 -8 L 6 -5 L 5 -3 L 2 -2 L -5 -2 M 0 -1 L 6 9 L 7 9 M 1 -1 L 7 9","-10 10 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 2 -1 L 4 0 L 5 1 L 6 3 L 6 6 L 5 7 L 2 8 L -2 8 L -4 7 L -5 6 L -7 6 M 7 -9 L 5 -9 L 4 -10 L 2 -11 L -2 -11 L -5 -10 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 2 -2 L 4 -1 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-8 9 M 0 -11 L 0 9 M 1 -11 L 1 9 L 0 9 M -6 -12 L 7 -12 L 7 -11 M -6 -12 L -6 -11 L 7 -11","-11 11 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -12 M -7 -12 L -6 -12 L -6 3 L -5 6 L -4 7 L -1 8 L 1 8 L 4 7 L 5 6 L 6 3 L 6 -12 L 7 -12","-10 10 M -8 -12 L 0 9 M -8 -12 L -7 -12 L 0 6 M 8 -12 L 7 -12 L 0 6 M 8 -12 L 0 9","-13 13 M -11 -12 L -5 9 M -11 -12 L -10 -12 L -5 6 M 0 -12 L -5 6 M 0 -9 L -5 9 M 0 -9 L 5 9 M 0 -12 L 5 6 M 11 -12 L 10 -12 L 5 6 M 11 -12 L 5 9","-10 10 M -7 -12 L 6 9 L 7 9 M -7 -12 L -6 -12 L 7 9 M 7 -12 L 6 -12 L -7 9 M 7 -12 L -6 9 L -7 9","-9 10 M -7 -12 L 0 -2 L 0 9 L 1 9 M -7 -12 L -6 -12 L 1 -2 M 8 -12 L 7 -12 L 0 -2 M 8 -12 L 1 -2 L 1 9","-10 10 M 6 -12 L -7 9 M 7 -12 L -6 9 M -7 -12 L 7 -12 M -7 -12 L -7 -11 L 6 -11 M -6 8 L 7 8 L 7 9 M -7 9 L 7 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-10 10 M 5 -5 L 5 9 L 6 9 M 5 -5 L 6 -5 L 6 9 M 5 -2 L 3 -4 L 1 -5 L -2 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6 M 5 -2 L 1 -4 L -2 -4 L -4 -3 L -5 -2 L -6 1 L -6 3 L -5 6 L -4 7 L -2 8 L 1 8 L 5 6","-10 10 M -6 -12 L -6 9 L -5 9 M -6 -12 L -5 -12 L -5 9 M -5 -2 L -3 -4 L -1 -5 L 2 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 2 9 L -1 9 L -3 8 L -5 6 M -5 -2 L -1 -4 L 2 -4 L 4 -3 L 5 -2 L 6 1 L 6 3 L 5 6 L 4 7 L 2 8 L -1 8 L -5 6","-9 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 M 6 -2 L 5 -1 L 4 -3 L 2 -4 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 3 L -4 6 L -3 7 L -1 8 L 2 8 L 4 7 L 5 5 L 6 6","-10 10 M 5 -12 L 5 9 L 6 9 M 5 -12 L 6 -12 L 6 9 M 5 -2 L 3 -4 L 1 -5 L -2 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6 M 5 -2 L 1 -4 L -2 -4 L -4 -3 L -5 -2 L -6 1 L -6 3 L -5 6 L -4 7 L -2 8 L 1 8 L 5 6","-9 9 M -5 2 L 6 2 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 M -5 1 L 5 1 L 5 -1 L 4 -3 L 2 -4 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 3 L -4 6 L -3 7 L -1 8 L 2 8 L 4 7 L 5 5 L 6 6","-6 8 M 5 -12 L 3 -12 L 1 -11 L 0 -8 L 0 9 L 1 9 M 5 -12 L 5 -11 L 3 -11 L 1 -10 M 2 -11 L 1 -8 L 1 9 M -3 -5 L 4 -5 L 4 -4 M -3 -5 L -3 -4 L 4 -4","-10 10 M 6 -5 L 5 -5 L 5 10 L 4 13 L 3 14 L 1 15 L -1 15 L -3 14 L -4 13 L -6 13 M 6 -5 L 6 10 L 5 13 L 3 15 L 1 16 L -2 16 L -4 15 L -6 13 M 5 -2 L 3 -4 L 1 -5 L -2 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6 M 5 -2 L 1 -4 L -2 -4 L -4 -3 L -5 -2 L -6 1 L -6 3 L -5 6 L -4 7 L -2 8 L 1 8 L 5 6","-10 10 M -6 -12 L -6 9 L -5 9 M -6 -12 L -5 -12 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9 M -5 -1 L -2 -3 L 0 -4 L 2 -4 L 4 -3 L 5 -1 L 5 9 L 6 9","-4 5 M 0 -12 L -1 -11 L -1 -10 L 0 -9 L 1 -9 L 2 -10 L 2 -11 L 1 -12 L 0 -12 M 0 -11 L 0 -10 L 1 -10 L 1 -11 L 0 -11 M 0 -5 L 0 9 L 1 9 M 0 -5 L 1 -5 L 1 9","-4 5 M 0 -12 L -1 -11 L -1 -10 L 0 -9 L 1 -9 L 2 -10 L 2 -11 L 1 -12 L 0 -12 M 0 -11 L 0 -10 L 1 -10 L 1 -11 L 0 -11 M 0 -5 L 0 16 L 1 16 M 0 -5 L 1 -5 L 1 16","-10 9 M -6 -12 L -6 9 L -5 9 M -6 -12 L -5 -12 L -5 9 M 6 -5 L 5 -5 L -5 5 M 6 -5 L -5 6 M -2 2 L 4 9 L 6 9 M -1 1 L 6 9","-4 5 M 0 -12 L 0 9 L 1 9 M 0 -12 L 1 -12 L 1 9","-15 16 M -11 -5 L -11 9 L -10 9 M -11 -5 L -10 -5 L -10 9 M -10 -1 L -7 -4 L -5 -5 L -2 -5 L 0 -4 L 1 -1 L 1 9 M -10 -1 L -7 -3 L -5 -4 L -3 -4 L -1 -3 L 0 -1 L 0 9 L 1 9 M 1 -1 L 4 -4 L 6 -5 L 9 -5 L 11 -4 L 12 -1 L 12 9 M 1 -1 L 4 -3 L 6 -4 L 8 -4 L 10 -3 L 11 -1 L 11 9 L 12 9","-10 10 M -6 -5 L -6 9 L -5 9 M -6 -5 L -5 -5 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9 M -5 -1 L -2 -3 L 0 -4 L 2 -4 L 4 -3 L 5 -1 L 5 9 L 6 9","-9 10 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 2 -5 L -1 -5 M -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 3 L -4 6 L -3 7 L -1 8 L 2 8 L 4 7 L 5 6 L 6 3 L 6 1 L 5 -2 L 4 -3 L 2 -4 L -1 -4","-10 10 M -6 -5 L -6 16 L -5 16 M -6 -5 L -5 -5 L -5 16 M -5 -2 L -3 -4 L -1 -5 L 2 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 2 9 L -1 9 L -3 8 L -5 6 M -5 -2 L -1 -4 L 2 -4 L 4 -3 L 5 -2 L 6 1 L 6 3 L 5 6 L 4 7 L 2 8 L -1 8 L -5 6","-10 10 M 5 -5 L 5 16 L 6 16 M 5 -5 L 6 -5 L 6 16 M 5 -2 L 3 -4 L 1 -5 L -2 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6 M 5 -2 L 1 -4 L -2 -4 L -4 -3 L -5 -2 L -6 1 L -6 3 L -5 6 L -4 7 L -2 8 L 1 8 L 5 6","-7 7 M -3 -5 L -3 9 L -2 9 M -3 -5 L -2 -5 L -2 9 M -2 1 L -1 -2 L 1 -4 L 3 -5 L 6 -5 M -2 1 L -1 -1 L 1 -3 L 3 -4 L 6 -4 L 6 -5","-8 9 M 6 -2 L 5 -4 L 2 -5 L -1 -5 L -4 -4 L -5 -2 L -4 0 L -2 1 L 3 3 L 5 4 M 4 3 L 5 5 L 5 6 L 4 8 M 5 7 L 2 8 L -1 8 L -4 7 M -3 8 L -4 6 L -5 6 M 6 -2 L 5 -2 L 4 -4 M 5 -3 L 2 -4 L -1 -4 L -4 -3 M -3 -4 L -4 -2 L -3 0 M -4 -1 L -2 0 L 3 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -1 9 L -4 8 L -5 6","-5 6 M 0 -12 L 0 9 L 1 9 M 0 -12 L 1 -12 L 1 9 M -3 -5 L 4 -5 L 4 -4 M -3 -5 L -3 -4 L 4 -4","-10 10 M -6 -5 L -6 5 L -5 8 L -3 9 L 0 9 L 2 8 L 5 5 M -6 -5 L -5 -5 L -5 5 L -4 7 L -2 8 L 0 8 L 2 7 L 5 5 M 5 -5 L 5 9 L 6 9 M 5 -5 L 6 -5 L 6 9","-8 8 M -6 -5 L 0 9 M -6 -5 L -5 -5 L 0 7 M 6 -5 L 5 -5 L 0 7 M 6 -5 L 0 9","-12 12 M -9 -5 L -4 9 M -9 -5 L -8 -5 L -4 6 M 0 -5 L -4 6 M 0 -2 L -4 9 M 0 -2 L 4 9 M 0 -5 L 4 6 M 9 -5 L 8 -5 L 4 6 M 9 -5 L 4 9","-9 9 M -6 -5 L 5 9 L 6 9 M -6 -5 L -5 -5 L 6 9 M 6 -5 L 5 -5 L -6 9 M 6 -5 L -5 9 L -6 9","-8 8 M -6 -5 L 0 9 M -6 -5 L -5 -5 L 0 7 M 6 -5 L 5 -5 L 0 7 L -4 16 M 6 -5 L 0 9 L -3 16 L -4 16","-9 9 M 4 -4 L -6 9 M 6 -5 L -4 8 M -6 -5 L 6 -5 M -6 -5 L -6 -4 L 4 -4 M -4 8 L 6 8 L 6 9 M -6 9 L 6 9","-7 7 M 3 -16 L -4 0 L 3 16","-4 4 M 0 -16 L 0 16","-7 7 M -3 -16 L 4 0 L -3 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -gothiceng = ["-8 8","-6 6 M 0 -12 L -1 -11 L -3 -10 L -1 -9 L 0 2 M 0 -9 L 1 -10 L 0 -11 L -1 -10 L 0 -9 L 0 2 M 0 -12 L 1 -11 L 3 -10 L 1 -9 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 2 -12 L 4 -11 L 5 -9 L 5 -7 L 7 -8 L 6 -10 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M 6 -8 L 5 -10 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 7 L -6 5 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -5 4 L -5 6 L -4 8 L -2 9","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 7 -4 L 8 -3 L 9 -3 L 10 -4 M 6 -3 L 7 -2 L 9 -2 M 6 -2 L 7 -1 L 8 -1 L 9 -2 L 10 -4 M 7 -4 L 1 2 M 0 3 L -6 9 L -10 4 L -4 -2 M -3 -3 L 1 -7 L -3 -12 L -8 -6 L -2 0 L 2 6 L 4 8 L 6 9 L 8 9 L 9 8 L 10 6 M -6 8 L -9 4 M 0 -7 L -3 -11 M -7 -6 L -2 -1 L 2 5 L 4 7 L 6 8 L 9 8 M -5 8 L -9 3 M 0 -6 L -4 -11 M -7 -7 L -1 -1 L 3 5 L 4 6 L 6 7 L 9 7 L 10 6","-4 5 M 1 -12 L 0 -11 L 0 -5 M 1 -11 L 0 -5 M 1 -12 L 2 -11 L 0 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 M -1 -10 L -2 -7 L -3 -3 L -3 3 L -2 7 L -1 10 M 1 -14 L 0 -12 L -1 -9 L -2 -3 L -2 3 L -1 9 L 0 12 L 1 14","-7 7 M -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16 M 1 -10 L 2 -7 L 3 -3 L 3 3 L 2 7 L 1 10 M -1 -14 L 0 -12 L 1 -9 L 2 -3 L 2 3 L 1 9 L 0 12 L -1 14","-8 8 M 0 -12 L -1 -11 L 1 -1 L 0 0 M 0 -12 L 0 0 M 0 -12 L 1 -11 L -1 -1 L 0 0 M -5 -9 L -4 -9 L 4 -3 L 5 -3 M -5 -9 L 5 -3 M -5 -9 L -5 -8 L 5 -4 L 5 -3 M 5 -9 L 4 -9 L -4 -3 L -5 -3 M 5 -9 L -5 -3 M 5 -9 L 5 -8 L -5 -4 L -5 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-6 6 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-13 13 M -9 0 L 9 0","-6 6 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -3 -10 L -2 -9 L -1 -7 L -1 6 L -3 7 M -1 -9 L -2 -10 L -1 -11 L 0 -9 L 0 7 L 2 8 M -3 -10 L 0 -12 L 1 -10 L 1 6 L 3 7 L 4 7 M -3 7 L -2 7 L 0 8 L 1 9 L 2 8 L 4 7","-10 10 M -6 -10 L -4 -10 L -2 -11 L -1 -12 L 1 -11 L 4 -10 L 6 -10 M -2 -10 L 0 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -10 L 1 -11 M 4 -10 L 4 -2 M 5 -9 L 5 -3 M 6 -10 L 6 -2 L -1 -2 L -4 -1 L -6 1 L -7 4 L -7 9 M -7 9 L -3 7 L 1 6 L 4 6 L 8 7 M -4 8 L -1 7 L 4 7 L 7 8 M -7 9 L -2 8 L 3 8 L 6 9 L 8 7","-10 10 M -6 -10 L -5 -10 L -3 -11 L -2 -12 L 0 -11 L 4 -10 L 6 -10 M -3 -10 L -1 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -11 M 4 -10 L 4 -3 M 5 -9 L 5 -4 M 6 -10 L 6 -3 L 4 -3 L 1 -2 L -1 -1 M -1 -2 L 1 -1 L 4 0 L 6 0 L 6 7 M 5 1 L 5 6 M 4 0 L 4 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M 3 -12 L -7 -2 L -7 3 L 2 3 M 4 3 L 8 3 L 9 4 L 9 2 L 8 3 M -6 -2 L -6 2 M -5 -4 L -5 3 M 2 -11 L 2 6 L 0 7 M 3 -8 L 4 -10 L 3 -11 L 3 7 L 5 8 M 3 -12 L 5 -10 L 4 -8 L 4 6 L 6 7 L 7 7 M 0 7 L 1 7 L 3 8 L 4 9 L 5 8 L 7 7","-10 10 M -6 -12 L -6 -3 M -6 -12 L 6 -12 M -5 -11 L 4 -11 M -6 -10 L 3 -10 L 5 -11 L 6 -12 M 4 -6 L 3 -5 L 1 -4 L -3 -3 L -6 -3 M 1 -4 L 2 -4 L 4 -3 L 4 7 M 3 -5 L 5 -4 L 5 6 M 4 -6 L 5 -5 L 7 -4 L 8 -4 L 6 -3 L 6 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 0 -11 L 2 -12 L 3 -11 L 5 -10 L 6 -10 M 1 -11 L 3 -10 M 0 -11 L 2 -9 L 4 -9 L 6 -10 M -4 -2 L -3 -2 L 1 -3 L 3 -4 L 4 -5 M 1 -3 L 2 -3 L 4 -2 L 4 7 M 3 -4 L 5 -2 L 5 6 M 4 -5 L 5 -4 L 7 -3 L 8 -3 L 6 -2 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -7 -10 L -5 -12 L -2 -11 L 3 -11 L 8 -12 M -6 -11 L -3 -10 L 2 -10 L 5 -11 M -7 -10 L -3 -9 L 0 -9 L 4 -10 L 8 -12 M 8 -12 L 7 -10 L 5 -7 L 1 -3 L -1 0 L -2 3 L -2 6 L -1 9 M 0 -1 L -1 2 L -1 5 L 0 8 M 3 -5 L 1 -2 L 0 1 L 0 4 L 1 7 L -1 9","-10 10 M -6 -9 L -6 -3 M -5 -8 L -5 -4 M -4 -9 L -4 -3 M -6 -9 L -4 -9 L 1 -10 L 3 -11 L 4 -12 M 1 -10 L 2 -10 L 4 -9 L 4 -3 M 3 -11 L 5 -10 L 5 -4 M 4 -12 L 5 -11 L 7 -10 L 8 -10 L 6 -9 L 6 -3 M -6 -3 L -4 -3 L 4 0 L 6 0 M 6 -3 L 4 -3 L -4 0 L -6 0 M -6 0 L -6 6 L -8 7 M -5 1 L -5 6 L -2 8 M -4 0 L -4 6 L -2 7 L -1 8 M 4 0 L 4 7 M 5 1 L 5 6 M 6 0 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 -1 L -8 0 M -5 -9 L -5 0 L -3 1 M -4 -10 L -4 -1 L -2 0 L -1 0 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 0 L -7 0 L -5 1 L -4 2 L -3 1 L -1 0 L 3 -1 L 4 -1 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -8 L -5 -10 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -2 L 1 -1 M -5 -8 L -4 -10 M 4 -10 L 5 -9 L 5 -5 L 4 -4 M -6 -8 L -4 -7 L -4 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 4 -9 L 4 -5 L 3 -3 L 1 -1 M 0 -1 L 0 2 L 1 -1 L -1 -1 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-11 11 M -6 -9 L -4 -11 L -2 -12 L 0 -12 L 1 -11 L 8 5 L 9 6 L 11 6 M -1 -11 L 0 -10 L 7 6 L 8 8 L 9 7 L 7 6 M -4 -11 L -2 -11 L -1 -10 L 6 6 L 7 8 L 8 9 L 9 9 L 11 6 M -6 -5 L -5 -6 L -3 -7 L -2 -7 L -1 -6 M -2 -6 L -2 -5 M -5 -6 L -3 -6 L -2 -4 M -11 9 L -9 7 L -7 6 L -4 6 L -2 7 M -8 7 L -4 7 L -3 8 M -11 9 L -8 8 L -5 8 L -4 9 L -2 7 M 0 -8 L -6 6 M -4 1 L 4 1","-12 12 M -10 -10 L -8 -12 L -5 -12 L -3 -11 L -1 -12 M -7 -11 L -4 -11 M -10 -10 L -8 -11 L -6 -10 L -3 -10 L -1 -12 M -5 -7 L -6 -6 L -7 -4 L -7 -3 L -9 -3 L -10 -2 L -10 0 L -9 -1 L -7 -1 L -7 5 M -6 -5 L -6 3 M -9 -2 L -6 -2 M -5 -7 L -5 2 L -6 4 L -7 5 M 0 -9 L -1 -8 L -2 -6 L -2 3 M -1 -7 L -1 1 M 0 -9 L 0 0 L -1 2 L -2 3 M 0 -9 L 6 -12 L 8 -11 L 9 -9 L 9 -7 L 7 -5 L 3 -3 M 6 -11 L 8 -9 L 8 -7 M 4 -11 L 6 -10 L 7 -9 L 7 -6 L 5 -4 M 5 -4 L 8 -2 L 9 0 L 9 6 M 7 -2 L 8 0 L 8 5 M 5 -4 L 6 -3 L 7 -1 L 7 6 M -8 9 L -5 7 L -2 6 L 2 6 L 5 7 M -6 8 L -3 7 L 2 7 L 4 8 M -8 9 L -4 8 L 1 8 L 3 9 L 5 7 L 7 6 L 9 6 M 3 -3 L 3 6 M 3 0 L 7 0 M 3 3 L 7 3","-13 11 M -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 1 L -9 4 L -8 6 L -5 8 L -2 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 M -8 -7 L -9 -4 L -9 1 L -7 5 L -4 7 L -1 8 L 2 8 L 5 7 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 0 L -7 3 L -4 6 L -1 7 L 2 7 L 5 6 L 7 5 L 9 3 M -2 -8 L -2 4 M -1 -8 L -1 2 M 0 -9 L 0 1 L -1 3 L -2 4 M -2 -8 L 0 -9 L 3 -12 L 5 -11 L 7 -11 L 8 -12 M 2 -11 L 4 -10 L 6 -10 M 1 -10 L 3 -9 L 5 -9 L 7 -10 L 8 -12 M 5 -9 L 5 6","-11 12 M -9 -12 L 5 -12 L 7 -11 L 8 -9 L 8 6 M -7 -11 L 5 -11 L 7 -9 L 7 5 M -9 -12 L -8 -11 L -6 -10 L 5 -10 L 6 -9 L 6 6 M -3 -7 L -4 -6 L -5 -4 L -5 -3 L -7 -3 L -8 -2 L -8 0 L -7 -1 L -5 -1 L -5 4 M -4 -5 L -4 2 M -7 -2 L -4 -2 M -3 -7 L -3 1 L -4 3 L -5 4 M -9 9 L -6 7 L -3 6 L 1 6 L 4 7 M -7 8 L -4 7 L 1 7 L 3 8 M -9 9 L -5 8 L 0 8 L 2 9 L 4 7 L 6 6 L 8 6 M 0 -10 L 0 6 M 0 -5 L 2 -4 L 4 -4 L 6 -5 M 0 1 L 2 0 L 4 0 L 6 1","-11 11 M -9 -10 L -7 -12 L -5 -12 L -3 -11 L -1 -12 M -6 -11 L -4 -11 M -9 -10 L -7 -11 L -5 -10 L -3 -10 L -1 -12 M -4 -7 L -5 -6 L -6 -4 L -6 -3 L -8 -3 L -9 -2 L -9 0 L -8 -1 L -6 -1 L -6 5 M -5 -5 L -5 3 M -8 -2 L -5 -2 M -4 -7 L -4 2 L -5 4 L -6 5 M -1 -5 L 0 -8 L 1 -10 L 2 -11 L 4 -12 L 6 -12 L 9 -11 M 2 -10 L 4 -11 L 6 -11 L 8 -10 M 0 -8 L 1 -9 L 3 -10 L 5 -10 L 7 -9 L 9 -11 M -1 3 L 0 0 L 1 -2 L 2 -3 L 4 -3 L 6 -2 M 2 -2 L 4 -2 L 5 -1 M 0 0 L 1 -1 L 3 -1 L 4 0 L 6 -2 M -7 9 L -4 7 L 0 6 L 5 6 L 9 7 M -5 8 L -2 7 L 5 7 L 8 8 M -7 9 L -3 8 L 4 8 L 7 9 L 9 7 M -1 -5 L -1 6","-12 11 M -8 -10 L -6 -12 L -3 -12 L -1 -11 L 1 -12 M -5 -11 L -2 -11 M -8 -10 L -6 -11 L -4 -10 L -1 -10 L 1 -12 M -2 -7 L -3 -6 L -4 -4 L -4 -3 L -6 -3 L -7 -2 L -7 0 L -6 -1 L -4 -1 L -4 4 M -3 -5 L -3 2 M -6 -2 L -3 -2 M -2 -7 L -2 1 L -3 3 L -4 4 M 1 -8 L 1 7 L 0 8 L -1 8 L -5 6 L -7 6 L -9 7 L -11 9 M 2 -8 L 2 6 M 2 -2 L 6 -2 M -2 8 L -3 8 L -5 7 L -8 7 M 3 -9 L 3 -3 L 6 -3 M 6 -1 L 3 -1 L 3 5 L 2 7 L -2 9 L -4 9 L -6 8 L -8 8 L -11 9 M 1 -8 L 3 -9 L 6 -12 L 8 -11 L 10 -11 L 11 -12 M 5 -11 L 7 -10 L 9 -10 M 4 -10 L 6 -9 L 8 -9 L 10 -10 L 11 -12 M 6 -9 L 6 5","-13 12 M -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 3 9 L 6 8 L 8 6 L 9 4 L 9 1 L 8 -1 L 7 -2 L 5 -3 L 3 -3 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 7 6 L 8 5 L 8 1 L 7 -1 M 3 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 3 -3 M -2 -8 L -2 5 M -1 -8 L -1 3 M 0 -9 L 0 2 L -1 4 L -2 5 M -2 -8 L 0 -9 L 3 -12 L 5 -11 L 7 -11 L 8 -12 M 2 -11 L 4 -10 L 6 -10 M 1 -10 L 3 -9 L 5 -9 L 7 -10 L 8 -12 M 7 -10 L 3 -3 L 3 9 M 3 1 L 7 1 M 3 4 L 7 4","-12 12 M -10 -10 L -8 -12 L -5 -12 L -3 -11 L -1 -12 M -7 -11 L -4 -11 M -10 -10 L -8 -11 L -6 -10 L -3 -10 L -1 -12 M -5 -7 L -6 -6 L -7 -4 L -7 -3 L -9 -3 L -10 -2 L -10 0 L -9 -1 L -7 -1 L -7 5 M -6 -5 L -6 3 M -9 -2 L -6 -2 M -5 -7 L -5 2 L -6 4 L -7 5 M -8 9 L -5 7 L -2 6 L 1 6 L 3 7 M -6 8 L -3 7 L 0 7 L 2 8 M -8 9 L -4 8 L -1 8 L 1 9 L 3 7 M 0 -9 L -1 -8 L -2 -6 L -2 3 M -1 -7 L -1 1 M 0 -9 L 0 0 L -1 2 L -2 3 M 0 -9 L 2 -11 L 4 -12 L 6 -12 L 8 -11 M 5 -11 L 6 -11 L 7 -10 M 2 -11 L 4 -11 L 6 -9 L 8 -11 M 3 -3 L 5 -4 L 7 -6 L 8 -5 L 9 -2 L 9 2 L 8 6 L 6 9 M 6 -5 L 7 -4 L 8 -2 L 8 3 L 7 6 M 5 -4 L 6 -4 L 7 -2 L 7 3 L 6 9 M 3 -3 L 3 7 M 3 0 L 7 0 M 3 3 L 7 3","-9 10 M -6 -10 L -4 -12 L -1 -12 L 2 -11 L 4 -12 M -3 -11 L 1 -11 M -6 -10 L -4 -11 L -1 -10 L 2 -10 L 4 -12 M 1 -7 L 0 -6 L -1 -4 L -1 -3 L -3 -3 L -4 -2 L -4 0 L -3 -1 L -1 -1 L -1 4 M 0 -5 L 0 2 M -3 -2 L 0 -2 M 1 -7 L 1 1 L 0 3 L -1 4 M 7 -10 L 5 -8 L 4 -5 L 4 6 L 3 8 L 1 8 L -3 6 L -5 6 L -7 7 L -9 9 M 5 -7 L 5 5 M 0 8 L -1 8 L -3 7 L -6 7 M 7 -10 L 6 -8 L 6 4 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -7 8 L -9 9","-10 10 M -6 -10 L -4 -12 L -1 -12 L 2 -11 L 4 -12 M -3 -11 L 1 -11 M -6 -10 L -4 -11 L -1 -10 L 2 -10 L 4 -12 M 1 -7 L 0 -6 L -1 -4 L -1 -3 L -3 -3 L -4 -2 L -4 0 L -3 -1 L -1 -1 L -1 4 M 0 -5 L 0 2 M -3 -2 L 0 -2 M 1 -7 L 1 1 L 0 3 L -1 4 M 7 -10 L 5 -8 L 4 -5 L 4 6 L 3 8 M 5 -7 L 5 5 M 7 -10 L 6 -8 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -6 8 L -8 6 L -8 4 L -7 3 L -6 3 L -5 4 L -6 5 L -7 5 M -8 4 L -5 4","-12 12 M -10 -10 L -8 -12 L -5 -12 L -3 -11 L -1 -12 M -7 -11 L -4 -11 M -10 -10 L -8 -11 L -6 -10 L -3 -10 L -1 -12 M -5 -7 L -6 -6 L -7 -4 L -7 -3 L -9 -3 L -10 -2 L -10 0 L -9 -1 L -7 -1 L -7 5 M -6 -5 L -6 3 M -9 -2 L -6 -2 M -5 -7 L -5 2 L -6 4 L -7 5 M -8 9 L -5 7 L -2 6 L 1 6 L 3 7 M -6 8 L -4 7 L 0 7 L 2 8 M -8 9 L -4 8 L -1 8 L 1 9 L 3 7 M 0 -9 L -1 -8 L -2 -6 L -2 3 M -1 -7 L -1 1 M 0 -9 L 0 0 L -1 2 L -2 3 M 0 -9 L 2 -11 L 4 -12 L 6 -12 L 8 -11 M 5 -11 L 6 -11 L 7 -10 M 2 -11 L 4 -11 L 6 -9 L 8 -11 M 3 -3 L 6 -6 L 7 -5 L 9 -4 M 5 -5 L 7 -4 L 9 -4 M 9 -4 L 7 -1 L 5 1 L 3 3 M 5 1 L 7 2 L 8 6 L 9 8 L 10 8 M 7 4 L 8 8 M 5 1 L 6 2 L 7 8 L 8 9 L 9 9 L 10 8 M 3 -3 L 3 7","-11 11 M -9 -10 L -7 -12 L -4 -12 L -2 -11 L 0 -12 M -6 -11 L -3 -11 M -9 -10 L -7 -11 L -5 -10 L -2 -10 L 0 -12 M -4 -7 L -5 -6 L -6 -4 L -6 -3 L -8 -3 L -9 -2 L -9 0 L -8 -1 L -6 -1 L -6 5 M -5 -5 L -5 3 M -8 -2 L -5 -2 M -4 -7 L -4 2 L -5 4 L -6 5 M -7 9 L -4 7 L 0 6 L 5 6 L 9 7 M -5 8 L -2 7 L 5 7 L 8 8 M -7 9 L -3 8 L 4 8 L 7 9 L 9 7 M 1 -9 L 0 -8 L -1 -6 L -1 3 M 0 -7 L 0 1 M 1 -9 L 1 0 L 0 2 L -1 3 M 1 -9 L 3 -11 L 5 -12 L 7 -12 L 9 -11 M 6 -11 L 7 -11 L 8 -10 M 3 -11 L 5 -11 L 7 -9 L 9 -11 M 5 -11 L 5 6","-14 14 M -6 -8 L -7 -7 L -8 -5 L -8 -3 L -10 -3 L -11 -2 L -11 0 L -10 -1 L -8 -1 L -8 3 M -7 -6 L -7 1 M -10 -2 L -7 -2 M -6 -8 L -6 0 L -7 2 L -8 3 M -13 9 L -11 7 L -9 6 L -7 6 L -5 7 L -4 7 L -3 6 M -10 7 L -7 7 L -5 8 M -13 9 L -11 8 L -8 8 L -6 9 L -5 9 L -4 8 L -3 6 M -6 -8 L -2 -12 L 2 -8 L 2 5 L 3 7 L 4 7 M -2 -11 L 1 -8 L 1 6 L 0 7 L 1 8 L 2 7 L 1 6 M -2 -2 L 1 -2 M -4 -10 L -3 -10 L 0 -7 L 0 -3 L -3 -3 M -3 -1 L 0 -1 L 0 6 L -1 7 L 1 9 L 4 7 L 5 6 M 2 -8 L 6 -12 L 10 -8 L 10 5 L 11 7 L 12 7 M 6 -11 L 9 -8 L 9 6 L 11 8 M 6 -2 L 9 -2 M 4 -10 L 5 -10 L 8 -7 L 8 -3 L 5 -3 M 5 -1 L 8 -1 L 8 7 L 10 9 L 12 7 M -3 -10 L -3 6 M 5 -10 L 5 6","-13 12 M -11 -9 L -9 -11 L -7 -12 L -5 -12 L -3 -11 L -1 -8 L 4 3 L 6 6 L 7 7 M -5 -11 L -3 -9 L -2 -7 L 4 5 L 7 8 M -9 -11 L -7 -11 L -5 -10 L -3 -7 L 2 4 L 4 7 L 5 8 L 7 9 M 4 -10 L 6 -9 L 8 -9 L 10 -10 L 11 -12 M 5 -11 L 7 -10 L 9 -10 M 4 -10 L 6 -12 L 8 -11 L 10 -11 L 11 -12 M -7 -3 L -9 -3 L -10 -2 L -10 0 L -9 -1 L -7 -1 M -9 -2 L -7 -2 M -11 9 L -9 7 L -7 6 L -4 6 L -2 7 M -8 7 L -5 7 L -3 8 M -11 9 L -8 8 L -5 8 L -4 9 L -2 7 M -7 -11 L -7 6 M 7 -9 L 7 9 M 0 -6 L 1 -5 L 3 -4 L 5 -4 L 7 -5 M -7 2 L -5 1 L -1 1 L 1 2","-13 13 M -4 -12 L -6 -11 L -8 -9 L -9 -7 L -10 -4 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -4 L 9 -7 L 8 -9 L 6 -11 L 4 -12 L 3 -11 L 0 -9 L -3 -8 M -8 -8 L -9 -5 L -9 1 L -8 4 M -4 -12 L -6 -10 L -7 -8 L -8 -5 L -8 1 L -7 4 L -6 6 L -4 8 M 8 4 L 9 1 L 9 -5 L 7 -9 L 6 -10 M 4 8 L 6 6 L 7 4 L 8 1 L 8 -5 L 7 -7 L 5 -10 L 3 -11 M -3 -8 L -3 5 M -2 -8 L -2 3 M -1 -8 L -1 2 L -2 4 L -3 5 M 3 -11 L 3 8 M 3 -5 L 5 -4 L 6 -4 L 8 -5 M 3 1 L 5 0 L 6 0 L 8 1","-10 12 M -7 -12 L -6 -11 L -5 -9 L -5 -3 L -7 -3 L -8 -2 L -8 0 L -7 -1 L -5 -1 L -5 7 L -8 9 L -5 8 L -5 16 L -3 14 M -5 -10 L -4 -8 L -4 14 M -7 -2 L -4 -2 M -7 -12 L -5 -11 L -4 -10 L -3 -8 L -3 14 M -3 -7 L 0 -9 L 4 -12 L 8 -8 L 8 6 M 4 -11 L 7 -8 L 7 6 M 2 -10 L 3 -10 L 6 -7 L 6 7 M 0 6 L 3 6 L 6 7 M 1 7 L 3 7 L 5 8 M 0 8 L 2 8 L 4 9 L 6 7 L 8 6 M 0 -9 L 0 13 M 0 -5 L 2 -4 L 4 -4 L 6 -5 M 0 1 L 2 0 L 4 0 L 6 1","-13 13 M -4 -12 L -6 -11 L -8 -9 L -9 -7 L -10 -4 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -2 9 L 2 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -4 L 9 -7 L 8 -9 L 6 -11 L 4 -12 L 3 -11 L 0 -9 L -3 -8 M -8 -8 L -9 -5 L -9 1 L -8 4 M -4 -12 L -6 -10 L -7 -8 L -8 -5 L -8 1 L -7 4 L -6 6 L -4 8 M 8 4 L 9 1 L 9 -5 L 7 -9 L 6 -10 M 4 8 L 6 6 L 7 4 L 8 1 L 8 -5 L 7 -7 L 5 -10 L 3 -11 M -3 -8 L -3 5 M -2 -8 L -2 3 M -1 -8 L -1 2 L -2 4 L -3 5 M 3 -11 L 3 8 M 3 -5 L 5 -4 L 6 -4 L 8 -5 M 3 1 L 5 0 L 6 0 L 8 1 M -2 9 L -1 8 L 0 8 L 2 9 L 6 14 L 8 15 L 9 15 M 2 10 L 4 13 L 6 15 L 7 15 M 0 8 L 1 9 L 4 15 L 6 16 L 8 16 L 9 15","-12 12 M -10 -10 L -8 -12 L -5 -12 L -3 -11 L -1 -12 M -7 -11 L -4 -11 M -10 -10 L -8 -11 L -6 -10 L -3 -10 L -1 -12 M -5 -7 L -6 -6 L -7 -4 L -7 -3 L -9 -3 L -10 -2 L -10 0 L -9 -1 L -7 -1 L -7 5 M -6 -5 L -6 3 M -9 -2 L -6 -2 M -5 -7 L -5 2 L -6 4 L -7 5 M -8 9 L -5 7 L -2 6 L 0 6 L 3 7 M -6 8 L -4 7 L 0 7 L 2 8 M -8 9 L -4 8 L -1 8 L 1 9 L 3 7 M 0 -9 L -1 -8 L -2 -6 L -2 3 M -1 -7 L -1 1 M 0 -9 L 0 0 L -1 2 L -2 3 M 0 -9 L 3 -11 L 5 -12 L 7 -11 L 8 -9 L 8 -6 L 7 -4 L 6 -3 L 2 -1 L 0 0 M 5 -11 L 6 -11 L 7 -9 L 7 -5 L 6 -4 M 3 -11 L 5 -10 L 6 -8 L 6 -5 L 5 -3 L 2 -1 M 2 -1 L 4 0 L 5 1 L 8 6 L 9 7 L 10 7 M 5 2 L 7 6 L 9 8 M 2 -1 L 4 1 L 6 7 L 8 9 L 10 7","-11 12 M 3 -9 L 2 -10 L 0 -11 L -3 -12 M 4 -10 L 2 -11 M 5 -11 L 1 -12 L -3 -12 L -6 -11 L -7 -10 L -8 -8 L -7 -6 L -6 -5 L -3 -4 L 5 -4 L 7 -3 L 8 -2 L 8 0 L 7 3 M -7 -7 L -6 -6 L -3 -5 L 6 -5 L 8 -4 L 9 -3 L 9 -1 L 8 1 M -7 -10 L -7 -8 L -6 -7 L -3 -6 L 7 -6 L 9 -5 L 10 -3 L 10 -1 L 7 3 L 3 9 M -9 -3 L -8 -2 L -6 -1 L 3 -1 L 4 0 L 4 1 L 3 3 M -8 -1 L -6 0 L 2 0 L 3 1 M -9 -3 L -9 -2 L -8 0 L -6 1 L 1 1 L 3 2 L 3 3 M -9 9 L -6 7 L -2 6 L 1 6 L 4 7 M -7 8 L -4 7 L 0 7 L 3 8 M -9 9 L -5 8 L 0 8 L 3 9 M 5 -11 L 3 -9 L 1 -6 M 0 -4 L -2 -1 M -3 1 L -5 3 L -7 4 L -8 4 L -8 3 L -7 4","-13 11 M -8 -8 L -9 -6 L -10 -3 L -10 1 L -9 4 L -7 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 M -9 1 L -8 4 L -6 6 L -4 7 L -1 8 L 2 8 L 5 7 M -8 -8 L -9 -5 L -9 -1 L -8 2 L -6 5 L -4 6 L -1 7 L 2 7 L 5 6 L 7 5 L 9 3 M -10 -9 L -9 -11 L -7 -12 L -3 -12 L 3 -11 L 7 -11 L 9 -12 M -2 -11 L 2 -10 L 6 -10 M -10 -9 L -9 -10 L -7 -11 L -4 -11 L 2 -9 L 5 -9 L 7 -10 L 9 -12 M 1 -9 L 0 -8 L -2 -7 L -2 4 M -1 -7 L -1 2 M 0 -8 L 0 1 L -1 3 L -2 4 M 5 -9 L 5 6","-12 12 M -10 -10 L -8 -12 L -6 -12 L -3 -11 L -1 -12 M -7 -11 L -4 -11 M -10 -10 L -8 -11 L -5 -10 L -3 -10 L -1 -12 M -7 -8 L -8 -6 L -9 -3 L -9 1 L -8 4 L -7 6 L -5 8 L -2 9 L 1 9 L 4 8 L 6 7 L 8 9 L 10 7 M -8 1 L -7 4 L -4 7 L -1 8 L 2 8 M -7 -8 L -8 -4 L -8 -1 L -7 2 L -6 4 L -4 6 L -1 7 L 3 7 L 6 6 M 3 -9 L -1 -8 L -2 -6 L -2 4 M -1 -7 L -1 2 M 0 -8 L 0 1 L -1 3 L -2 4 M 3 -9 L 5 -10 L 7 -12 L 8 -11 L 10 -10 L 8 -9 L 8 5 L 9 7 L 10 7 M 7 -9 L 8 -10 L 7 -11 L 6 -10 L 7 -9 L 7 6 L 9 8 M 5 -10 L 6 -9 L 6 6 M 3 -9 L 3 7 M 3 -4 L 6 -4 M 3 0 L 6 0","-11 12 M -8 -12 L -7 -11 L -6 -9 L -6 -3 L -8 -3 L -9 -2 L -9 0 L -8 -1 L -6 -1 L -6 6 L -8 7 M -6 -10 L -5 -8 L -5 6 M -8 -2 L -5 -2 M -4 7 L -1 7 L 1 8 M -8 -12 L -6 -11 L -5 -10 L -4 -8 L -4 6 L 0 6 L 3 7 M -8 7 L -5 7 L -2 8 L 0 9 L 3 7 L 6 6 L 8 6 M 0 -8 L 3 -9 L 5 -10 L 7 -12 L 8 -11 L 10 -10 L 8 -9 L 8 6 M 7 -9 L 8 -10 L 7 -11 L 6 -10 L 7 -9 L 7 5 M 5 -10 L 6 -9 L 6 6 M 0 -8 L 0 6 M 0 -5 L 2 -4 L 4 -4 L 6 -5 M 0 1 L 2 0 L 4 0 L 6 1","-13 14 M -10 -12 L -9 -11 L -8 -9 L -8 -3 L -10 -3 L -11 -2 L -11 0 L -10 -1 L -8 -1 L -8 6 L -10 7 M -8 -10 L -7 -8 L -7 6 M -10 -2 L -7 -2 M -6 7 L -4 7 L -2 8 M -10 -12 L -8 -11 L -7 -10 L -6 -8 L -6 6 L -3 6 L -1 7 M -10 7 L -7 7 L -4 8 L -3 9 L -1 7 L 2 6 L 4 7 L 5 9 L 7 7 L 10 6 M -3 -10 L 0 -12 L 2 -10 L 2 6 L 5 6 L 7 7 M 0 -11 L 1 -10 L 1 6 M -3 -10 L -1 -10 L 0 -9 L 0 6 L -1 7 M 5 7 L 6 8 M 5 -10 L 8 -12 L 10 -10 L 10 6 M 8 -11 L 9 -10 L 9 6 M 5 -10 L 7 -10 L 8 -9 L 8 6 L 7 7 M -3 -10 L -3 6 M 5 -10 L 5 6 M -3 -4 L 0 -4 M -3 0 L 0 0 M 5 -4 L 8 -4 M 5 0 L 8 0","-11 11 M -10 -9 L -8 -11 L -6 -12 L -4 -12 L -3 -11 L 5 7 L 6 8 L 8 8 M -5 -11 L -4 -10 L 4 7 L 5 8 M -8 -11 L -6 -11 L -5 -10 L 3 8 L 4 9 L 6 9 L 8 8 L 10 6 M 5 -12 L 7 -11 L 9 -11 L 10 -12 M 5 -11 L 6 -10 L 8 -10 M 4 -10 L 5 -9 L 7 -9 L 9 -10 L 10 -12 M -10 9 L -9 7 L -7 6 L -5 6 L -4 7 M -8 7 L -6 7 L -5 8 M -10 9 L -9 8 L -7 8 L -5 9 M 5 -12 L 1 -3 M -1 0 L -5 9 M -6 -2 L -2 -2 M 1 -2 L 6 -2","-11 12 M -8 -12 L -7 -11 L -6 -9 L -6 -3 L -8 -3 L -9 -2 L -9 0 L -8 -1 L -6 -1 L -6 6 L -8 7 M -6 -10 L -5 -8 L -5 6 M -8 -2 L -5 -2 M -4 7 L -1 7 L 1 8 M -8 -12 L -6 -11 L -5 -10 L -4 -8 L -4 6 L 0 6 L 3 7 M -8 7 L -5 7 L -2 8 L 0 9 L 3 7 L 6 6 M 0 -8 L 3 -9 L 5 -10 L 7 -12 L 8 -11 L 10 -10 L 8 -9 L 8 12 L 7 14 L 5 16 L 3 15 L -1 14 L -6 14 M 7 -9 L 8 -10 L 7 -11 L 6 -10 L 7 -9 L 7 7 M 5 -10 L 6 -9 L 6 6 L 8 9 M 6 15 L 4 14 L 1 14 M 7 14 L 4 13 L -2 13 L -6 14 M 0 -8 L 0 6 M 0 -5 L 2 -4 L 4 -4 L 6 -5 M 0 1 L 2 0 L 4 0 L 6 1","-10 10 M 6 -11 L 5 -9 L 0 -3 L -3 1 L -5 5 L -8 9 M 4 -7 L -4 4 M 8 -12 L 5 -8 L 3 -4 L 0 0 L -5 6 L -6 8 M -8 -10 L -6 -12 L -3 -11 L 3 -11 L 8 -12 M -7 -11 L -3 -10 L 1 -10 L 5 -11 M -8 -10 L -4 -9 L 0 -9 L 4 -10 L 6 -11 M -6 8 L -4 7 L 0 6 L 4 6 L 8 7 M -5 8 L -1 7 L 3 7 L 7 8 M -8 9 L -3 8 L 3 8 L 6 9 L 8 7 M -5 -2 L -1 -2 M 2 -2 L 6 -2","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-11 11 M -11 16 L 11 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-8 9 M -2 0 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9 L 0 7 L 3 6 M -5 4 L -4 6 L -3 7 L -1 8 M -4 2 L -4 4 L -3 6 L -1 7 L 0 7 M -4 -2 L -2 -2 L 1 -3 L 3 -4 L 4 -5 L 6 -3 L 5 -2 L 5 6 L 6 7 L 7 7 M -3 -4 L -4 -3 L -1 -3 M 2 -3 L 5 -3 L 4 -4 L 4 7 L 5 8 M -5 -3 L -3 -5 L -2 -4 L 0 -3 L 3 -2 L 3 7 L 5 9 L 7 7 M -5 -3 L 0 2","-9 9 M -6 -10 L -5 -8 L -5 6 L -7 7 M -4 -8 L -5 -10 L -4 -11 L -4 6 L -1 8 M -6 -10 L -3 -12 L -3 6 L -1 7 L 0 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 3 7 L 5 7 M -3 -2 L 0 -3 L 2 -4 L 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 7 M 2 -4 L 4 -3 L 4 6 M 0 -3 L 1 -3 L 3 -2 L 3 7","-8 6 M -4 -3 L -4 6 L -6 7 L -5 7 L -3 8 L -2 9 M -3 -3 L -3 7 L -1 8 M -2 -3 L -2 6 L 0 7 L 1 7 L -1 8 L -2 9 M -4 -3 L 0 -4 L 2 -5 L 3 -4 L 5 -3 L 6 -3 M 1 -4 L 2 -3 L 4 -3 M -2 -3 L 0 -4 L 2 -2 L 4 -2 L 6 -3","-9 8 M 0 -5 L -2 -4 L -5 -3 L -5 6 L -7 7 M -4 -3 L -4 6 L -1 8 M 0 -5 L -3 -3 L -3 6 L -1 7 L 0 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 3 7 L 5 7 M -5 -10 L -2 -12 L -1 -9 L 5 -3 L 5 7 M -2 -9 L -4 -10 L -3 -11 L -2 -9 L 4 -3 L 4 6 M -5 -10 L 3 -2 L 3 7","-8 6 M -4 -3 L -4 6 L -6 7 L -5 7 L -3 8 L -2 9 M -3 -3 L -3 7 L -1 8 M -2 -3 L -2 6 L 0 7 L 1 7 L -1 8 L -2 9 M -4 -3 L 0 -4 L 2 -5 L 5 -1 L 3 0 L -2 3 M 1 -4 L 4 -1 M -2 -3 L 0 -4 L 3 0","-8 5 M -4 -10 L -4 6 L -6 7 L -5 7 L -3 8 L -2 9 M -3 -10 L -3 7 L -1 8 M -2 -10 L -2 6 L 0 7 L 1 7 L -1 8 L -2 9 M -4 -10 L -1 -11 L 1 -12 L 2 -11 L 4 -10 L 5 -10 M 0 -11 L 1 -10 L 3 -10 M -2 -10 L -1 -11 L 1 -9 L 3 -9 L 5 -10 M -7 -5 L -4 -5 M -2 -5 L 2 -5","-9 9 M -5 -3 L -5 6 L -7 7 L -6 7 L -4 8 L -3 9 L -2 8 L 0 7 L 3 6 M -4 -2 L -4 7 L -2 8 M -3 -3 L -3 6 L -1 7 L 0 7 M -5 -3 L -3 -3 L 0 -4 L 2 -5 L 3 -4 L 5 -3 L 7 -3 L 5 -2 L 5 10 L 4 13 L 2 15 L 0 16 L -1 15 L -3 14 L -5 14 M 1 -4 L 4 -2 L 4 10 M 1 15 L -1 14 L -2 14 M 0 -4 L 1 -3 L 3 -2 L 3 8 L 4 11 L 4 13 M 2 15 L 1 14 L -1 13 L -3 13 L -5 14","-9 9 M -6 -10 L -5 -8 L -5 6 L -7 7 L -6 7 L -4 8 L -3 9 M -4 -8 L -5 -10 L -4 -11 L -4 7 L -2 8 M -6 -10 L -3 -12 L -3 6 L -1 7 L -3 9 M -3 -2 L 0 -3 L 2 -4 L 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 7 L 3 9 L 2 11 M 2 -4 L 4 -3 L 4 7 L 3 9 M 0 -3 L 1 -3 L 3 -2 L 3 7 L 2 11 L 2 14 L 3 16 L 4 16 L 2 14","-5 5 M 0 -12 L -2 -10 L 0 -9 L 2 -10 L 0 -12 M 0 -11 L -1 -10 L 1 -10 L 0 -11 M 0 -5 L -1 -4 L -3 -3 L -1 -2 L -1 7 L 1 9 L 3 7 M 0 -2 L 1 -3 L 0 -4 L -1 -3 L 0 -2 L 0 7 L 1 8 M 0 -5 L 1 -4 L 3 -3 L 1 -2 L 1 6 L 2 7 L 3 7","-5 5 M 0 -12 L -2 -10 L 0 -9 L 2 -10 L 0 -12 M 0 -11 L -1 -10 L 1 -10 L 0 -11 M 0 -5 L -1 -4 L -3 -3 L -1 -2 L -1 7 L 1 9 L 2 11 M 0 -2 L 1 -3 L 0 -4 L -1 -3 L 0 -2 L 0 7 L 1 9 M 0 -5 L 1 -4 L 3 -3 L 1 -2 L 1 7 L 2 11 L 2 14 L 0 16 L -2 16 L -2 15 L 0 16","-9 8 M -6 -10 L -5 -8 L -5 6 L -7 7 L -6 7 L -4 8 L -3 9 M -4 -8 L -5 -10 L -4 -11 L -4 7 L -2 8 M -6 -10 L -3 -12 L -3 6 L -1 7 L -3 9 M -3 -2 L 0 -4 L 2 -5 L 4 -2 L 1 0 L -3 3 M 1 -4 L 3 -2 M 0 -4 L 2 -1 M 1 0 L 2 1 L 4 6 L 5 7 L 6 7 M 1 1 L 2 2 L 3 7 L 4 8 M 0 1 L 1 2 L 2 7 L 4 9 L 6 7","-5 5 M -2 -10 L -1 -8 L -1 6 L -3 7 L -2 7 L 0 8 L 1 9 M 0 -8 L -1 -10 L 0 -11 L 0 7 L 2 8 M -2 -10 L 1 -12 L 1 6 L 3 7 L 4 7 L 2 8 L 1 9","-13 13 M -11 -3 L -10 -3 L -9 -2 L -9 6 L -11 7 L -10 7 L -8 8 L -7 9 M -9 -4 L -8 -3 L -8 7 L -6 8 M -11 -3 L -9 -5 L -7 -3 L -7 6 L -5 7 L -7 9 M -7 -2 L -4 -3 L -2 -4 L -1 -5 L 1 -3 L 1 6 L 3 7 L 1 9 M -2 -4 L 0 -3 L 0 7 L 2 8 M -4 -3 L -3 -3 L -1 -2 L -1 6 L -2 7 L 0 8 L 1 9 M 1 -2 L 4 -3 L 6 -4 L 7 -5 L 8 -4 L 10 -3 L 11 -3 L 9 -2 L 9 6 L 10 7 L 11 7 M 6 -4 L 8 -3 L 8 7 L 9 8 M 4 -3 L 5 -3 L 7 -2 L 7 7 L 9 9 L 11 7","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -7 7 L -6 7 L -4 8 L -3 9 M -5 -4 L -4 -3 L -4 7 L -2 8 M -7 -3 L -5 -5 L -3 -3 L -3 6 L -1 7 L -3 9 M -3 -2 L 0 -3 L 2 -4 L 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 6 L 6 7 L 7 7 M 2 -4 L 4 -3 L 4 7 L 5 8 M 0 -3 L 1 -3 L 3 -2 L 3 7 L 5 9 L 7 7","-9 9 M -5 -3 L -5 6 L -7 7 M -4 -2 L -4 6 L -1 8 M -3 -3 L -3 6 L -1 7 L 0 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 3 7 L 5 7 M -5 -3 L -3 -3 L 0 -4 L 2 -5 L 3 -4 L 5 -3 L 7 -3 L 5 -2 L 5 7 M 1 -4 L 4 -2 L 4 6 M 0 -4 L 1 -3 L 3 -2 L 3 7","-9 9 M -6 -5 L -5 -3 L -5 6 L -7 7 L -5 7 L -5 16 M -5 -4 L -4 -3 L -4 15 L -3 14 L -4 12 M -4 7 L -3 7 L -1 8 M -6 -5 L -4 -4 L -3 -3 L -3 6 L -1 7 L 0 8 M -3 8 L -2 9 L 0 8 L 3 7 L 5 7 M -3 8 L -3 12 L -2 14 L -5 16 M -3 -2 L 0 -3 L 2 -4 L 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 7 M 2 -4 L 4 -3 L 4 6 M 0 -3 L 1 -3 L 3 -2 L 3 7","-9 9 M -5 -3 L -5 6 L -7 7 M -4 -2 L -4 7 L -2 8 M -3 -3 L -3 6 L -1 7 L 0 7 M -7 7 L -6 7 L -4 8 L -3 9 L -2 8 L 0 7 L 3 6 M -5 -3 L -3 -3 L 0 -4 L 2 -5 L 3 -4 L 5 -3 L 7 -3 L 5 -2 L 5 16 M 1 -4 L 4 -2 L 4 15 L 3 14 L 4 12 M 0 -4 L 1 -3 L 3 -2 L 3 12 L 2 14 L 5 16","-8 6 M -6 -3 L -5 -3 L -4 -2 L -4 6 L -6 7 L -5 7 L -3 8 L -2 9 M -5 -4 L -3 -3 L -3 7 L -1 8 M -6 -3 L -4 -5 L -2 -3 L -2 6 L 0 7 L 1 7 L -1 8 L -2 9 M -2 -3 L 2 -5 L 3 -4 L 5 -3 L 6 -3 M 1 -4 L 2 -3 L 4 -3 M 0 -4 L 2 -2 L 4 -2 L 6 -3","-8 8 M -5 -3 L -5 1 L -3 2 L 3 2 L 5 3 L 5 7 M -4 -3 L -4 1 M 4 3 L 4 7 M -2 -4 L -3 -3 L -3 1 L -1 2 M 1 2 L 3 3 L 3 7 L 2 8 M -5 -3 L -2 -4 L 0 -5 L 2 -4 L 4 -4 L 5 -5 M -1 -4 L 1 -4 M -2 -4 L 0 -3 L 2 -3 L 4 -4 M 5 7 L 2 8 L 0 9 L -2 8 L -4 8 L -6 9 M 1 8 L -1 8 M 2 8 L 0 7 L -3 7 L -6 9 M 5 -5 L 4 -3 L 2 0 L -3 5 L -6 9","-5 5 M -2 -10 L -1 -8 L -1 6 L -3 7 L -2 7 L 0 8 L 1 9 M 0 -8 L -1 -10 L 0 -11 L 0 7 L 2 8 M -2 -10 L 1 -12 L 1 6 L 3 7 L 4 7 L 2 8 L 1 9 M -4 -5 L -1 -5 M 1 -5 L 4 -5","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -7 7 M -6 -4 L -4 -3 L -4 7 L -2 8 M -7 -3 L -5 -5 L -3 -3 L -3 6 L -1 7 L 0 7 M -7 7 L -6 7 L -4 8 L -3 9 L -2 8 L 0 7 L 3 6 M 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 6 L 6 7 L 7 7 M 2 -4 L 4 -3 L 4 7 L 5 8 M 3 -5 L 1 -3 L 3 -2 L 3 7 L 5 9 L 7 7","-9 9 M -6 -5 L -5 -3 L -5 6 L -2 9 L 0 7 L 3 6 L 5 6 M -5 -4 L -4 -3 L -4 6 L -1 8 M -6 -5 L -4 -4 L -3 -3 L -3 5 L -2 6 L 0 7 M 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 6 M 2 -4 L 4 -3 L 4 5 M 3 -5 L 1 -3 L 3 -2 L 3 6","-13 13 M -10 -5 L -9 -3 L -9 6 L -6 9 L -4 7 L -1 6 M -9 -4 L -8 -3 L -8 6 L -5 8 M -10 -5 L -8 -4 L -7 -3 L -7 5 L -6 6 L -4 7 M -1 -5 L -3 -3 L -1 -2 L -1 6 L 2 9 L 4 7 L 7 6 L 9 6 M -2 -4 L 0 -3 L 0 6 L 3 8 M -1 -5 L 0 -4 L 2 -3 L 1 -2 L 1 5 L 2 6 L 4 7 M 7 -5 L 8 -4 L 10 -3 L 11 -3 L 9 -2 L 9 6 M 6 -4 L 8 -3 L 8 5 M 7 -5 L 5 -3 L 7 -2 L 7 6","-10 9 M -7 -3 L -6 -3 L -4 -2 L -3 -1 L 1 7 L 2 8 L 4 9 L 6 7 M -5 -4 L -3 -3 L 2 7 L 4 8 M -7 -3 L -5 -5 L -3 -4 L -2 -3 L 2 5 L 3 6 L 5 7 L 6 7 M 0 1 L 3 -5 L 4 -4 L 6 -4 L 7 -5 M 3 -4 L 4 -3 L 5 -3 M 2 -3 L 4 -2 L 6 -3 L 7 -5 M -1 3 L -4 9 L -5 8 L -7 8 L -8 9 M -4 8 L -5 7 L -6 7 M -3 7 L -5 6 L -7 7 L -8 9 M -5 2 L -2 2 M 1 2 L 4 2","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -7 7 M -6 -4 L -4 -3 L -4 7 L -2 8 M -7 -3 L -5 -5 L -3 -3 L -3 6 L -1 7 L 0 7 M -7 7 L -6 7 L -4 8 L -3 9 L -2 8 L 0 7 L 3 6 M 3 -5 L 4 -4 L 6 -3 L 7 -3 L 5 -2 L 5 10 L 4 13 L 2 15 L 0 16 L -1 15 L -3 14 L -5 14 M 2 -4 L 4 -3 L 4 10 M 1 15 L -1 14 L -2 14 M 3 -5 L 1 -3 L 3 -2 L 3 8 L 4 11 L 4 13 M 2 15 L 1 14 L -1 13 L -3 13 L -5 14","-9 9 M 6 -5 L -6 9 M -6 -3 L -4 -2 L -1 -2 L 2 -3 L 6 -5 M -5 -4 L -3 -3 L 1 -3 M -6 -3 L -4 -5 L -2 -4 L 2 -4 L 6 -5 M -6 9 L -2 7 L 1 6 L 4 6 L 6 7 M -1 7 L 3 7 L 5 8 M -6 9 L -2 8 L 2 8 L 4 9 L 6 7 M -4 2 L 4 2","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -gothicger = ["-8 8","-6 6 M 0 -12 L -1 -11 L -3 -10 L -1 -9 L 0 2 M 0 -9 L 1 -10 L 0 -11 L -1 -10 L 0 -9 L 0 2 M 0 -12 L 1 -11 L 3 -10 L 1 -9 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 2 -12 L 4 -11 L 5 -9 L 5 -7 L 7 -8 L 6 -10 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M 6 -8 L 5 -10 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 7 L -6 5 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -5 4 L -5 6 L -4 8 L -2 9","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 7 -4 L 8 -3 L 9 -3 L 10 -4 M 6 -3 L 7 -2 L 9 -2 M 6 -2 L 7 -1 L 8 -1 L 9 -2 L 10 -4 M 7 -4 L 1 2 M 0 3 L -6 9 L -10 4 L -4 -2 M -3 -3 L 1 -7 L -3 -12 L -8 -6 L -2 0 L 2 6 L 4 8 L 6 9 L 8 9 L 9 8 L 10 6 M -6 8 L -9 4 M 0 -7 L -3 -11 M -7 -6 L -2 -1 L 2 5 L 4 7 L 6 8 L 9 8 M -5 8 L -9 3 M 0 -6 L -4 -11 M -7 -7 L -1 -1 L 3 5 L 4 6 L 6 7 L 9 7 L 10 6","-4 5 M 1 -12 L 0 -11 L 0 -5 M 1 -11 L 0 -5 M 1 -12 L 2 -11 L 0 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 M -1 -10 L -2 -7 L -3 -3 L -3 3 L -2 7 L -1 10 M 1 -14 L 0 -12 L -1 -9 L -2 -3 L -2 3 L -1 9 L 0 12 L 1 14","-7 7 M -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16 M 1 -10 L 2 -7 L 3 -3 L 3 3 L 2 7 L 1 10 M -1 -14 L 0 -12 L 1 -9 L 2 -3 L 2 3 L 1 9 L 0 12 L -1 14","-8 8 M 0 -12 L -1 -11 L 1 -1 L 0 0 M 0 -12 L 0 0 M 0 -12 L 1 -11 L -1 -1 L 0 0 M -5 -9 L -4 -9 L 4 -3 L 5 -3 M -5 -9 L 5 -3 M -5 -9 L -5 -8 L 5 -4 L 5 -3 M 5 -9 L 4 -9 L -4 -3 L -5 -3 M 5 -9 L -5 -3 M 5 -9 L 5 -8 L -5 -4 L -5 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-6 6 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-13 13 M -9 0 L 9 0","-6 6 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -3 -10 L -2 -9 L -1 -7 L -1 6 L -3 7 M -1 -9 L -2 -10 L -1 -11 L 0 -9 L 0 7 L 2 8 M -3 -10 L 0 -12 L 1 -10 L 1 6 L 3 7 L 4 7 M -3 7 L -2 7 L 0 8 L 1 9 L 2 8 L 4 7","-10 10 M -6 -10 L -4 -10 L -2 -11 L -1 -12 L 1 -11 L 4 -10 L 6 -10 M -2 -10 L 0 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -10 L 1 -11 M 4 -10 L 4 -2 M 5 -9 L 5 -3 M 6 -10 L 6 -2 L -1 -2 L -4 -1 L -6 1 L -7 4 L -7 9 M -7 9 L -3 7 L 1 6 L 4 6 L 8 7 M -4 8 L -1 7 L 4 7 L 7 8 M -7 9 L -2 8 L 3 8 L 6 9 L 8 7","-10 10 M -6 -10 L -5 -10 L -3 -11 L -2 -12 L 0 -11 L 4 -10 L 6 -10 M -3 -10 L -1 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -11 M 4 -10 L 4 -3 M 5 -9 L 5 -4 M 6 -10 L 6 -3 L 4 -3 L 1 -2 L -1 -1 M -1 -2 L 1 -1 L 4 0 L 6 0 L 6 7 M 5 1 L 5 6 M 4 0 L 4 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M 3 -12 L -7 -2 L -7 3 L 2 3 M 4 3 L 8 3 L 9 4 L 9 2 L 8 3 M -6 -2 L -6 2 M -5 -4 L -5 3 M 2 -11 L 2 6 L 0 7 M 3 -8 L 4 -10 L 3 -11 L 3 7 L 5 8 M 3 -12 L 5 -10 L 4 -8 L 4 6 L 6 7 L 7 7 M 0 7 L 1 7 L 3 8 L 4 9 L 5 8 L 7 7","-10 10 M -6 -12 L -6 -3 M -6 -12 L 6 -12 M -5 -11 L 4 -11 M -6 -10 L 3 -10 L 5 -11 L 6 -12 M 4 -6 L 3 -5 L 1 -4 L -3 -3 L -6 -3 M 1 -4 L 2 -4 L 4 -3 L 4 7 M 3 -5 L 5 -4 L 5 6 M 4 -6 L 5 -5 L 7 -4 L 8 -4 L 6 -3 L 6 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 0 -11 L 2 -12 L 3 -11 L 5 -10 L 6 -10 M 1 -11 L 3 -10 M 0 -11 L 2 -9 L 4 -9 L 6 -10 M -4 -2 L -3 -2 L 1 -3 L 3 -4 L 4 -5 M 1 -3 L 2 -3 L 4 -2 L 4 7 M 3 -4 L 5 -2 L 5 6 M 4 -5 L 5 -4 L 7 -3 L 8 -3 L 6 -2 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -7 -10 L -5 -12 L -2 -11 L 3 -11 L 8 -12 M -6 -11 L -3 -10 L 2 -10 L 5 -11 M -7 -10 L -3 -9 L 0 -9 L 4 -10 L 8 -12 M 8 -12 L 7 -10 L 5 -7 L 1 -3 L -1 0 L -2 3 L -2 6 L -1 9 M 0 -1 L -1 2 L -1 5 L 0 8 M 3 -5 L 1 -2 L 0 1 L 0 4 L 1 7 L -1 9","-10 10 M -6 -9 L -6 -3 M -5 -8 L -5 -4 M -4 -9 L -4 -3 M -6 -9 L -4 -9 L 1 -10 L 3 -11 L 4 -12 M 1 -10 L 2 -10 L 4 -9 L 4 -3 M 3 -11 L 5 -10 L 5 -4 M 4 -12 L 5 -11 L 7 -10 L 8 -10 L 6 -9 L 6 -3 M -6 -3 L -4 -3 L 4 0 L 6 0 M 6 -3 L 4 -3 L -4 0 L -6 0 M -6 0 L -6 6 L -8 7 M -5 1 L -5 6 L -2 8 M -4 0 L -4 6 L -2 7 L -1 8 M 4 0 L 4 7 M 5 1 L 5 6 M 6 0 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 -1 L -8 0 M -5 -9 L -5 0 L -3 1 M -4 -10 L -4 -1 L -2 0 L -1 0 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 0 L -7 0 L -5 1 L -4 2 L -3 1 L -1 0 L 3 -1 L 4 -1 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -8 L -5 -10 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -2 L 1 -1 M -5 -8 L -4 -10 M 4 -10 L 5 -9 L 5 -5 L 4 -4 M -6 -8 L -4 -7 L -4 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 4 -9 L 4 -5 L 3 -3 L 1 -1 M 0 -1 L 0 2 L 1 -1 L -1 -1 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-12 12 M -9 -10 L -8 -9 L -9 -8 L -10 -9 L -9 -11 L -7 -12 L -5 -12 L -3 -11 L -2 -10 L -1 -7 L -1 -3 L -2 0 L -4 2 L -6 3 L -9 4 M -3 -10 L -2 -7 L -2 -2 L -3 0 M -5 -12 L -4 -11 L -3 -8 L -3 -2 L -4 1 L -6 3 M -6 4 L -3 7 M -7 4 L -3 8 M -9 4 L -4 9 L 3 4 M 10 -11 L 9 -10 L 10 -10 L 10 -11 L 9 -12 L 7 -12 L 5 -11 L 4 -10 L 3 -8 L 3 7 L 5 9 L 9 5 M 5 -10 L 4 -8 L 4 6 L 6 8 M 7 -12 L 6 -11 L 5 -8 L 5 5 L 7 7","-13 13 M -11 -1 L -11 0 L -10 1 L -8 1 L -6 0 L -6 -3 L -7 -5 L -9 -8 L -9 -10 L -7 -12 M -7 -3 L -9 -7 M -8 1 L -7 0 L -7 -2 L -9 -5 L -10 -7 L -10 -9 L -9 -11 L -7 -12 L -4 -12 L -2 -11 L -1 -10 L 0 -8 L 0 0 L -1 3 L -3 5 M -2 -10 L -1 -8 L -1 2 M -4 -12 L -3 -11 L -2 -8 L -2 3 L -3 5 M 0 -9 L 1 -11 L 3 -12 L 5 -12 L 7 -11 L 8 -10 L 9 -8 L 10 -7 M 7 -10 L 8 -8 M 5 -12 L 6 -11 L 7 -8 L 8 -7 L 10 -7 M 10 -7 L 0 -2 M 7 -5 L 9 -3 L 10 0 L 10 3 L 9 6 L 7 8 L 4 9 L 1 9 L -2 8 L -8 5 L -9 5 L -10 6 M 6 -4 L 7 -4 L 9 -2 M 4 -4 L 7 -3 L 9 -1 L 10 1 M 2 8 L 0 8 L -6 5 L -7 5 M 8 7 L 6 8 L 3 8 L 0 7 L -4 5 L -7 4 L -9 4 L -10 6 L -10 8 L -9 9 L -8 8 L -9 7","-12 12 M 0 -10 L -2 -12 L -4 -12 L -6 -11 L -8 -8 L -9 -4 L -9 0 L -8 4 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 9 5 M -6 -10 L -7 -8 L -8 -5 L -8 0 L -7 4 L -5 7 L -2 8 M -4 -12 L -5 -11 L -6 -9 L -7 -5 L -7 -1 L -6 3 L -5 5 L -3 7 L 0 8 L 3 8 L 6 7 L 9 5 M 3 -12 L 0 -10 L -1 -9 L -2 -7 L -2 -6 L -1 -4 L 2 -2 L 3 0 L 3 2 M -1 -7 L -1 -6 L 3 -2 L 3 -1 M -1 -9 L -1 -8 L 0 -6 L 3 -4 L 4 -2 L 4 0 L 3 2 L 1 3 L 0 3 L -2 2 L -3 0 M 3 -12 L 4 -11 L 6 -10 L 8 -10 M 3 -11 L 4 -10 L 5 -10 M 2 -11 L 4 -9 L 6 -9 L 8 -10 L 9 -11","-13 13 M -10 -6 L -10 -7 L -9 -9 L -7 -11 L -4 -12 L 0 -12 L 3 -11 L 5 -10 L 7 -8 L 9 -5 L 10 -1 L 10 3 L 9 6 L 7 8 L 4 9 L 1 9 L -2 8 L -8 5 L -9 5 L -10 6 M -7 -10 L -5 -11 L 0 -11 L 3 -10 L 5 -9 L 7 -7 L 9 -4 M 2 8 L 0 8 L -6 5 L -7 5 M -10 -7 L -8 -9 L -5 -10 L 0 -10 L 3 -9 L 5 -8 L 7 -6 L 9 -3 L 10 0 M 8 7 L 6 8 L 3 8 L 0 7 L -4 5 L -7 4 L -9 4 L -10 6 L -10 8 L -9 9 L -8 8 L -9 7 M -2 -10 L -5 -7 L -6 -5 L -6 -3 L -4 1 L -4 3 M -5 -4 L -5 -3 L -4 -1 L -4 0 M -5 -7 L -5 -5 L -3 -1 L -3 1 L -4 3 L -5 4 L -7 4 L -8 3 L -8 2","-12 12 M 0 -10 L -2 -12 L -4 -12 L -6 -11 L -8 -8 L -9 -4 L -9 0 L -8 4 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 9 5 M -6 -10 L -7 -8 L -8 -5 L -8 0 L -7 4 L -5 7 L -2 8 M -4 -12 L -5 -11 L -6 -9 L -7 -5 L -7 -1 L -6 3 L -5 5 L -3 7 L 0 8 L 3 8 L 6 7 L 9 5 M 3 -12 L 0 -10 L -1 -9 L -2 -7 L -2 -6 L -1 -4 L 2 -2 L 3 0 L 3 2 M -1 -7 L -1 -6 L 3 -2 L 3 -1 M -1 -9 L -1 -8 L 0 -6 L 3 -4 L 4 -2 L 4 0 L 3 2 L 1 3 L 0 3 L -2 2 L -3 0 M 3 -12 L 4 -11 L 6 -10 L 8 -10 M 3 -11 L 4 -10 L 5 -10 M 2 -11 L 4 -9 L 6 -9 L 8 -10 L 9 -11 M 3 -4 L 7 -7 M 7 -7 L 8 -6 L 10 -6 M 6 -6 L 7 -5 L 8 -5 M 5 -5 L 6 -4 L 8 -4 L 10 -6","-12 12 M -5 -4 L -7 -5 L -8 -7 L -8 -9 L -7 -11 L -4 -12 L -1 -12 L 2 -11 L 6 -9 M -7 -10 L -5 -11 L 0 -11 L 3 -10 M -8 -7 L -7 -9 L -5 -10 L 0 -10 L 6 -9 L 8 -9 L 9 -10 L 9 -11 L 8 -12 L 7 -12 M 1 -10 L 0 -9 L -1 -7 L -1 -5 L 0 -3 L 4 1 L 5 4 L 5 7 L 4 10 L 3 11 L 1 12 M 2 -2 L 5 1 L 6 4 L 6 7 L 5 9 M -1 -5 L 1 -3 L 4 -1 L 6 1 L 7 4 L 7 7 L 6 9 L 4 11 L 1 12 L -3 12 L -6 11 L -7 10 L -8 8 L -8 5 L -6 2 L -6 0 L -7 -1 M -6 10 L -7 9 L -7 5 L -6 3 M -3 12 L -5 11 L -6 9 L -6 5 L -5 2 L -5 0 L -6 -1 L -8 -1 L -9 0 L -9 1 M 3 -2 L 7 -6 M 7 -6 L 8 -5 L 10 -5 M 6 -5 L 7 -4 L 8 -4 M 5 -4 L 6 -3 L 8 -3 L 10 -5","-13 13 M 3 -8 L 2 -10 L 1 -11 L -1 -12 L -4 -12 L -7 -11 L -9 -8 L -10 -4 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 9 5 L 10 2 L 10 -1 L 9 -4 L 7 -6 M -7 -10 L -8 -8 L -9 -5 L -9 0 L -8 3 L -7 5 M 8 5 L 9 3 L 9 -1 L 8 -4 L 7 -5 M -4 -12 L -6 -11 L -7 -9 L -8 -5 L -8 0 L -7 4 L -6 6 L -4 8 M 5 8 L 7 6 L 8 3 L 8 -1 L 7 -3 L 5 -5 M 3 -12 L 0 -10 L -2 -8 L -3 -6 L -3 -5 L -2 -3 L 1 -1 L 2 1 L 2 3 M -2 -6 L -2 -5 L 2 -1 L 2 0 M -2 -8 L -2 -7 L -1 -5 L 2 -3 L 3 -1 L 3 1 L 2 3 L 0 4 L -1 4 L -3 3 L -4 1 M 2 -3 L 7 -6 L 8 -8 M 10 -12 L 8 -8 M 7 -11 L 11 -9 M 10 -12 L 9 -11 L 7 -11 L 8 -10 L 8 -8 L 9 -9 L 11 -9 L 10 -10 L 10 -12","-12 13 M 0 -12 L -2 -11 L -4 -9 L -5 -7 L -5 -5 L -4 -3 L -2 -1 L -1 1 L -1 3 M -4 -6 L -4 -5 L -1 -1 L -1 0 M -4 -9 L -4 -7 L -3 -5 L -1 -3 L 0 -1 L 0 1 L -1 3 L -2 4 L -4 5 L -6 5 L -8 4 L -9 3 L -10 1 L -10 -1 L -9 -2 L -8 -1 L -9 0 M 0 -12 L 2 -10 L 4 -10 L 6 -11 M -1 -11 L 1 -10 M -2 -11 L -1 -10 L 1 -9 L 3 -9 L 6 -11 M 0 -2 L 7 -7 M 7 -7 L 9 -4 L 10 -1 L 10 2 L 9 5 L 7 7 L 4 8 L 0 9 M 6 -6 L 8 -4 L 9 -1 L 9 3 L 8 5 M 4 -5 L 5 -5 L 7 -3 L 8 0 L 8 4 L 7 6 L 6 7 L 4 8 M 4 8 L 2 8 L 0 7 L -2 7 L -4 8 L -5 10 L -4 12 L -2 13 L 0 13 L 2 12 M 1 8 L -1 8 M 0 9 L -2 8 L -4 8","-12 13 M -2 -2 L -4 -2 L -6 -3 L -7 -4 L -8 -6 L -8 -8 L -7 -10 L -6 -11 L -3 -12 L -1 -12 L 2 -11 L 5 -8 L 7 -7 M -6 -10 L -4 -11 L 0 -11 L 2 -10 L 3 -9 M -8 -8 L -7 -9 L -5 -10 L -1 -10 L 2 -9 L 4 -8 L 7 -7 L 9 -7 L 10 -8 L 10 -10 L 9 -11 L 7 -11 M -8 6 L -7 7 L -8 8 L -9 7 L -9 5 L -8 4 L -6 4 L -4 5 L -2 7 L 0 10 L 2 12 M -4 6 L -3 7 L -1 10 L 0 11 M -6 4 L -5 5 L -4 7 L -2 10 L -1 11 L 1 12 L 4 12 L 6 11 L 7 10 L 8 8 L 8 5 L 7 3 L 5 0 L 4 -2 L 4 -3 M 7 6 L 7 5 L 4 0 L 4 -1 M 6 11 L 7 9 L 7 7 L 6 5 L 4 2 L 3 0 L 3 -2 L 5 -4 L 7 -4 L 8 -3 L 8 -2","-12 13 M -2 -2 L -4 -2 L -6 -3 L -7 -4 L -8 -6 L -8 -8 L -7 -10 L -6 -11 L -3 -12 L -1 -12 L 2 -11 L 5 -8 L 7 -7 M -6 -10 L -4 -11 L 0 -11 L 2 -10 L 3 -9 M -8 -8 L -7 -9 L -5 -10 L -1 -10 L 2 -9 L 4 -8 L 7 -7 L 9 -7 L 10 -8 L 10 -10 L 9 -11 L 7 -11 M -8 6 L -7 7 L -8 8 L -9 7 L -9 5 L -8 4 L -6 4 L -4 5 L -2 7 L 0 10 L 2 12 M -4 6 L -3 7 L -1 10 L 0 11 M -6 4 L -5 5 L -4 7 L -2 10 L -1 11 L 1 12 L 4 12 L 6 11 L 7 10 L 8 8 L 8 5 L 7 3 L 5 0 L 4 -2 L 4 -3 M 7 6 L 7 5 L 4 0 L 4 -1 M 6 11 L 7 9 L 7 7 L 6 5 L 4 2 L 3 0 L 3 -2 L 5 -4 L 7 -4 L 8 -3 L 8 -2","-13 13 M 9 -7 L 8 -9 L 6 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -6 -4 L -5 -1 L -2 5 L -2 7 L -4 9 M -5 -4 L -5 -3 L -2 3 L -2 4 M -4 -10 L -5 -8 L -5 -5 L -4 -3 L -2 1 L -1 4 L -1 6 L -2 8 L -4 9 L -6 9 L -8 8 M -10 4 L -8 8 M -11 7 L -7 5 M -10 4 L -10 6 L -11 7 L -9 7 L -8 8 L -8 6 L -7 5 L -9 5 L -10 4 M -4 -3 L -4 -5 L -3 -7 L -1 -8 L 2 -8 L 4 -7 L 6 -5 L 7 -5 M 3 -7 L 5 -5 M 0 -8 L 2 -7 L 3 -6 L 4 -4 M 7 -5 L -2 -1 M 3 -3 L 7 6 L 8 7 L 9 7 M 2 -2 L 6 6 L 8 8 M 1 -2 L 5 7 L 7 9 L 10 6","-11 12 M 8 1 L 7 2 L 4 2 L 3 1 L 3 -1 L 4 -3 L 6 -6 L 7 -8 L 7 -10 M 4 -1 L 4 -2 L 7 -6 L 7 -7 M 5 2 L 4 1 L 4 0 L 5 -2 L 7 -4 L 8 -6 L 8 -8 L 7 -10 L 6 -11 L 3 -12 L -2 -12 L -5 -11 L -6 -10 L -7 -8 L -7 -6 L -6 -4 L -4 -1 L -3 1 L -3 2 L -4 4 M -6 -7 L -6 -6 L -3 -1 L -3 0 M -6 -10 L -6 -8 L -5 -6 L -3 -3 L -2 -1 L -2 1 L -3 3 L -5 5 L -8 7 M -5 5 L -3 5 L 0 7 L 3 8 L 6 8 L 8 7 M -4 6 L -3 6 L 1 8 L 2 8 M -8 7 L -6 6 L -5 6 L -1 8 L 2 9 L 4 9 L 7 8 L 8 7 L 9 5","-16 16 M -13 -1 L -13 0 L -12 1 L -10 1 L -8 0 L -8 -3 L -9 -5 L -11 -8 L -11 -10 L -9 -12 M -9 -3 L -11 -7 M -10 1 L -9 0 L -9 -2 L -11 -5 L -12 -7 L -12 -9 L -11 -11 L -9 -12 L -7 -12 L -5 -11 L -3 -9 L -2 -6 L -2 0 L -3 3 L -4 5 L -6 7 L -9 9 L -10 8 L -11 8 M -4 -9 L -3 -6 L -3 0 L -4 3 L -5 5 M -8 8 L -9 7 L -10 7 M -7 -12 L -5 -10 L -4 -7 L -4 0 L -5 4 L -6 6 L -7 7 L -8 6 L -9 6 L -12 9 M -4 -11 L -2 -12 L 0 -12 L 2 -11 L 4 -9 L 5 -6 L 5 0 L 4 3 L 3 5 L 1 7 L -1 9 L -2 8 L -3 8 M 3 -9 L 4 -6 L 4 0 L 3 4 M 0 8 L -1 7 L -2 7 M 0 -12 L 2 -10 L 3 -7 L 3 1 L 2 5 L 1 7 L 0 6 L -1 6 L -4 9 M 3 -10 L 4 -11 L 6 -12 L 8 -12 L 10 -11 L 11 -10 L 12 -8 L 13 -7 M 10 -10 L 11 -8 M 8 -12 L 9 -11 L 10 -8 L 11 -7 L 13 -7 M 13 -7 L 10 -5 L 9 -4 L 8 -1 L 8 2 L 9 6 L 11 9 L 14 6 M 10 -4 L 9 -2 L 9 2 L 10 5 L 12 8 M 13 -7 L 11 -5 L 10 -3 L 10 1 L 11 5 L 13 7","-14 14 M -11 -1 L -11 0 L -10 1 L -8 1 L -6 0 L -6 -3 L -7 -5 L -9 -8 L -9 -10 L -7 -12 M -7 -3 L -9 -7 M -8 1 L -7 0 L -7 -2 L -9 -5 L -10 -7 L -10 -9 L -9 -11 L -7 -12 L -4 -12 L -2 -11 L 0 -9 L 1 -6 L 1 0 L 0 3 L -1 5 L -3 7 L -6 9 L -7 8 L -9 8 L -11 9 M -1 -9 L 0 -7 L 0 0 L -1 3 L -2 5 L -3 6 M -5 8 L -7 7 L -9 7 M -4 -12 L -2 -10 L -1 -7 L -1 0 L -2 4 L -4 7 L -6 6 L -8 6 L -11 9 M 0 -10 L 1 -11 L 3 -12 L 5 -12 L 7 -11 L 8 -10 L 9 -8 L 10 -7 M 7 -10 L 8 -8 M 5 -12 L 6 -11 L 7 -8 L 8 -7 L 10 -7 M 10 -7 L 7 -5 L 6 -4 L 5 -1 L 5 2 L 6 6 L 8 9 L 11 6 M 7 -4 L 6 -2 L 6 2 L 7 5 L 9 8 M 10 -7 L 8 -5 L 7 -3 L 7 1 L 8 5 L 10 7","-14 14 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -7 -5 L -5 -1 L -5 1 M -6 -6 L -6 -5 L -5 -3 L -5 -2 M -6 -9 L -6 -7 L -4 -3 L -4 -1 L -5 1 L -6 2 L -8 2 L -9 1 L -9 0 M -2 -12 L -1 -11 L 5 -9 L 8 -7 L 9 -5 L 10 -2 L 10 1 L 9 4 L 8 6 L 6 8 L 3 9 L 0 9 L -3 8 L -9 5 L -10 5 L -11 6 M -2 -11 L -1 -10 L 5 -8 L 7 -7 L 8 -6 M -2 -12 L -2 -10 L -1 -9 L 5 -7 L 7 -6 L 9 -4 L 10 -2 M 1 8 L -1 8 L -7 5 L -8 5 M 7 7 L 5 8 L 2 8 L -1 7 L -5 5 L -8 4 L -10 4 L -11 6 L -11 8 L -10 9 L -9 8 L -10 7","-13 14 M -10 -1 L -10 0 L -9 1 L -7 1 L -5 0 L -5 -3 L -6 -5 L -8 -8 L -8 -10 L -6 -12 M -6 -3 L -8 -7 M -7 1 L -6 0 L -6 -2 L -8 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -3 -12 L -1 -11 L 0 -10 L 1 -8 L 1 3 M 1 5 L 1 10 L 0 12 L -2 13 L -5 13 L -6 12 L -6 10 L -5 9 L -4 10 L -5 11 M -1 -10 L 0 -8 L 0 10 L -1 12 M -3 -12 L -2 -11 L -1 -8 L -1 3 M -1 5 L -1 10 L -2 12 L -3 13 M 1 -8 L 6 -12 M 6 -12 L 8 -9 L 9 -7 L 10 -3 L 10 0 L 9 3 L 7 6 L 4 9 M 5 -11 L 8 -7 L 9 -4 L 9 -3 M 4 -10 L 6 -8 L 8 -5 L 9 -2 L 9 1 L 8 4 L 7 6 M 5 7 L 3 4 L 1 3 M -1 3 L -3 4 L -5 6 M 5 8 L 3 5 L 1 4 L -2 4 M 4 9 L 2 6 L 1 5 M -1 5 L -3 5 L -5 6","-14 14 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -7 -5 L -5 -1 L -5 1 M -6 -6 L -6 -5 L -5 -3 L -5 -2 M -6 -9 L -6 -7 L -4 -3 L -4 -1 L -5 1 L -6 2 L -8 2 L -9 1 L -9 0 M -2 -12 L -1 -11 L 5 -9 L 8 -7 L 9 -5 L 10 -2 L 10 1 L 9 4 L 8 6 M 6 8 L 3 9 L 0 9 L -3 8 L -9 5 L -10 5 L -11 6 M -2 -11 L -1 -10 L 5 -8 L 7 -7 L 8 -6 M -2 -12 L -2 -10 L -1 -9 L 5 -7 L 7 -6 L 9 -4 L 10 -2 M 1 8 L -1 8 L -7 5 L -8 5 M 6 8 L 2 8 L -1 7 L -5 5 L -8 4 L -10 4 L -11 6 L -11 8 L -10 9 L -9 8 L -10 7 M 2 6 L 4 4 L 6 4 L 10 8 L 11 8 M 5 5 L 6 5 L 9 8 M 3 5 L 4 5 L 8 9 L 10 9 L 12 7","-14 14 M -11 -1 L -11 0 L -10 1 L -8 1 L -6 0 L -6 -3 L -7 -5 L -9 -8 L -9 -10 L -7 -12 M -7 -3 L -9 -7 M -8 1 L -7 0 L -7 -2 L -9 -5 L -10 -7 L -10 -9 L -9 -11 L -7 -12 L -4 -12 L -2 -11 L -1 -10 L 0 -8 L 0 4 L -1 6 L -3 8 L -5 9 L -7 9 L -9 8 M -2 -10 L -1 -8 L -1 4 L -2 6 M -4 -12 L -3 -11 L -2 -8 L -2 4 L -3 7 L -5 9 M -11 4 L -9 8 M -12 7 L -8 5 M -11 4 L -11 6 L -12 7 L -10 7 L -9 8 L -9 6 L -8 5 L -10 5 L -11 4 M 0 -9 L 1 -11 L 3 -12 L 5 -12 L 7 -11 L 8 -10 L 9 -8 L 10 -7 M 7 -10 L 8 -8 M 5 -12 L 6 -11 L 7 -8 L 8 -7 L 10 -7 M 10 -7 L 0 -2 M 2 -3 L 6 7 L 8 9 L 11 6 M 3 -3 L 7 6 L 9 8 M 4 -4 L 8 6 L 9 7 L 10 7","-13 14 M 10 -10 L 9 -11 L 10 -12 L 11 -11 L 11 -9 L 10 -7 L 8 -7 L 4 -9 L 1 -10 L -3 -10 L -7 -9 L -9 -7 M 7 -8 L 4 -10 L 1 -11 L -3 -11 L -6 -10 M 11 -9 L 10 -8 L 8 -8 L 4 -11 L 1 -12 L -3 -12 L -6 -11 L -8 -9 L -9 -7 L -10 -4 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 3 9 L 6 8 L 8 7 L 10 5 L 11 2 L 11 -1 L 10 -3 L 8 -4 L 5 -4 L 3 -3 L 1 0 L -1 1 L -3 1 M -6 6 L -4 7 L -1 8 L 3 8 L 7 7 M -9 3 L -7 5 L -5 6 L -2 7 L 3 7 L 7 6 L 9 5 L 10 4 L 11 2 M 6 -3 L 5 -3 L 1 1 L 0 1 M 11 -1 L 9 -3 L 7 -3 L 5 -2 L 3 1 L 1 2 L -1 2 L -3 1 L -4 -1 L -4 -3 L -3 -5 L -1 -6","-12 13 M -6 -4 L -8 -5 L -9 -7 L -9 -9 L -8 -11 L -5 -12 L 0 -12 L 3 -11 L 7 -8 L 9 -8 L 10 -9 M -8 -10 L -6 -11 L 0 -11 L 3 -10 L 6 -8 M -9 -7 L -8 -9 L -6 -10 L 0 -10 L 3 -9 L 7 -7 L 9 -7 L 10 -9 L 10 -11 L 9 -12 L 8 -11 L 9 -10 M 3 -9 L 0 -6 L -1 -4 L -1 -2 L 1 2 L 1 4 M 0 -3 L 0 -2 L 1 0 L 1 1 M 0 -6 L 0 -4 L 2 0 L 2 2 L 1 4 L 0 5 L -2 5 L -3 4 L -3 2 M -8 7 L -7 8 L -8 9 L -9 8 L -9 6 L -8 4 L -6 4 L -3 5 L 1 7 L 4 8 L 7 8 L 9 7 M -6 5 L -5 5 L 1 8 L 3 8 M -9 6 L -8 5 L -7 5 L -5 6 L -1 8 L 2 9 L 5 9 L 8 8 L 10 6","-11 11 M -8 -10 L -7 -10 L -6 -9 L -6 5 L -8 6 M -7 -11 L -5 -10 L -5 6 L -2 8 M -9 -9 L -6 -12 L -4 -10 L -4 5 L -2 7 L 0 7 M -8 6 L -7 6 L -5 7 L -3 9 L 0 7 L 4 4 M 2 -10 L 3 -10 L 4 -9 L 4 7 L 6 9 L 9 6 M 3 -11 L 5 -10 L 5 7 L 7 8 M 1 -9 L 4 -12 L 7 -10 L 6 -9 L 6 6 L 7 7 L 8 7","-14 14 M -11 -1 L -11 0 L -10 1 L -8 1 L -6 0 L -6 -3 L -7 -5 L -9 -8 L -9 -10 L -7 -12 M -7 -3 L -9 -7 M -8 1 L -7 0 L -7 -2 L -9 -5 L -10 -7 L -10 -9 L -9 -11 L -7 -12 L -4 -12 L -2 -11 L -1 -10 L 0 -8 L 0 0 L -1 3 L -3 5 M -2 -10 L -1 -8 L -1 2 M -4 -12 L -3 -11 L -2 -8 L -2 3 L -3 5 M 0 -9 L 1 -11 L 3 -12 L 5 -12 L 7 -11 L 9 -8 L 10 -7 M 7 -10 L 8 -8 M 5 -12 L 6 -11 L 7 -8 L 8 -7 L 10 -7 M 8 -7 L 6 -7 L 5 -6 L 5 -4 L 6 -2 L 9 0 L 10 2 M 6 -3 L 9 -1 M 5 -5 L 6 -4 L 9 -2 L 10 0 L 10 4 L 9 6 L 7 8 L 5 9 L 1 9 L -2 8 L -8 5 L -9 5 L -10 6 M 2 8 L 0 8 L -6 5 L -7 5 M 8 7 L 6 8 L 3 8 L 0 7 L -4 5 L -7 4 L -9 4 L -10 6 L -10 8 L -9 9 L -8 8 L -9 7","-16 17 M -13 -1 L -13 0 L -12 1 L -10 1 L -8 0 L -8 -3 L -9 -5 L -11 -8 L -11 -10 L -9 -12 M -9 -3 L -11 -7 M -10 1 L -9 0 L -9 -2 L -11 -5 L -12 -7 L -12 -9 L -11 -11 L -9 -12 L -6 -12 L -4 -11 L -3 -10 L -2 -8 L -2 -4 L -3 -1 L -5 2 L -7 4 M -4 -10 L -3 -8 L -3 -3 L -4 0 M -6 -12 L -5 -11 L -4 -8 L -4 -3 L -5 1 L -7 4 M -4 -11 L -2 -12 L 1 -12 L 3 -11 M 5 -12 L 2 -11 L 1 -9 L 1 -5 L 2 -2 L 4 1 L 5 3 L 5 5 L 4 7 M 2 -5 L 2 -4 L 5 1 L 5 2 M 5 -12 L 3 -11 L 2 -9 L 2 -6 L 3 -4 L 5 -1 L 6 2 L 6 4 L 5 6 L 3 8 L 1 9 L -3 9 L -5 8 L -7 6 L -9 5 L -11 5 L -12 6 M -4 8 L -7 5 L -8 5 M -1 9 L -3 8 L -6 5 L -8 4 L -11 4 L -12 6 L -12 8 L -11 9 L -10 8 L -11 7 M 5 -12 L 8 -12 L 10 -11 L 12 -8 L 13 -7 M 10 -10 L 11 -8 M 8 -12 L 9 -11 L 10 -8 L 11 -7 L 13 -7 M 11 -7 L 9 -7 L 8 -6 L 8 -4 L 9 -2 L 12 0 L 13 2 M 9 -3 L 12 -1 M 8 -5 L 9 -4 L 12 -2 L 13 0 L 13 5 L 12 7 L 11 8 L 9 9 L 6 9 L 3 8 M 7 8 L 6 8 L 4 7 M 12 7 L 10 8 L 8 8 L 6 7 L 5 6","-12 12 M -7 -10 L -5 -10 L -3 -9 L -2 -8 L -1 -5 L -1 -3 M -1 -1 L -1 3 L -2 6 L -5 9 L -7 8 L -9 9 M -4 8 L -6 7 L -7 7 M -3 7 L -4 7 L -6 6 L -9 9 M -5 -11 L -2 -10 L -1 -9 L 0 -6 L 0 3 L 1 5 L 3 7 L 5 8 M -9 -9 L -4 -12 L -2 -11 L 0 -9 L 1 -6 L 1 -3 M 1 -1 L 1 2 L 2 5 L 3 6 L 5 7 L 7 7 M -1 3 L 0 6 L 2 8 L 4 9 L 9 6 M 1 -6 L 2 -9 L 5 -12 L 7 -11 L 9 -12 M 4 -11 L 6 -10 L 7 -10 M 3 -10 L 4 -10 L 6 -9 L 9 -12 M -7 1 L -5 -3 L -1 -3 M 1 -3 L 5 -3 L 7 -5 M -5 -2 L 5 -2 M -7 1 L -5 -1 L -1 -1 M 1 -1 L 5 -1 L 7 -5","-13 13 M -10 -1 L -10 0 L -9 1 L -7 1 L -5 0 L -5 -3 L -6 -5 L -8 -8 L -8 -10 L -6 -12 M -6 -3 L -8 -7 M -7 1 L -6 0 L -6 -2 L -8 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -3 -12 L -1 -11 L 0 -10 L 1 -8 L 1 -3 L 0 0 L -1 2 L -1 3 L 1 5 L 2 5 M -1 -10 L 0 -8 L 0 -2 L -1 1 L -2 3 L 1 6 M -3 -12 L -2 -11 L -1 -8 L -1 -2 L -2 2 L -3 4 L 0 7 L 3 4 M 1 -8 L 9 -12 M 7 -11 L 7 8 L 6 11 M 8 -11 L 8 6 L 7 9 M 9 -12 L 9 4 L 8 8 L 7 10 L 5 12 L 2 13 L -2 13 L -5 12 L -7 10 L -8 8 L -7 7 L -6 8 L -7 9","-12 12 M -4 -9 L -3 -11 L -1 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -5 L 5 -3 L 4 -2 L 2 -1 M -1 -1 L -3 -2 L -4 -4 M 4 -10 L 5 -9 L 5 -4 L 4 -3 M 2 -12 L 3 -11 L 4 -9 L 4 -4 L 3 -2 L 2 -1 M -5 3 L -4 1 L -3 0 L -1 -1 L 2 -1 L 5 0 L 7 2 L 8 4 L 8 8 L 7 10 L 5 12 L 2 13 L -2 13 L -4 12 L -7 8 L -8 7 M 6 2 L 7 4 L 7 8 L 6 10 M 2 -1 L 5 1 L 6 3 L 6 9 L 5 11 L 4 12 L 2 13 M -3 12 L -4 11 L -6 8 L -7 7 M 0 13 L -2 12 L -3 11 L -5 8 L -6 7 L -9 7 L -10 8 L -10 10 L -9 11 L -8 11","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-12 12 M -12 16 L 12 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-8 9 M 2 -5 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 4 L -4 7 L -3 9 L 3 6 M -4 4 L -3 7 L -2 8 M -1 -4 L -3 -2 L -4 1 L -4 3 L -3 6 L -1 8 M 0 -4 L 1 -3 L 3 -2 L 3 7 L 5 9 L 8 6 M 1 -4 L 4 -2 L 4 6 L 6 8 M 2 -5 L 3 -4 L 5 -3 L 6 -3 M 5 -2 L 6 -3 M 5 -2 L 5 6 L 6 7 L 7 7","-8 9 M -6 -10 L -5 -9 L -4 -7 M 2 -12 L -1 -11 L -3 -9 L -4 -7 L -4 6 L -5 7 M -2 -9 L -3 -7 L -3 6 L 0 8 M 2 -12 L 0 -11 L -1 -10 L -2 -7 L -2 6 L 0 7 L 1 8 M -5 7 L -4 7 L -2 8 L -1 9 L 2 8 M -2 -2 L 4 -5 L 5 -3 L 6 0 L 6 3 L 5 6 L 4 7 L 2 8 M 3 -4 L 4 -3 L 5 -1 M 2 -4 L 4 -2 L 5 1 L 5 3 L 4 6 L 2 8","-7 6 M 0 -4 L 2 -2 L 4 -3 L 2 -5 L 0 -4 L -3 -2 L -4 0 L -4 5 L -3 7 L -1 9 L 3 7 M 1 -4 L 3 -3 M -2 -2 L -3 0 L -3 5 L -2 7 L -1 8 M -1 -3 L -2 -1 L -2 4 L -1 6 L 1 8","-8 9 M -1 -12 L -4 -9 L -4 -7 L -3 -6 L 1 -4 L 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 M -3 -8 L -3 -7 L 1 -5 L 4 -3 L 5 -2 M -3 -10 L -3 -9 L -2 -8 L 3 -5 L 5 -3 L 6 0 L 6 3 L 5 6 L 2 8 L -1 9 M 0 -4 L -4 -2 L -4 6 L -5 7 M -3 -2 L -3 6 L 0 8 M -2 -3 L -2 6 L 0 7 L 1 8 M -5 7 L -4 7 L -2 8 L -1 9","-7 6 M -2 3 L 4 -1 L 1 -5 L -3 -2 L -4 0 L -4 5 L -3 7 L -1 9 L 3 7 M 3 -1 L 0 -4 M -2 -2 L -3 0 L -3 5 L -2 7 L -1 8 M 2 0 L 0 -3 L -1 -3 L -2 -1 L -2 4 L -1 6 L 1 8","-6 7 M 6 -12 L 5 -11 L 3 -11 L 1 -12 L -1 -12 L -2 -10 L -2 -5 L -3 -3 L -4 -2 M 4 -10 L 2 -10 L 0 -11 L -1 -11 M 6 -12 L 5 -10 L 4 -9 L 2 -9 L 0 -10 L -1 -10 L -2 -9 M -2 -7 L -1 -5 L 0 -4 L 2 -3 L 4 -3 L 4 -2 M -4 -2 L -2 -2 M 0 -2 L 4 -2 M -2 -2 L -2 2 L -1 14 M 1 -3 L -2 -3 L -1 -4 L -1 9 M 0 -2 L 0 2 L -1 14","-8 9 M 2 -5 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 4 L -4 7 L -3 9 L 3 6 M -4 5 L -3 7 L -2 8 M -1 -4 L -3 -2 L -4 1 L -4 3 L -3 6 L -1 8 M 0 -4 L 1 -3 L 3 -2 L 3 6 L 4 9 L 4 11 L 3 13 M 1 -4 L 4 -2 L 4 8 M 2 -5 L 3 -4 L 5 -3 L 6 -3 M 5 -2 L 6 -3 M 5 -2 L 5 10 L 4 12 L 3 13 L 1 14 L -2 14 L -4 13 L -5 12 L -5 11 L -4 11 L -4 12","-8 9 M -6 -10 L -5 -9 L -4 -7 M 2 -12 L -1 -11 L -3 -9 L -4 -7 L -4 6 L -5 7 M -2 -9 L -3 -7 L -3 7 L -2 8 M 2 -12 L 0 -11 L -1 -10 L -2 -7 L -2 6 L -1 7 L 0 7 M -5 7 L -3 8 L -2 9 L 1 6 M -2 -2 L 4 -5 L 5 -3 L 6 1 L 6 5 L 5 8 L 4 10 L 2 12 L -1 14 M 3 -4 L 4 -3 L 5 0 M 2 -4 L 4 -1 L 5 2 L 5 5 L 4 9 L 2 12","-5 5 M 0 -12 L -1 -11 L -1 -10 L 0 -9 L 1 -10 L 1 -11 L 0 -12 M -1 -11 L 1 -10 M -1 -10 L 1 -11 M -3 -3 L -2 -3 L -1 -2 L -1 7 L 1 9 L 4 6 M -2 -4 L 0 -3 L 0 6 L 2 8 M -4 -2 L -1 -5 L 0 -4 L 2 -3 M 1 -2 L 2 -3 M 1 -2 L 1 6 L 2 7 L 3 7","-5 5 M 0 -12 L -1 -11 L -1 -10 L 0 -9 L 1 -10 L 1 -11 L 0 -12 M -1 -11 L 1 -10 M -1 -10 L 1 -11 M -3 -3 L -2 -3 L -1 -2 L -1 9 L -2 12 L -3 13 L -5 14 M -2 -4 L 0 -3 L 0 9 L -1 11 M -4 -2 L -1 -5 L 0 -4 L 2 -3 M 1 -2 L 2 -3 M 1 -2 L 1 9 L 0 11 L -2 13 L -5 14 M 1 9 L 2 11 L 3 12","-7 7 M -4 -10 L -3 -9 L -2 -7 M 3 -12 L 1 -11 L -1 -9 L -2 -7 L -2 -5 L -3 -3 L -4 -2 M -2 -2 L -2 6 L -3 7 M 0 -9 L -1 -7 L -1 -5 M -1 -3 L -2 -3 L -1 -5 L -1 6 L 1 8 M 3 -12 L 1 -10 L 0 -7 L 0 -3 M 0 -2 L 0 6 L 1 7 L 2 7 M -3 7 L -1 8 L 0 9 L 3 6 M 0 -6 L 4 -9 L 5 -8 L 5 -6 L 3 -4 L 1 -3 M 3 -8 L 4 -7 L 4 -6 L 3 -4 M 0 -3 L 5 -3 L 5 -2 M -4 -2 L -2 -2 M 0 -2 L 5 -2","-5 5 M -3 -10 L -2 -9 L -1 -7 M 5 -12 L 2 -11 L 0 -9 L -1 -7 L -1 6 L -2 7 M 1 -9 L 0 -7 L 0 7 L 2 8 M 5 -12 L 3 -11 L 2 -10 L 1 -7 L 1 6 L 2 7 L 3 7 M -2 7 L 0 8 L 1 9 L 4 6","-13 13 M -11 -3 L -10 -3 L -9 -2 L -9 6 L -10 7 L -8 9 M -10 -4 L -8 -2 L -8 6 L -9 7 L -8 8 L -7 7 L -8 6 M -12 -2 L -9 -5 L -7 -3 L -7 6 L -6 7 L -8 9 M -4 -4 L -2 -3 L -1 -1 L -1 6 L -2 7 L 0 9 M -2 -4 L -1 -3 L 0 -1 L 0 6 L -1 7 L 0 8 L 1 7 L 0 6 M -7 -2 L -4 -4 L -2 -5 L 0 -4 L 1 -2 L 1 6 L 2 7 L 0 9 M 4 -4 L 5 -3 L 7 -2 L 7 7 L 9 9 L 12 6 M 5 -4 L 8 -2 L 8 6 L 10 8 M 1 -2 L 4 -4 L 6 -5 L 7 -4 L 9 -3 L 10 -3 M 9 -2 L 10 -3 M 9 -2 L 9 6 L 10 7 L 11 7","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -6 7 L -4 9 M -6 -4 L -4 -2 L -4 6 L -5 7 L -4 8 L -3 7 L -4 6 M -8 -2 L -5 -5 L -3 -3 L -3 6 L -2 7 L -4 9 M 0 -4 L 1 -3 L 3 -2 L 3 7 L 5 9 L 8 6 M 1 -4 L 4 -2 L 4 6 L 6 8 M -3 -2 L 0 -4 L 2 -5 L 3 -4 L 5 -3 L 6 -3 M 5 -2 L 6 -3 M 5 -2 L 5 6 L 6 7 L 7 7","-8 9 M -4 -2 L -4 6 L -5 7 M -3 -2 L -3 6 L 0 8 M -1 -3 L -2 -2 L -2 6 L 0 7 L 1 8 M -5 7 L -4 7 L -2 8 L -1 9 L 2 8 M -4 -2 L -1 -3 L 4 -5 L 5 -3 L 6 0 L 6 3 L 5 6 L 4 7 L 2 8 M 3 -4 L 4 -3 L 5 -1 M 2 -4 L 4 -2 L 5 1 L 5 3 L 4 6 L 2 8","-8 9 M -3 -8 L -5 -6 L -5 -4 L -4 -1 L -4 6 L -6 8 M -4 7 L -3 14 M -4 -5 L -4 -4 L -3 -1 L -3 9 M -4 -7 L -4 -6 L -3 -4 L -2 -1 L -2 6 L -1 6 L 1 7 L 2 8 M -2 7 L -3 14 M 1 8 L -1 7 M 2 8 L 0 9 L -2 7 M -4 7 L -6 8 M -2 -2 L 4 -5 L 5 -3 L 6 0 L 6 3 L 5 6 L 4 7 L 2 8 M 3 -4 L 4 -3 L 5 -1 M 2 -4 L 4 -2 L 5 1 L 5 3 L 4 6 L 2 8","-8 9 M 2 -5 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 4 L -4 7 L -3 9 L 3 6 M -4 5 L -3 7 L -2 8 M -1 -4 L -3 -2 L -4 1 L -4 3 L -3 6 L -1 8 M 0 -4 L 1 -3 L 3 -2 L 3 6 L 4 14 M 1 -4 L 4 -2 L 4 9 M 2 -5 L 3 -4 L 5 -3 L 6 -3 M 5 -2 L 6 -3 M 5 -2 L 5 6 L 4 14","-7 7 M -4 -3 L -3 -3 L -2 -2 L -2 6 L -3 7 M -3 -4 L -1 -2 L -1 7 L 1 8 M -5 -2 L -2 -5 L 0 -3 L 0 6 L 1 7 L 2 7 M -3 7 L -1 8 L 0 9 L 3 6 M 2 -4 L 3 -2 L 5 -3 L 4 -5 L 0 -3 M 3 -4 L 4 -3","-6 5 M 6 -12 L 5 -11 L 3 -11 L 1 -12 L -1 -12 L -2 -10 L -2 -5 L -3 -3 L -4 -2 M 4 -10 L 2 -10 L 0 -11 L -1 -11 M 6 -12 L 5 -10 L 4 -9 L 2 -9 L 0 -10 L -1 -10 L -2 -9 M -2 -7 L 0 -2 M -2 -2 L -2 2 L -1 14 M -1 -3 L -2 -3 L -1 -4 L -1 9 M 0 -2 L 0 2 L -1 14 M -4 -2 L -2 -2","-6 6 M 1 -9 L 0 -6 L -1 -4 L -2 -3 L -4 -2 M 1 -9 L 1 -3 L 4 -3 L 4 -2 M -4 -2 L -1 -2 M 1 -2 L 4 -2 M -1 -2 L -1 6 L -2 7 M 0 -3 L -1 -3 L 0 -5 L 0 6 L 2 8 M 1 -2 L 1 6 L 2 7 L 3 7 M -2 7 L 0 8 L 1 9 L 4 6","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -6 7 M -6 -4 L -4 -2 L -4 6 L -2 8 M -8 -2 L -5 -5 L -3 -3 L -3 6 L -1 7 L 0 8 M -6 7 L -5 7 L -3 8 L -2 9 L 0 8 L 3 6 M 4 -5 L 2 -3 L 3 -2 L 3 7 L 5 9 L 8 6 M 4 -2 L 5 -3 L 4 -4 L 3 -3 L 4 -2 L 4 6 L 6 8 M 4 -5 L 6 -3 L 5 -2 L 5 6 L 6 7 L 7 7","-8 9 M -3 -7 L -5 -5 L -5 -3 L -4 0 L -4 6 L -5 7 M -4 -4 L -4 -3 L -3 0 L -3 6 L 0 8 M -4 -6 L -4 -5 L -3 -3 L -2 0 L -2 6 L 0 7 L 1 8 M -5 7 L -4 7 L -2 8 L -1 9 L 2 8 M -2 -2 L 4 -5 L 5 -3 L 6 0 L 6 3 L 5 6 L 4 7 L 2 8 M 3 -4 L 4 -3 L 5 -1 M 2 -4 L 4 -2 L 5 1 L 5 3 L 4 6 L 2 8","-12 13 M -7 -7 L -9 -5 L -9 -3 L -8 0 L -8 6 L -9 7 L -7 9 M -8 -4 L -8 -3 L -7 0 L -7 6 L -8 7 L -7 8 L -6 7 L -7 6 M -8 -6 L -8 -5 L -7 -3 L -6 0 L -6 6 L -5 7 L -7 9 M -3 -4 L -1 -3 L 0 -1 L 0 6 L -1 7 M -1 -4 L 0 -3 L 1 -1 L 1 6 L 4 8 M -6 -2 L -3 -4 L -1 -5 L 1 -4 L 2 -2 L 2 6 L 4 7 L 5 8 M -1 7 L 0 7 L 2 8 L 3 9 L 6 8 M 2 -2 L 8 -5 L 9 -3 L 10 0 L 10 2 L 9 6 L 8 7 L 6 8 M 7 -4 L 8 -3 L 9 -1 M 6 -4 L 8 -2 L 9 1 L 9 3 L 8 6 L 6 8","-7 8 M -3 -3 L -2 -3 L -1 -2 L -1 6 L -2 6 L -4 7 L -5 9 L -5 11 L -4 13 L -2 14 L 1 14 L 4 13 L 4 12 L 3 12 L 3 13 M -2 -4 L 0 -2 L 0 6 L 3 8 M -4 -2 L -1 -5 L 1 -3 L 1 6 L 3 7 L 4 8 M 6 7 L 2 9 L 1 8 L -1 7 L -3 7 L -5 9 M 3 -4 L 4 -2 L 6 -3 L 5 -5 L 1 -3 M 4 -4 L 5 -3","-8 9 M -3 -7 L -5 -5 L -5 -3 L -4 0 L -4 6 L -5 7 M -4 -4 L -4 -3 L -3 0 L -3 7 L -1 8 M -4 -6 L -4 -5 L -3 -3 L -2 0 L -2 6 L -1 7 L 0 7 M -5 7 L -3 8 L -2 9 L 1 6 M -2 -2 L 4 -5 L 5 -3 L 6 1 L 6 5 L 5 8 L 4 10 L 2 12 L -1 14 M 3 -4 L 4 -3 L 5 0 M 2 -4 L 4 -1 L 5 2 L 5 5 L 4 9 L 2 12","-7 7 M -4 -2 L 1 -5 L 3 -4 L 4 -2 L 4 0 L 3 2 L -1 4 M 1 -4 L 3 -3 M 0 -4 L 2 -3 L 3 -1 L 3 0 L 2 2 L 1 3 M 1 3 L 3 5 L 4 7 L 4 11 L 3 13 L 1 14 L -1 14 L -3 13 L -4 11 L -4 9 L -3 7 L -1 6 L 5 4 M 0 4 L 2 5 L 3 7 M -1 4 L 2 6 L 3 8 L 3 11 L 2 13 L 1 14","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -gothicita = ["-8 8","-6 6 M 0 -12 L -1 -11 L -3 -10 L -1 -9 L 0 2 M 0 -9 L 1 -10 L 0 -11 L -1 -10 L 0 -9 L 0 2 M 0 -12 L 1 -11 L 3 -10 L 1 -9 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 2 -12 L 4 -11 L 5 -9 L 5 -7 L 7 -8 L 6 -10 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M 6 -8 L 5 -10 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 7 L -6 5 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -5 4 L -5 6 L -4 8 L -2 9","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 7 -4 L 8 -3 L 9 -3 L 10 -4 M 6 -3 L 7 -2 L 9 -2 M 6 -2 L 7 -1 L 8 -1 L 9 -2 L 10 -4 M 7 -4 L 1 2 M 0 3 L -6 9 L -10 4 L -4 -2 M -3 -3 L 1 -7 L -3 -12 L -8 -6 L -2 0 L 2 6 L 4 8 L 6 9 L 8 9 L 9 8 L 10 6 M -6 8 L -9 4 M 0 -7 L -3 -11 M -7 -6 L -2 -1 L 2 5 L 4 7 L 6 8 L 9 8 M -5 8 L -9 3 M 0 -6 L -4 -11 M -7 -7 L -1 -1 L 3 5 L 4 6 L 6 7 L 9 7 L 10 6","-4 5 M 1 -12 L 0 -11 L 0 -5 M 1 -11 L 0 -5 M 1 -12 L 2 -11 L 0 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 M -1 -10 L -2 -7 L -3 -3 L -3 3 L -2 7 L -1 10 M 1 -14 L 0 -12 L -1 -9 L -2 -3 L -2 3 L -1 9 L 0 12 L 1 14","-7 7 M -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16 M 1 -10 L 2 -7 L 3 -3 L 3 3 L 2 7 L 1 10 M -1 -14 L 0 -12 L 1 -9 L 2 -3 L 2 3 L 1 9 L 0 12 L -1 14","-8 8 M 0 -12 L -1 -11 L 1 -1 L 0 0 M 0 -12 L 0 0 M 0 -12 L 1 -11 L -1 -1 L 0 0 M -5 -9 L -4 -9 L 4 -3 L 5 -3 M -5 -9 L 5 -3 M -5 -9 L -5 -8 L 5 -4 L 5 -3 M 5 -9 L 4 -9 L -4 -3 L -5 -3 M 5 -9 L -5 -3 M 5 -9 L 5 -8 L -5 -4 L -5 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-6 6 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-13 13 M -9 0 L 9 0","-6 6 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -3 -10 L -2 -9 L -1 -7 L -1 6 L -3 7 M -1 -9 L -2 -10 L -1 -11 L 0 -9 L 0 7 L 2 8 M -3 -10 L 0 -12 L 1 -10 L 1 6 L 3 7 L 4 7 M -3 7 L -2 7 L 0 8 L 1 9 L 2 8 L 4 7","-10 10 M -6 -10 L -4 -10 L -2 -11 L -1 -12 L 1 -11 L 4 -10 L 6 -10 M -2 -10 L 0 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -10 L 1 -11 M 4 -10 L 4 -2 M 5 -9 L 5 -3 M 6 -10 L 6 -2 L -1 -2 L -4 -1 L -6 1 L -7 4 L -7 9 M -7 9 L -3 7 L 1 6 L 4 6 L 8 7 M -4 8 L -1 7 L 4 7 L 7 8 M -7 9 L -2 8 L 3 8 L 6 9 L 8 7","-10 10 M -6 -10 L -5 -10 L -3 -11 L -2 -12 L 0 -11 L 4 -10 L 6 -10 M -3 -10 L -1 -11 M -6 -10 L -4 -9 L -2 -9 L 0 -11 M 4 -10 L 4 -3 M 5 -9 L 5 -4 M 6 -10 L 6 -3 L 4 -3 L 1 -2 L -1 -1 M -1 -2 L 1 -1 L 4 0 L 6 0 L 6 7 M 5 1 L 5 6 M 4 0 L 4 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M 3 -12 L -7 -2 L -7 3 L 2 3 M 4 3 L 8 3 L 9 4 L 9 2 L 8 3 M -6 -2 L -6 2 M -5 -4 L -5 3 M 2 -11 L 2 6 L 0 7 M 3 -8 L 4 -10 L 3 -11 L 3 7 L 5 8 M 3 -12 L 5 -10 L 4 -8 L 4 6 L 6 7 L 7 7 M 0 7 L 1 7 L 3 8 L 4 9 L 5 8 L 7 7","-10 10 M -6 -12 L -6 -3 M -6 -12 L 6 -12 M -5 -11 L 4 -11 M -6 -10 L 3 -10 L 5 -11 L 6 -12 M 4 -6 L 3 -5 L 1 -4 L -3 -3 L -6 -3 M 1 -4 L 2 -4 L 4 -3 L 4 7 M 3 -5 L 5 -4 L 5 6 M 4 -6 L 5 -5 L 7 -4 L 8 -4 L 6 -3 L 6 7 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 6 L -8 7 M -5 -9 L -5 6 L -2 8 M -4 -10 L -4 6 L -2 7 L -1 8 M -6 -10 L -4 -10 L 0 -11 L 2 -12 L 3 -11 L 5 -10 L 6 -10 M 1 -11 L 3 -10 M 0 -11 L 2 -9 L 4 -9 L 6 -10 M -4 -2 L -3 -2 L 1 -3 L 3 -4 L 4 -5 M 1 -3 L 2 -3 L 4 -2 L 4 7 M 3 -4 L 5 -2 L 5 6 M 4 -5 L 5 -4 L 7 -3 L 8 -3 L 6 -2 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -7 -10 L -5 -12 L -2 -11 L 3 -11 L 8 -12 M -6 -11 L -3 -10 L 2 -10 L 5 -11 M -7 -10 L -3 -9 L 0 -9 L 4 -10 L 8 -12 M 8 -12 L 7 -10 L 5 -7 L 1 -3 L -1 0 L -2 3 L -2 6 L -1 9 M 0 -1 L -1 2 L -1 5 L 0 8 M 3 -5 L 1 -2 L 0 1 L 0 4 L 1 7 L -1 9","-10 10 M -6 -9 L -6 -3 M -5 -8 L -5 -4 M -4 -9 L -4 -3 M -6 -9 L -4 -9 L 1 -10 L 3 -11 L 4 -12 M 1 -10 L 2 -10 L 4 -9 L 4 -3 M 3 -11 L 5 -10 L 5 -4 M 4 -12 L 5 -11 L 7 -10 L 8 -10 L 6 -9 L 6 -3 M -6 -3 L -4 -3 L 4 0 L 6 0 M 6 -3 L 4 -3 L -4 0 L -6 0 M -6 0 L -6 6 L -8 7 M -5 1 L -5 6 L -2 8 M -4 0 L -4 6 L -2 7 L -1 8 M 4 0 L 4 7 M 5 1 L 5 6 M 6 0 L 6 7 M -8 7 L -6 7 L -4 8 L -3 9 L -1 8 L 4 7 L 6 7","-10 10 M -6 -10 L -6 -1 L -8 0 M -5 -9 L -5 0 L -3 1 M -4 -10 L -4 -1 L -2 0 L -1 0 M -6 -10 L -4 -10 L 1 -11 L 3 -12 M 1 -11 L 2 -10 L 4 -9 L 4 7 M 2 -11 L 5 -9 L 5 6 M 3 -12 L 4 -11 L 6 -10 L 8 -10 L 6 -9 L 6 7 M -8 0 L -7 0 L -5 1 L -4 2 L -3 1 L -1 0 L 3 -1 L 4 -1 M -7 7 L -5 6 L -3 6 L -1 7 L 0 8 M -3 7 L -1 8 M -7 7 L -5 7 L -3 8 L -2 9 L 0 8 L 4 7 L 6 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-6 6 M 0 -5 L -2 -3 L 0 -2 L 2 -3 L 0 -5 M 0 -4 L -1 -3 L 1 -3 L 0 -4 M 0 12 L 0 10 L -2 8 L 0 6 L 1 8 L 1 10 L 0 12 L -2 13 M 0 7 L -1 8 L 0 9 L 0 7","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -8 L -5 -10 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -2 L 1 -1 M -5 -8 L -4 -10 M 4 -10 L 5 -9 L 5 -5 L 4 -4 M -6 -8 L -4 -7 L -4 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 4 -9 L 4 -5 L 3 -3 L 1 -1 M 0 -1 L 0 2 L 1 -1 L -1 -1 L 0 2 M 0 6 L -2 8 L 0 9 L 2 8 L 0 6 M 0 7 L -1 8 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-13 13 M -4 -10 L -6 -9 L -8 -7 L -9 -5 L -10 -2 L -10 1 L -9 3 L -7 4 M -8 -6 L -9 -3 L -9 1 L -8 3 M -4 -10 L -6 -8 L -7 -6 L -8 -3 L -8 0 L -7 4 L -7 6 L -8 8 L -10 9 M 4 -10 L 6 -10 L 6 7 L 4 7 M 7 -10 L 7 7 M 8 -11 L 8 8 M -10 -12 L -7 -11 L -1 -10 L 4 -10 L 8 -11 L 10 -12 M -8 -2 L 6 -2 M -10 9 L -7 8 L -1 7 L 4 7 L 8 8 L 10 9","-13 13 M -6 -11 L -6 8 M -5 -11 L -5 8 M -2 -12 L -4 -11 L -4 8 L -2 9 M -10 -8 L -8 -10 L -6 -11 L -2 -12 L 3 -12 L 6 -11 L 8 -9 L 8 -7 L 7 -5 M 6 -10 L 7 -9 L 7 -7 L 6 -5 M 3 -12 L 5 -11 L 6 -9 L 6 -7 L 5 -6 M -1 3 L -3 2 L -4 0 L -4 -2 L -3 -4 L -2 -5 L 1 -6 L 4 -6 L 7 -5 L 9 -3 L 10 -1 L 10 2 L 9 5 L 7 7 L 5 8 L 2 9 L -2 9 L -6 8 L -8 7 L -10 5 M 8 -3 L 9 -1 L 9 3 L 8 5 M 4 -6 L 7 -4 L 8 -1 L 8 3 L 7 6 L 5 8","-13 13 M 10 -12 L 9 -10 L 8 -8 L 6 -10 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 7 L 10 9 M 9 -10 L 8 -5 L 8 2 L 9 7 M 8 -7 L 7 -8 M 8 -4 L 7 -7 L 6 -9 L 4 -11 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 7 5 L 8 4 M 4 8 L 6 6 L 7 4 L 8 1","-13 13 M -7 -11 L -7 8 M -6 -11 L -6 8 M -4 -12 L -5 -11 L -5 8 L -4 9 M -10 -7 L -9 -9 L -7 -11 L -4 -12 L 1 -12 L 4 -11 L 6 -10 L 8 -8 L 9 -6 L 10 -3 L 10 0 L 9 3 L 8 5 L 6 7 L 4 8 L 1 9 L -4 9 L -7 8 L -9 6 L -10 4 M 8 -7 L 9 -4 L 9 1 L 8 4 M 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8","-13 13 M 10 -12 L 9 -10 L 8 -8 L 6 -10 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 7 L 10 9 M 9 -10 L 8 -5 L 8 2 L 9 7 M 8 -7 L 7 -8 M 8 -5 L 6 -9 L 4 -11 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 7 5 L 8 4 M 4 8 L 6 6 L 7 4 L 8 1 M -8 -2 L -7 -3 L -4 -3 L 3 -1 L 6 -1 L 8 -2 M -2 -2 L 0 -1 L 3 0 L 5 0 L 7 -1 M -5 -3 L 0 0 L 3 1 L 5 1 L 7 0 L 8 -2 M 8 -5 L 7 -6 L 6 -6 L 5 -5 L 6 -4 L 7 -5","-13 13 M -8 -10 L -8 8 M -5 -11 L -7 -10 L -7 7 M -3 -12 L -5 -11 L -6 -9 L -6 7 L -4 7 M -10 -8 L -8 -10 L -6 -11 L -3 -12 L 1 -12 L 4 -11 L 6 -10 L 7 -9 L 10 -12 M 10 -12 L 9 -10 L 8 -6 L 8 -3 L 9 1 L 10 3 M 8 -9 L 7 -7 M 4 -11 L 6 -9 L 7 -6 L 8 -3 M -6 -2 L -5 -3 L -3 -3 L 2 -2 L 5 -2 L 7 -3 M -1 -2 L 2 -1 L 4 -1 L 6 -2 M -4 -3 L 2 0 L 4 0 L 6 -1 L 7 -3 L 7 -6 L 6 -7 L 5 -7 L 4 -6 L 5 -5 L 6 -6 M -10 9 L -8 8 L -4 7 L 1 7 L 7 8 L 10 9","-13 13 M 10 -12 L 9 -10 L 8 -8 L 6 -10 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 4 8 L 6 7 L 7 6 L 8 4 L 9 7 L 10 9 M 9 -10 L 8 -5 L 8 2 L 9 7 M 8 -7 L 7 -8 M 8 -4 L 7 -7 L 6 -9 L 4 -11 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 6 6 L 7 4 L 7 0 M 4 8 L 5 7 L 6 4 L 6 -1 M -7 1 L -6 0 L -5 1 L -6 2 L -7 2 L -8 1 M -8 -2 L -7 -4 L -5 -5 L -3 -5 L 0 -4 L 3 -2 L 5 -1 M -7 -3 L -5 -4 L -3 -4 L 0 -3 L 2 -2 M -8 -2 L -6 -3 L -3 -3 L 3 -1 L 7 -1 L 8 -2","-13 13 M -8 -11 L -8 8 L -10 9 M -7 -10 L -7 8 M -4 -10 L -6 -10 L -6 8 M -10 -12 L -8 -11 L -4 -10 L 1 -10 L 7 -11 L 10 -12 M -6 -2 L -5 -4 L -3 -6 L 0 -7 L 4 -7 L 7 -6 L 9 -4 L 10 -1 L 10 2 L 9 3 L 7 4 M 8 -4 L 9 -2 L 9 1 L 8 3 M 4 -7 L 6 -6 L 7 -5 L 8 -3 L 8 1 L 7 4 L 7 6 L 8 8 L 10 9 M -10 9 L -6 8 L -2 8 L 3 9","-13 13 M -1 -9 L -1 7 M 0 -8 L 0 6 M 1 -9 L 1 7 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12 M -10 9 L -7 8 L -3 7 L 3 7 L 7 8 L 10 9","-13 13 M 2 -9 L 4 -9 L 4 6 L 3 8 L 1 9 M 5 -9 L 5 6 L 4 7 M 6 -10 L 6 7 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12 M -9 -3 L -10 -1 L -10 3 L -9 6 L -7 8 L -4 9 L 1 9 L 4 8 L 6 7 L 8 5 L 10 2 M -9 3 L -8 6 L -7 7 M -10 1 L -8 3 L -7 6 L -6 8 L -4 9","-13 13 M -8 -11 L -8 8 L -10 9 M -7 -10 L -7 8 M -4 -10 L -6 -10 L -6 8 M -10 -12 L -8 -11 L -4 -10 L 1 -10 L 7 -11 L 10 -12 M -6 -2 L -5 -4 L -3 -6 L 0 -7 L 3 -7 L 6 -6 L 7 -5 L 7 -3 L 6 -2 L 1 0 L -1 1 L -2 2 L -2 3 L -1 4 L 0 3 L -1 2 M 5 -6 L 6 -5 L 6 -3 L 5 -2 M 3 -7 L 5 -5 L 5 -3 L 4 -2 L 1 0 M 1 0 L 4 0 L 7 1 L 8 3 L 8 5 L 7 6 M 5 1 L 7 3 L 7 5 M 1 0 L 4 1 L 6 3 L 7 6 L 8 8 L 9 9 L 10 9 M -10 9 L -6 8 L -2 8 L 3 9","-13 13 M -8 -11 L -8 8 M -7 -10 L -7 7 M -4 -10 L -6 -10 L -6 7 L -4 7 M 10 -7 L 8 -4 L 7 -2 L 6 1 L 6 3 L 7 5 L 9 6 M 8 -3 L 7 0 L 7 3 L 8 5 M 10 -7 L 9 -5 L 8 -1 L 8 2 L 9 6 L 10 9 M -10 -12 L -8 -11 L -4 -10 L 1 -10 L 7 -11 L 10 -12 M -10 9 L -8 8 L -4 7 L 1 7 L 7 8 L 10 9","-13 13 M -1 -9 L -1 7 M 0 -8 L 0 6 M 1 -9 L 1 7 M -4 7 L -6 5 L -8 4 L -9 3 L -10 0 L -10 -5 L -9 -8 L -7 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 7 -10 L 9 -8 L 10 -5 L 10 0 L 9 3 L 8 4 L 6 5 L 4 7 M -8 3 L -9 0 L -9 -5 L -8 -8 M -6 5 L -7 3 L -8 0 L -8 -6 L -7 -9 L -5 -11 M 8 -8 L 9 -5 L 9 0 L 8 3 M 5 -11 L 7 -9 L 8 -6 L 8 0 L 7 3 L 6 5 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12 M -10 9 L -7 8 L -3 7 L 3 7 L 7 8 L 10 9","-13 13 M -8 -10 L -8 8 L -10 9 M -6 -10 L -7 -9 L -7 8 M -3 -12 L -5 -11 L -6 -9 L -6 8 M -10 -8 L -8 -10 L -6 -11 L -3 -12 L 1 -12 L 4 -11 L 6 -10 L 8 -8 L 9 -6 L 10 -3 L 10 1 L 9 3 L 7 4 M 8 -7 L 9 -4 L 9 0 L 8 3 M 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 0 L 7 4 L 7 6 L 8 8 L 9 9 L 10 9 M -10 9 L -6 8 L -2 8 L 3 9","-13 13 M -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -3 L 9 -6 L 8 -8 L 6 -10 L 4 -11 L 1 -12 L -1 -12 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 8 4 L 9 1 L 9 -4 L 8 -7 M 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11","-13 13 M -8 -9 L -8 8 M -5 -10 L -7 -8 L -7 7 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -6 7 L -4 7 M -10 -7 L -8 -9 L -4 -11 L -1 -12 L 2 -12 L 5 -11 L 7 -10 L 9 -8 L 10 -5 L 10 -3 L 9 0 L 7 2 L 4 3 L 0 3 L -3 2 L -5 0 L -6 -3 M 8 -8 L 9 -6 L 9 -2 L 8 0 M 5 -11 L 7 -9 L 8 -6 L 8 -2 L 7 1 L 4 3 M -10 9 L -8 8 L -4 7 L 1 7 L 7 8 L 10 9","-13 13 M -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -3 L 9 -6 L 8 -8 L 6 -10 L 4 -11 L 1 -12 L -1 -12 M -8 -7 L -9 -4 L -9 1 L -8 4 M -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 M 8 4 L 9 1 L 9 -4 L 8 -7 M 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 M -8 1 L -7 3 L -4 4 L 2 5 L 9 5 L 10 6 L 10 8 L 9 9 L 9 8 L 10 7 M -2 5 L 0 5 M -7 3 L -4 5 L -1 6 L 1 6 L 2 5","-13 13 M -8 -9 L -8 8 L -10 9 M -7 -9 L -7 8 M -6 -10 L -6 8 M -10 -7 L -8 -9 L -6 -10 L -4 -11 L -1 -12 L 3 -12 L 7 -11 L 9 -9 L 10 -7 L 10 -4 L 9 -2 L 8 -1 M 7 -10 L 8 -9 L 9 -7 L 9 -4 L 8 -2 M 3 -12 L 5 -11 L 7 -9 L 8 -7 L 8 -3 L 7 -1 M 6 0 L 3 1 L 0 1 L -2 0 L -2 -2 L 0 -3 L 3 -3 L 6 -2 L 8 0 L 10 3 L 10 5 L 9 6 L 8 6 M 6 -1 L 7 0 L 9 4 L 9 5 L 8 2 M 2 -3 L 4 -2 L 6 0 L 7 2 L 8 6 L 9 8 L 10 9 M -10 9 L -6 8 L -2 8 L 3 9","-13 13 M 2 -12 L 8 -11 L 10 -12 L 9 -10 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -8 -8 L -9 -5 L -9 -3 L -8 0 L -6 2 L -3 3 L 0 3 L 2 2 L 3 1 L 4 -1 L 4 -2 M 9 -11 L 8 -10 L 9 -8 M -8 -2 L -7 0 L -6 1 L -3 2 L 0 2 L 2 1 M -7 -9 L -8 -7 L -8 -4 L -7 -2 L -5 0 L -2 1 L 0 1 L 2 0 L 4 -2 L 5 -3 L 6 -3 M -6 -1 L -5 -1 L -4 -2 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 7 -2 L 8 0 L 8 3 L 7 6 L 5 8 M -2 -5 L 0 -6 L 3 -6 L 6 -5 L 8 -3 L 9 0 L 9 3 L 8 5 M -9 5 L -8 7 L -9 8 M -4 -2 L -4 -3 L -3 -5 L -2 -6 L 0 -7 L 3 -7 L 6 -6 L 9 -3 L 10 0 L 10 2 L 9 5 L 7 7 L 5 8 L 2 9 L -2 9 L -5 8 L -7 7 L -9 5 L -9 7 L -10 9 L -8 8 L -2 9","-13 13 M -1 -10 L -5 -10 L -7 -9 L -8 -8 L -9 -6 L -10 -3 L -10 1 L -9 4 L -8 6 L -7 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -4 L 9 -7 L 7 -9 L 5 -10 M 3 -10 L 2 -9 L 2 -7 L 3 -6 L 4 -7 L 3 -8 M -9 1 L -8 4 L -6 6 L -4 7 L -1 8 L 2 8 L 5 7 M -8 -8 L -9 -4 L -9 -1 L -8 2 L -6 5 L -4 6 L -1 7 L 2 7 L 5 6 L 7 5 L 9 2 L 10 0 M -10 -12 L -7 -9 M -7 -10 L -6 -11 M -9 -11 L -8 -11 L -7 -12 L -5 -11 L -1 -10 L 5 -10 L 8 -11 L 10 -12","-13 13 M -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 3 9 L 6 8 L 8 7 M -7 -8 L -8 -6 L -9 -3 L -9 1 L -8 4 M -7 -9 L -6 -8 L -6 -7 L -7 -5 L -8 -2 L -8 1 L -7 4 L -6 6 L -4 8 M 4 -10 L 6 -10 L 6 6 L 5 8 L 3 9 M 7 -10 L 7 6 L 6 7 M 8 -11 L 8 7 L 10 9 M -10 -12 L -7 -11 L -1 -10 L 4 -10 L 8 -11 L 10 -12","-13 13 M -10 -12 L 0 9 M -9 -11 L -8 -10 L -1 5 L 0 7 M -8 -11 L -7 -10 L 0 5 L 1 6 M 10 -12 L 0 9 M 5 -4 L 3 1 M 7 -6 L 3 -1 L 2 2 L 2 4 M -10 -12 L -8 -11 L -3 -10 L 3 -10 L 8 -11 L 10 -12","-13 13 M -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 1 9 L 4 8 L 6 7 L 8 5 L 9 3 L 10 0 L 10 -3 L 9 -6 L 8 -8 L 6 -10 M -8 -6 L -9 -3 L -9 0 L -8 3 L -7 5 M -8 -8 L -7 -7 L -7 -6 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 M 7 5 L 8 3 L 9 0 L 9 -3 L 8 -6 M 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -6 L 7 -7 L 8 -8 M -1 -9 L -1 9 M 0 -8 L 0 8 M 1 -9 L 1 9 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12","-13 13 M -10 -12 L 6 7 L 7 8 M -9 -11 L -7 -10 L 8 8 M -6 -10 L 10 9 M 10 -12 L 1 -2 M -1 0 L -8 8 M -2 1 L -5 3 L -6 5 M -1 0 L -5 2 L -6 3 L -7 5 L -7 7 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12 M -10 9 L -8 8 L -4 7 L 1 7 L 7 8 L 10 9","-13 13 M 6 -10 L 6 8 M 7 -10 L 7 7 M 8 -11 L 8 7 M -7 -10 L -9 -8 L -10 -5 L -10 -2 L -9 1 L -7 3 L -5 4 L -2 5 L 1 5 L 4 4 L 6 3 M -6 3 L -3 4 L 3 4 M -10 -2 L -9 0 L -7 2 L -4 3 L 2 3 L 4 4 M -10 -12 L -6 -10 L -2 -9 L 2 -9 L 6 -10 L 10 -12 M -10 5 L -8 7 L -6 8 L -2 9 L 2 9 L 6 8 L 10 6","-13 13 M -10 -12 L -9 -11 L -7 -10 L -4 -10 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 M 6 -11 L 7 -9 L 7 -7 L 6 -5 M 4 -12 L 5 -11 L 6 -9 L 6 -6 M 6 -4 L 2 -3 L 0 -3 L -2 -4 L -2 -6 L 0 -7 L 2 -7 L 6 -6 M 2 -7 L 4 -6 L 5 -5 L 4 -4 L 2 -3 M 7 -5 L 9 -3 L 10 0 L 10 2 L 9 5 L 7 7 L 5 8 L 2 9 L -2 9 L -5 8 L -7 7 L -9 5 L -10 2 L -10 0 L -9 -3 L -8 -4 L -6 -5 L -4 -5 L -2 -4 L -2 -2 L -3 -1 L -4 -2 L -3 -3 M 6 -5 L 8 -3 L 9 -1 L 9 3 L 8 5 M 6 -4 L 7 -3 L 8 -1 L 8 3 L 7 6 L 5 8","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-13 13 M -13 16 L 13 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-8 9 M -2 -1 L -5 2 L -5 6 L -2 9 L 2 7 M -4 2 L -4 6 L -2 8 M -3 0 L -3 5 L 0 8 M 0 1 L -5 -4 L -4 -5 L -3 -4 L -4 -3 M -3 -4 L 1 -4 L 3 -5 L 5 -3 L 5 6 L 6 7 M 3 -4 L 4 -3 L 4 6 L 3 7 L 4 8 L 5 7 L 4 6 M 1 -4 L 3 -2 L 3 6 L 2 7 L 4 9 L 6 7","-9 8 M -4 -10 L -6 -12 L -5 -8 L -5 6 L -2 9 L 3 7 L 5 6 M -4 -10 L -4 6 L -2 8 M -4 -10 L -2 -12 L -3 -8 L -3 5 L 0 8 M -3 -3 L 2 -5 L 5 -2 L 5 6 M 2 -4 L 4 -2 L 4 6 M 0 -4 L 3 -1 L 3 7","-7 5 M -4 -2 L -4 7 L -2 9 L 0 7 M -3 -2 L -3 7 L -2 8 M -2 -3 L -2 6 L -1 7 L 0 7 M -4 -2 L 2 -5 L 4 -3 L 2 -2 L 0 -4 M 1 -4 L 3 -3","-8 8 M 0 -5 L -5 -2 L -5 6 L -2 9 L 0 8 L 3 7 L 5 7 M -4 -2 L -4 6 L -2 8 M -3 -3 L -3 5 L 0 8 M -2 -9 L -2 -12 L -1 -9 L 5 -2 L 5 7 M -2 -9 L 4 -2 L 4 6 M -2 -9 L -5 -9 L -2 -8 L 3 -2 L 3 7","-7 6 M -4 -2 L -4 7 L -2 9 L 0 7 M -3 -2 L -3 7 L -2 8 M -2 -3 L -2 6 L -1 7 L 0 7 M -4 -2 L 2 -5 L 5 -1 L -2 3 M 1 -4 L 4 -1 M 0 -4 L 3 0","-7 5 M -3 -9 L -3 6 L -4 7 L -2 9 M -2 -9 L -2 6 L -3 7 L -2 8 L -1 7 L -2 6 M -1 -10 L -1 6 L 0 7 L -2 9 M -3 -9 L 3 -12 L 5 -10 L 3 -9 L 1 -11 M 2 -11 L 4 -10 M -6 -5 L -3 -5 M -1 -5 L 3 -5","-8 9 M -5 -2 L -5 6 L -2 9 L 3 7 M -4 -2 L -4 6 L -2 8 M -3 -3 L -3 5 L 0 8 M -5 -2 L -3 -3 L 2 -5 L 5 -2 L 5 11 L 4 13 L 3 14 L 1 15 L -1 15 L -3 14 L -5 15 L -3 16 L -1 15 M 2 -4 L 4 -2 L 4 11 L 3 13 M -2 15 L -4 15 M 0 -4 L 3 -1 L 3 12 L 2 14 L 1 15","-9 9 M -4 -10 L -6 -12 L -5 -8 L -5 6 L -6 7 L -4 9 M -4 -10 L -4 6 L -5 7 L -4 8 L -3 7 L -4 6 M -4 -10 L -2 -12 L -3 -8 L -3 6 L -2 7 L -4 9 M -3 -3 L 0 -4 L 2 -5 L 5 -2 L 5 7 L 2 11 L 2 14 L 3 16 L 4 16 L 2 14 M 2 -4 L 4 -2 L 4 7 L 3 9 M 0 -4 L 3 -1 L 3 8 L 2 11","-5 5 M 0 -12 L -2 -10 L 0 -8 L 2 -10 L 0 -12 M 0 -11 L -1 -10 L 0 -9 L 1 -10 L 0 -11 M 0 -5 L -2 -3 L -1 -2 L -1 6 L -2 7 L 0 9 M 0 -2 L 1 -3 L 0 -4 L -1 -3 L 0 -2 L 0 6 L -1 7 L 0 8 L 1 7 L 0 6 M 0 -5 L 2 -3 L 1 -2 L 1 6 L 2 7 L 0 9","-5 5 M 0 -12 L -2 -10 L 0 -8 L 2 -10 L 0 -12 M 0 -11 L -1 -10 L 0 -9 L 1 -10 L 0 -11 M 0 -5 L -2 -3 L -1 -2 L -1 7 L 2 11 M 0 -2 L 1 -3 L 0 -4 L -1 -3 L 0 -2 L 0 7 L 1 9 M 0 -5 L 2 -3 L 1 -2 L 1 8 L 2 11 L 2 14 L 0 16 L -2 15 L -2 16 L 0 16","-9 8 M -4 -10 L -6 -12 L -5 -8 L -5 6 L -6 7 L -4 9 M -4 -10 L -4 6 L -5 7 L -4 8 L -3 7 L -4 6 M -4 -10 L -2 -12 L -3 -8 L -3 6 L -2 7 L -4 9 M -3 -2 L 0 -4 L 2 -5 L 4 -2 L 1 0 L -3 3 M 1 -4 L 3 -2 M 0 -4 L 2 -1 M 0 1 L 1 2 L 2 7 L 4 9 L 6 7 M 1 1 L 2 3 L 3 7 L 4 8 M 1 0 L 2 1 L 4 6 L 5 7 L 6 7","-5 5 M 0 -10 L -2 -12 L -1 -8 L -1 6 L -2 7 L 0 9 M 0 -10 L 0 6 L -1 7 L 0 8 L 1 7 L 0 6 M 0 -10 L 2 -12 L 1 -8 L 1 6 L 2 7 L 0 9","-13 13 M -11 -3 L -10 -3 L -9 -2 L -9 6 L -10 7 L -8 9 M -9 -4 L -8 -3 L -8 6 L -9 7 L -8 8 L -7 7 L -8 6 M -11 -3 L -9 -5 L -7 -3 L -7 6 L -6 7 L -8 9 M -7 -3 L -4 -4 L -2 -5 L 1 -3 L 1 6 L 2 7 L 0 9 M -2 -4 L 0 -3 L 0 6 L -1 7 L 0 8 L 1 7 L 0 6 M -4 -4 L -1 -2 L -1 6 L -2 7 L 0 9 M 1 -3 L 4 -4 L 6 -5 L 9 -3 L 9 6 L 10 7 L 8 9 M 6 -4 L 8 -3 L 8 6 L 7 7 L 8 8 L 9 7 L 8 6 M 4 -4 L 7 -2 L 7 6 L 6 7 L 8 9","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 6 L -6 7 L -4 9 M -5 -4 L -4 -3 L -4 6 L -5 7 L -4 8 L -3 7 L -4 6 M -7 -3 L -5 -5 L -3 -3 L -3 6 L -2 7 L -4 9 M -3 -3 L 0 -4 L 2 -5 L 5 -3 L 5 6 L 6 7 L 4 9 M 2 -4 L 4 -3 L 4 6 L 3 7 L 4 8 L 5 7 L 4 6 M 0 -4 L 3 -2 L 3 6 L 2 7 L 4 9","-8 8 M -5 -2 L -5 6 L -2 9 L 3 7 L 5 6 M -4 -2 L -4 6 L -2 8 M -3 -3 L -3 5 L 0 8 M -5 -2 L -3 -3 L 2 -5 L 5 -2 L 5 6 M 2 -4 L 4 -2 L 4 6 M 0 -4 L 3 -1 L 3 7","-9 8 M -6 -5 L -5 -3 L -5 6 L -7 7 L -5 7 L -5 13 L -6 16 L -4 14 M -4 -3 L -4 14 M -6 -5 L -4 -4 L -3 -3 L -3 6 L -1 7 L 0 8 M -4 7 L -3 7 L -1 8 M -3 8 L -2 9 L 3 7 L 5 6 M -3 8 L -3 13 L -2 16 L -4 14 M -3 -3 L 0 -4 L 2 -5 L 5 -2 L 5 6 M 2 -4 L 4 -2 L 4 6 M 0 -4 L 3 -1 L 3 7","-8 9 M -5 -2 L -5 6 L -2 9 L 3 7 M -4 -2 L -4 6 L -2 8 M -3 -3 L -3 5 L 0 8 M -5 -2 L -3 -3 L 2 -5 L 5 -2 L 5 13 L 6 16 L 4 14 M 2 -4 L 4 -2 L 4 14 M 0 -4 L 3 -1 L 3 13 L 2 16 L 4 14","-7 6 M -5 -3 L -4 -3 L -3 -2 L -3 6 L -4 7 L -2 9 M -3 -4 L -2 -3 L -2 6 L -3 7 L -2 8 L -1 7 L -2 6 M -5 -3 L -3 -5 L -1 -3 L -1 6 L 0 7 L -2 9 M -1 -3 L 3 -5 L 5 -3 L 3 -2 L 1 -4 M 2 -4 L 4 -3","-8 8 M -5 -2 L -5 1 L -3 3 L 3 0 L 5 2 L 5 6 M -4 -2 L -4 1 L -3 2 M -3 -3 L -3 1 L -2 2 M 3 1 L 4 2 L 4 6 M 2 1 L 3 2 L 3 7 M -5 -2 L 1 -5 L 4 -4 L 2 -3 L -1 -4 M 0 -4 L 3 -4 M 5 6 L -1 9 L -5 7 L -3 6 L 1 8 M -3 7 L -1 8","-5 5 M 0 -10 L -2 -12 L -1 -8 L -1 6 L -2 7 L 0 9 M 0 -10 L 0 6 L -1 7 L 0 8 L 1 7 L 0 6 M 0 -10 L 2 -12 L 1 -8 L 1 6 L 2 7 L 0 9 M -4 -5 L -1 -5 M 1 -5 L 4 -5","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 7 L -2 9 L 3 7 M -5 -4 L -4 -3 L -4 7 L -2 8 M -7 -3 L -5 -5 L -3 -3 L -3 6 L 0 8 M 4 -5 L 6 -3 L 5 -2 L 5 6 L 6 7 L 7 7 M 4 -2 L 5 -3 L 4 -4 L 3 -3 L 4 -2 L 4 7 L 5 8 M 4 -5 L 2 -3 L 3 -2 L 3 7 L 5 9 L 7 7","-9 9 M -6 -5 L -5 -3 L -5 6 L -1 9 L 1 7 L 5 5 M -5 -4 L -4 -3 L -4 6 L -1 8 M -6 -5 L -4 -4 L -3 -3 L -3 5 L 0 7 L 1 7 M 4 -5 L 6 -3 L 5 -2 L 5 5 M 4 -2 L 5 -3 L 4 -4 L 3 -3 L 4 -2 L 4 5 M 4 -5 L 2 -3 L 3 -2 L 3 6","-13 13 M -10 -5 L -9 -3 L -9 6 L -5 9 L -3 7 L -1 6 M -9 -4 L -8 -3 L -8 6 L -5 8 M -10 -5 L -8 -4 L -7 -3 L -7 5 L -4 7 L -3 7 M 0 -5 L -2 -3 L -1 -2 L -1 6 L 3 9 L 5 7 L 9 5 M 0 -2 L 1 -3 L 0 -4 L -1 -3 L 0 -2 L 0 6 L 3 8 M 0 -5 L 2 -3 L 1 -2 L 1 5 L 4 7 L 5 7 M 8 -5 L 10 -3 L 9 -2 L 9 5 M 8 -2 L 9 -3 L 8 -4 L 7 -3 L 8 -2 L 8 5 M 8 -5 L 6 -3 L 7 -2 L 7 6","-9 9 M -6 -3 L -4 -2 L 3 8 L 4 9 L 6 7 M -5 -4 L -3 -3 L 3 7 L 5 8 M -6 -3 L -4 -5 L -3 -4 L 4 6 L 6 7 M 6 -5 L 4 -5 L 4 -3 L 6 -3 L 6 -5 L 4 -3 L 1 1 M -1 3 L -4 7 L -6 9 L -4 9 L -4 7 L -6 7 L -6 9 M -4 2 L -1 2 M 1 2 L 4 2","-9 9 M -7 -3 L -6 -3 L -5 -2 L -5 7 L -2 9 L 3 7 M -5 -4 L -4 -3 L -4 7 L -2 8 M -7 -3 L -5 -5 L -3 -3 L -3 6 L 0 8 M 4 -5 L 6 -3 L 5 -2 L 5 11 L 4 13 L 3 14 L 1 15 L -1 15 L -3 14 L -5 15 L -3 16 L -1 15 M 4 -2 L 5 -3 L 4 -4 L 3 -3 L 4 -2 L 4 12 L 3 13 M -2 15 L -4 15 M 4 -5 L 2 -3 L 3 -2 L 3 12 L 2 14 L 1 15","-6 9 M 0 -4 L -3 -2 L -3 -3 L 0 -4 L 2 -5 L 5 -3 L 5 1 L 0 3 M 2 -4 L 4 -3 L 4 1 M 0 -4 L 3 -2 L 3 1 L 2 2 M 0 3 L 5 5 L 5 11 L 4 13 L 3 14 L 1 15 L -1 15 L -3 14 L -5 15 L -3 16 L -1 15 M 4 5 L 4 12 L 3 13 M -2 15 L -4 15 M 2 4 L 3 5 L 3 12 L 2 14 L 1 15","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -greek = ["-8 8","-5 5 M 0 -12 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -4 -12 L -4 -5 M 4 -12 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -6 9 L -8 8 L -9 7 L -10 5 L -10 3 L -9 1 L -8 0 L -1 -4 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 7 9 L 9 9 L 10 8 L 10 7","-5 5 M 0 -10 L -1 -11 L 0 -12 L 1 -11 L 1 -9 L 0 -7 L -1 -6","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9 M -5 2 L 5 2","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 M -7 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -7 9","-10 10 M -7 -12 L 7 9 M -7 9 L 7 -12","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9 M -8 9 L 8 9","-10 9 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2 M -6 9 L 7 9","-10 10 M 0 -12 L 0 9 M -2 -7 L -5 -6 L -6 -5 L -7 -3 L -7 0 L -6 2 L -5 3 L -2 4 L 2 4 L 5 3 L 6 2 L 7 0 L 7 -3 L 6 -5 L 5 -6 L 2 -7 L -2 -7","-10 7 M -6 -12 L -6 9 M -6 -12 L 6 -12","-11 11 M -7 -12 L -7 9 M 7 -12 L 7 9 M -7 -2 L 7 -2","-4 4 M 0 -12 L 0 9","-2 3 M 0 -1 L 0 0 L 1 0 L 1 -1 L 0 -1","-11 10 M -7 -12 L -7 9 M 7 -12 L -7 2 M -2 -3 L 7 9","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9","-12 12 M -8 -12 L -8 9 M -8 -12 L 0 9 M 8 -12 L 0 9 M 8 -12 L 8 9","-11 11 M -7 -12 L -7 9 M -7 -12 L 7 9 M 7 -12 L 7 9","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12","-11 11 M -7 -12 L -7 9 M 7 -12 L 7 9 M -7 -12 L 7 -12","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M -3 -2 L 3 -2","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 L -7 -1","-9 9 M -7 -12 L 0 -2 L -7 9 M -7 -12 L 7 -12 M -7 9 L 7 9","-8 8 M 0 -12 L 0 9 M -7 -12 L 7 -12","-9 9 M -7 -7 L -7 -9 L -6 -11 L -5 -12 L -3 -12 L -2 -11 L -1 -9 L 0 -5 L 0 9 M 7 -7 L 7 -9 L 6 -11 L 5 -12 L 3 -12 L 2 -11 L 1 -9 L 0 -5","-7 7 M -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -4 L 1 -4 L 3 -5 L 4 -7 L 4 -9 L 3 -11 L 1 -12 L -1 -12","-10 10 M -7 9 L -3 9 L -6 2 L -7 -2 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 -2 L 6 2 L 3 9 L 7 9","-9 9 M -7 -12 L 7 -12 M -3 -2 L 3 -2 M -7 9 L 7 9","-11 11 M 0 -12 L 0 9 M -9 -6 L -8 -6 L -7 -5 L -6 -1 L -5 1 L -4 2 L -1 3 L 1 3 L 4 2 L 5 1 L 6 -1 L 7 -5 L 8 -6 L 9 -6","-10 10 M 7 -12 L -7 9 M -7 -12 L 7 -12 M -7 9 L 7 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-8 8 M 0 -14 L -8 0 M 0 -14 L 8 0","-9 9 M -9 16 L 9 16","-4 4 M 1 -7 L -1 -5 L -1 -3 L 0 -2 L 1 -3 L 0 -4 L -1 -3","-10 11 M -1 -5 L -3 -4 L -5 -2 L -6 0 L -7 3 L -7 6 L -6 8 L -4 9 L -2 9 L 0 8 L 3 5 L 5 2 L 7 -2 L 8 -5 M -1 -5 L 1 -5 L 2 -4 L 3 -2 L 5 6 L 6 8 L 7 9 L 8 9","-9 10 M 3 -12 L 1 -11 L -1 -9 L -3 -5 L -4 -2 L -5 2 L -6 8 L -7 16 M 3 -12 L 5 -12 L 7 -10 L 7 -7 L 6 -5 L 5 -4 L 3 -3 L 0 -3 M 0 -3 L 2 -2 L 4 0 L 5 2 L 5 5 L 4 7 L 3 8 L 1 9 L -1 9 L -3 8 L -4 7 L -5 4","-9 9 M -7 -5 L -5 -5 L -3 -3 L 3 14 L 5 16 L 7 16 M 8 -5 L 7 -3 L 5 0 L -5 11 L -7 14 L -8 16","-9 9 M 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 2 8 L 4 6 L 5 3 L 5 0 L 4 -3 L 2 -5 L 0 -7 L -1 -9 L -1 -11 L 0 -12 L 2 -12 L 4 -11 L 6 -9","-8 8 M 5 -3 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -3 -2 L -2 0 L 1 1 M 1 1 L -3 2 L -5 4 L -5 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6","-11 11 M -3 -4 L -5 -3 L -7 -1 L -8 2 L -8 5 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 5 6 L 7 3 L 8 0 L 8 -3 L 6 -5 L 4 -5 L 2 -3 L 0 1 L -2 6 L -5 16","-9 10 M -8 -2 L -6 -4 L -4 -5 L -3 -5 L -1 -4 L 0 -3 L 1 0 L 1 4 L 0 9 M 8 -5 L 7 -2 L 6 0 L 0 9 L -2 13 L -3 16","-10 10 M -9 -1 L -8 -3 L -6 -5 L -4 -5 L -3 -4 L -3 -2 L -4 2 L -6 9 M -4 2 L -2 -2 L 0 -4 L 2 -5 L 4 -5 L 6 -3 L 6 0 L 5 5 L 2 16","-6 5 M 0 -5 L -2 2 L -3 6 L -3 8 L -2 9 L 0 9 L 2 7 L 3 5","-11 11 M -7 -7 L 7 7 M 7 -7 L -7 7","-9 9 M -3 -5 L -7 9 M 7 -4 L 6 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 L -4 1 M -4 1 L -2 2 L -1 3 L 1 8 L 2 9 L 3 9 L 4 8","-8 8 M -7 -12 L -5 -12 L -3 -11 L -2 -10 L 6 9 M 0 -5 L -6 9","-10 11 M -3 -5 L -9 16 M -4 -1 L -5 4 L -5 7 L -3 9 L -1 9 L 1 8 L 3 6 L 5 2 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5","-9 9 M -6 -5 L -3 -5 L -4 1 L -5 6 L -6 9 M 7 -5 L 6 -2 L 5 0 L 3 3 L 0 6 L -3 8 L -6 9","-8 9 M 0 -5 L -2 -4 L -4 -2 L -5 1 L -5 4 L -4 7 L -3 8 L -1 9 L 1 9 L 3 8 L 5 6 L 6 3 L 6 0 L 5 -3 L 4 -4 L 2 -5 L 0 -5","-11 11 M -2 -5 L -6 9 M 3 -5 L 4 1 L 5 6 L 6 9 M -9 -2 L -7 -4 L -4 -5 L 9 -5","-11 10 M -10 -1 L -9 -3 L -7 -5 L -5 -5 L -4 -4 L -4 -2 L -5 3 L -5 6 L -4 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 3 L 5 0 L 6 -5 L 6 -8 L 5 -11 L 3 -12 L 1 -12 L 0 -10 L 0 -8 L 1 -5 L 3 -2 L 5 0 L 8 2","-9 9 M -5 1 L -5 4 L -4 7 L -3 8 L -1 9 L 1 9 L 3 8 L 5 6 L 6 3 L 6 0 L 5 -3 L 4 -4 L 2 -5 L 0 -5 L -2 -4 L -4 -2 L -5 1 L -9 16","-9 11 M 9 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 2 8 L 4 6 L 5 3 L 5 0 L 4 -3 L 3 -4 L 1 -5","-10 10 M 1 -5 L -2 9 M -8 -2 L -6 -4 L -3 -5 L 8 -5","-10 10 M -9 -1 L -8 -3 L -6 -5 L -4 -5 L -3 -4 L -3 -2 L -5 4 L -5 7 L -3 9 L -1 9 L 2 8 L 4 6 L 6 2 L 7 -2 L 7 -5","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 0 L 9 0 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-12 11 M -4 -5 L -6 -4 L -8 -1 L -9 2 L -9 5 L -8 8 L -7 9 L -5 9 L -3 8 L -1 5 M 0 1 L -1 5 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 L 8 2 L 8 -1 L 7 -4 L 6 -5","-8 8 M 2 -12 L 0 -11 L -1 -10 L -1 -9 L 0 -8 L 3 -7 L 6 -7 M 3 -7 L 0 -6 L -2 -5 L -3 -3 L -3 -1 L -1 1 L 2 2 L 4 2 M 2 2 L -2 3 L -4 4 L -5 6 L -5 8 L -3 10 L 1 12 L 2 13 L 2 15 L 0 16 L -2 16","-12 11 M 4 -12 L -4 16 M -11 -1 L -10 -3 L -8 -5 L -6 -5 L -5 -4 L -5 -2 L -6 3 L -6 6 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 8 -2 L 9 -5","-8 7 M 2 -12 L 0 -11 L -1 -10 L -1 -9 L 0 -8 L 3 -7 L 6 -7 M 6 -7 L 2 -5 L -1 -3 L -4 0 L -5 3 L -5 5 L -4 7 L -2 9 L 1 11 L 2 13 L 2 15 L 1 16 L -1 16 L -2 14","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -japanese = ["-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 9 L -11 8 L -10 7 L -9 8 L -9 10 L -10 12 L -11 13","-14 13 M -10 -3 L -8 -1 L 8 -2 L 10 -1 M -9 -2 L 10 -1","-14 13 M -5 -10 L -7 -11 L -7 10 M -6 -10 L -6 10 M -6 8 L 6 8 M -6 -10 L 6 -10 M 5 -10 L 6 -11 L 8 -10 L 7 -8 M 6 -10 L 6 10 M 7 -10 L 7 10 M -6 -1 L 6 -1","-14 13 M -7 -11 L -9 -12 L -9 9 M -8 -11 L -8 9 M -8 -11 L 7 -11 M 6 -11 L 7 -12 L 9 -11 L 8 -9 M 7 -11 L 7 5 L 6 7 L 5 8 M 7 6 L 7 7 L 6 8 M 8 -11 L 8 7 L 7 9 L 6 9 L 5 8 L 3 7 M -1 -11 L -1 -2 M 0 -11 L 0 -2 M -8 -2 L 7 -2","-14 13 M -6 -12 L -8 -7 L -11 -1 M -6 -12 L -5 -11 L -6 -9 L -9 -4 L -11 -1 M -6 -9 L 10 -9 L 8 -11 L 6 -9 M 6 -9 L 9 -10 M 0 -9 L 0 10 M 1 -9 L 1 10 M -4 -3 L -6 -4 L -6 3 M -5 -3 L -5 3 M -5 -3 L 9 -3 L 7 -5 L 5 -3 M 5 -3 L 8 -4 M -11 3 L 11 3 L 9 1 L 7 3 M 7 3 L 10 2","-14 13 M -1 -12 L -1 -6 L -2 -1 L -4 3 L -6 6 L -8 8 L -11 10 M 0 -11 L 0 -7 M -1 -12 L 1 -11 L 0 -4 L -1 0 L -3 4 L -6 7 L -9 9 L -11 10 M -11 -5 L 11 -5 L 9 -7 L 7 -5 M 7 -5 L 10 -6 M 1 -5 L 2 -1 L 3 2 L 4 4 L 6 7 L 9 10 L 11 9 M 7 7 L 9 9 M 1 -5 L 2 -2 L 4 2 L 6 5 L 8 7 L 11 9","-14 13 M -8 -11 L -10 -12 L -10 10 M -9 -11 L -9 10 M -9 -11 L 9 -11 M 8 -11 L 9 -12 L 11 -11 L 10 -9 M 9 -11 L 9 10 M 10 -11 L 10 10 M -7 -7 L 7 -7 L 6 -8 L 5 -7 M -1 -7 L -1 5 M 0 -7 L 0 5 M -6 -1 L 6 -1 L 5 -2 L 4 -1 M -7 5 L 7 5 L 6 4 L 5 5 M 2 1 L 3 3 L 4 3 L 4 2 L 2 1 M -9 9 L 9 9","-14 13 M -1 -12 L -1 -6 L -2 -1 L -4 3 L -6 6 L -8 8 L -11 10 M 0 -11 L 0 -7 M -1 -12 L 1 -11 L 0 -4 L -1 0 L -3 4 L -6 7 L -9 9 L -11 10 M 1 -11 L 1 -7 L 2 -1 L 3 2 L 4 4 L 6 7 L 9 10 L 11 9 M 7 7 L 9 9 M 1 -7 L 2 -2 L 4 2 L 6 5 L 8 7 L 11 9","-14 13 M 0 -11 L 1 -12 L -1 -12 L -1 10 M 0 -11 L 0 10 M -11 -10 L 11 -10 L 9 -11 L 8 -10 M -6 -6 L -8 -7 L -8 3 M -7 -6 L -7 3 M -7 -6 L 6 -6 M 5 -6 L 6 -7 L 8 -6 L 7 -4 M 6 -6 L 6 3 M 7 -6 L 7 3 M -7 -2 L 6 -2 M -7 2 L 6 2 M -1 2 L -4 5 L -7 7 L -11 9 M -1 4 L -4 6 L -6 7 L -11 9 M 0 2 L 3 6 L 6 8 L 9 9 L 11 8 M 0 2 L 3 5 L 7 7 L 11 8","-14 13 M 0 -10 L 1 -11 L -1 -12 L -1 11 M 0 -11 L 0 11 M -8 -6 L -10 -7 L -10 4 M -9 -6 L -9 4 M -9 -6 L 8 -6 M 7 -6 L 8 -7 L 10 -6 L 9 -4 M 8 -6 L 8 4 M 9 -6 L 9 4 M -9 3 L 8 3","-14 13 M 0 -10 L 1 -11 L -1 -12 L -1 10 M 0 -11 L 0 10 M -11 -6 L 11 -6 L 9 -8 L 7 -6 M 7 -6 L 10 -7 M -2 -6 L -5 0 L -8 4 L -11 7 M -1 -5 L -3 -1 L -5 2 L -7 4 L -11 7 M 1 -5 L 2 -2 L 3 0 L 6 4 L 9 7 L 11 6 M 7 4 L 9 6 M 1 -5 L 2 -3 L 5 1 L 8 4 L 11 6 M -5 5 L 4 5 L 3 4 L 2 5","-14 13 M 0 -11 L 0 -12 L 1 -13 L -1 -13 L -1 -11 M -11 -11 L 11 -11 L 9 -13 L 7 -11 M 7 -11 L 10 -12 M -6 -7 L -8 -8 L -8 0 M -7 -7 L -7 0 M -7 -7 L 6 -7 M 5 -7 L 6 -8 L 8 -7 L 7 -5 M 6 -7 L 6 0 M 7 -7 L 7 0 M -7 -1 L 6 -1 M -1 -1 L -1 6 L -2 8 L -3 9 M -1 7 L -1 8 L -2 9 M 0 -1 L 0 8 L -1 10 L -2 10 L -3 9 L -5 8 M -6 2 L -11 7 M -6 2 L -5 3 L -11 7 M 4 2 L 6 4 L 8 7 L 9 7 L 9 6 L 8 5 L 4 2","-14 13 M -1 -12 L -1 9 M -1 -12 L 0 -12 L 0 9 M -8 -10 L -8 -2 M -8 -10 L -7 -10 L -7 -2 M -7 -3 L 6 -3 M 6 -10 L 6 -2 M 6 -10 L 7 -10 L 7 -2 M -10 1 L -10 10 M -10 1 L -9 1 L -9 10 M -9 9 L 8 9 M 8 1 L 8 10 M 8 1 L 9 1 L 9 10","-14 13 M -10 -12 L -10 5 M -10 -12 L -9 -11 L -9 5 M -9 -11 L -5 -11 M -5 -11 L -5 4 M -6 -11 L -5 -12 L -4 -11 L -4 4 M -9 -4 L -5 -4 M -9 3 L -5 3 M 3 -11 L 4 -12 L 2 -12 L 2 -4 M 3 -11 L 3 -4 M -2 -8 L 9 -8 L 7 -9 L 6 -8 M -4 -4 L 11 -4 L 9 -5 L 8 -4 M 5 -4 L 5 8 L 4 9 M 6 -4 L 6 8 L 5 10 L 4 9 L 2 8 M -4 0 L 11 0 L 9 -1 L 8 0 M -1 2 L 0 3 L 1 5 L 2 5 L 2 4 L 1 3 L -1 2","-14 13 M 0 -10 L 1 -11 L -1 -12 L -1 9 M 0 -11 L 0 9 M 0 -2 L 9 -2 L 7 -4 L 5 -2 M 5 -2 L 8 -3 M -11 9 L 11 9 L 9 7 L 7 9 M 7 9 L 10 8","-14 13 M -1 -11 L 0 -12 L -2 -12 L -2 -5 M -1 -11 L -1 -5 M -9 -9 L 3 -9 L 2 -10 L 1 -9 M -11 -5 L 11 -5 L 9 -6 L 8 -5 M 6 -11 L 3 -7 L 0 -4 L -4 -1 L -9 2 M 6 -11 L 7 -10 L 2 -5 L -2 -2 L -5 0 L -9 2 L -11 3 M -3 -1 L -5 -2 L -5 10 M -4 -1 L -4 10 M -4 -1 L 6 -1 M 5 -1 L 6 -2 L 8 -1 L 7 1 M 6 -1 L 6 10 M 7 -1 L 7 10 M -4 4 L 6 4 M -4 9 L 6 9","-14 13 M 0 -10 L 1 -11 L -1 -12 L -1 10 M 0 -11 L 0 10 M -11 -3 L 11 -3 L 9 -5 L 7 -3 M 7 -3 L 10 -4","-14 13 M -11 -1 L 11 -1 L 8 -3 L 6 -1 M 6 -1 L 9 -2","-14 13 M -8 -8 L 8 -8 L 6 -10 L 4 -8 M 4 -8 L 7 -9 M -11 6 L 11 6 L 9 4 L 7 6 M 7 6 L 10 5","-14 13 M -9 -9 L 9 -9 L 7 -11 L 5 -9 M 5 -9 L 8 -10 M -7 -1 L 7 -1 L 5 -3 L 3 -1 M 3 -1 L 6 -2 M -11 8 L 11 8 L 9 6 L 7 8 M 7 8 L 10 7","-14 13 M -8 -9 L -10 -10 L -10 8 M -9 -9 L -9 8 M -9 -9 L 9 -9 M 8 -9 L 9 -10 L 11 -9 L 10 -7 M 9 -9 L 9 8 M 10 -9 L 10 8 M -3 -9 L -3 -4 L -4 0 L -5 2 M -2 -9 L -2 -4 L -3 -1 L -5 2 L -7 4 M 1 -9 L 1 1 L 2 2 L 6 2 L 7 1 L 6 0 M 2 -9 L 2 0 L 3 1 L 5 1 L 6 0 L 6 -2 M -9 7 L 9 7","-14 13 M -9 -10 L 8 -10 L 6 -12 L 4 -10 M 4 -10 L 7 -11 M -1 -10 L -4 8 M 0 -10 L -3 8 M -9 -2 L 4 -2 M 3 -2 L 4 -3 L 6 -2 L 5 0 M 4 -2 L 3 8 M 5 -2 L 5 0 L 4 8 M -11 8 L 11 8 L 9 6 L 7 8 M 7 8 L 10 7","-14 13 M 0 -9 L 1 -10 L -1 -11 L -1 -5 M 0 -10 L 0 -5 M -11 -5 L 11 -5 L 9 -7 L 7 -5 M 7 -5 L 10 -6 M -5 -1 L -6 2 L -8 6 L -10 9 M -4 0 L -5 2 M -5 -1 L -3 0 L -5 3 L -8 7 L -10 9 M 2 -1 L 4 1 L 7 5 L 8 7 L 9 8 L 10 7 L 9 5 L 6 2 L 2 -1 M 7 4 L 9 7","-14 13 M -5 -9 L -4 -10 L -6 -11 L -6 8 L -5 9 L 7 9 L 8 8 L 7 6 M 6 8 L 7 8 L 7 7 M -5 -10 L -5 7 L -4 8 L 5 8 L 7 6 L 8 3 M -10 -1 L -4 -2 L 1 -3 L 9 -5 L 6 -6 L 5 -4 M 5 -4 L 7 -5","-14 13 M 0 -6 L -1 -3 L -3 2 L -5 5 L -8 8 L -11 10 M 0 -6 L 1 -5 L 0 -2 L -2 2 L -4 5 L -6 7 L -9 9 L -11 10 M -6 -11 L 3 -11 M 0 -11 L 1 -12 L 3 -11 L 1 -9 M 1 -11 L 1 -6 L 2 -1 L 3 2 L 4 4 L 6 7 L 9 10 L 11 9 M 7 7 L 9 9 M 1 -6 L 2 -2 L 4 2 L 6 5 L 8 7 L 11 9","-14 13 M -4 -9 L -3 -10 L -5 -11 L -5 0 L -6 4 L -8 7 L -11 10 M -4 -10 L -4 0 L -5 4 L -7 7 L -11 10 M -11 -4 L 2 -5 M 1 -5 L 2 -6 L 4 -5 L 3 -3 M 2 -5 L 2 8 L 3 9 L 10 9 L 11 8 L 10 6 M 9 8 L 10 8 L 10 7 M 3 -5 L 3 7 L 4 8 L 8 8 L 10 6 L 11 3","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -3 -12 L -1 -11 L -1 -9 L -2 -6 M -2 -11 L -2 0 L -1 4 M -7 -7 L -5 -6 L 0 -6 L 3 -7 L 6 -8 M 3 -7 L 4 -8 L 6 -8 M 1 1 L 2 -3 L 3 -2 L 1 1 L -2 5 L -4 7 L -6 8 L -8 8 L -9 7 L -9 4 L -8 2 L -6 0 L -4 -1 L -1 -2 L 4 -2 L 7 -1 L 9 1 L 10 3 L 10 5 L 9 7 L 7 9 L 4 10 L 2 10 M -7 8 L -8 7 L -8 4 L -7 2 L -5 0 L -1 -2 M 4 -2 L 6 -1 L 8 1 L 9 3 L 9 5 L 8 7 L 6 9 L 4 10","-14 13 M -10 -10 L -8 -9 L -8 -7 L -9 -5 L -10 -2 M -9 -9 L -9 -7 L -10 -2 L -10 1 L -9 4 L -8 5 L -6 6 L -5 6 L -5 4 L -4 1 L -3 -1 M -8 5 L -6 5 L -5 4 M 5 -6 L 7 -5 L 9 -2 L 10 1 L 10 3 L 8 2 L 5 3 M 9 -2 L 9 1 L 8 2","-14 13 M -4 -13 L -3 -12 L -1 -11 L 3 -11 M -3 -12 L 2 -12 L 3 -11 L -1 -9 M -7 -5 L -7 -4 L -6 -3 L -5 -3 L -2 -5 L 0 -6 M -7 -4 L -6 -4 L -3 -5 L 0 -6 L 2 -6 L 5 -5 L 6 -3 L 6 0 L 5 3 L 3 6 L 0 8 L -4 10 M 2 -6 L 4 -5 L 5 -3 L 5 0 L 4 3 L 3 5 L 1 7 L -2 9","-14 13 M -4 -13 L -3 -12 L -1 -11 L 3 -11 M -3 -12 L 2 -12 L 3 -11 L -1 -9 M -8 -5 L -8 -4 L -7 -3 L -5 -3 L 0 -5 L 3 -6 L 4 -5 M -8 -4 L -5 -4 L 0 -5 M 4 -5 L 0 -2 L -6 4 L -10 8 M 3 -6 L 0 -2 M -10 8 L -10 7 L -6 4 L -4 3 L 0 3 L 1 4 L 2 8 L 3 9 L 10 9 M 5 9 L 8 8 L 9 8 L 10 9","-14 13 M -5 -12 L -3 -11 L -3 -9 L -4 -5 M -4 -11 L -4 9 M -4 2 L -3 8 L -4 9 L -5 7 L -7 6 L -10 5 M -10 -5 L -8 -4 L -4 -4 L -1 -5 L 1 -6 M -4 -4 L -2 -5 L -1 -6 L 1 -6 M -10 6 L -6 3 L -1 0 L 2 -1 L 4 -1 L 7 0 L 8 2 L 8 4 L 7 6 L 5 7 L 3 7 L 1 6 L 0 4 M -10 6 L -10 5 L -6 3 M 4 -1 L 6 0 L 7 2 L 7 4 L 6 6 L 5 7 M 5 -7 L 7 -7 L 9 -6 L 10 -5 L 8 -5 L 7 -4 M 7 -7 L 8 -6 L 8 -5","-14 13 M -4 -12 L -2 -11 L -2 -9 L -3 -6 L -5 -1 L -10 9 M -3 -11 L -3 -9 L -5 -3 L -7 2 L -10 9 M -10 -5 L -10 -4 L -9 -3 L -8 -3 L -5 -5 L -3 -6 L 0 -6 L 2 -5 L 3 -3 L 3 0 L 2 4 L 0 8 L -1 9 L -2 9 L -2 8 L -3 7 L -5 6 M -10 -4 L -8 -4 L -5 -5 M 0 -6 L 2 -4 L 2 0 L 1 4 L 0 6 L -2 8 M 5 -5 L 7 -4 L 9 -2 L 10 0 L 10 2 L 9 1 L 7 2 M 8 -3 L 9 -1 L 9 1","-14 13 M -4 -12 L -1 -11 L 0 -7 L 1 -4 L 3 0 L 6 4 L 5 5 M -2 -11 L 0 -7 M 3 0 L 5 5 M -6 -7 L -4 -6 L -1 -6 L 2 -7 M -9 -3 L -8 -2 L -5 -1 L 0 -1 L 5 -2 L 8 -3 M 5 -2 L 7 -4 L 8 -3 M 5 5 L 3 4 L 0 3 L -4 3 L -6 4 L -7 5 L -7 7 L -6 8 L -4 9 L -1 10 L 5 10 M -4 9 L 4 9 L 5 10","-14 13 M 2 -12 L 4 -11 L 4 -10 L -4 -2 M 3 -11 L 2 -9 L -4 -2 L -4 -1 L 1 4 L 3 7 L 4 9 M -4 -1 L 4 6 L 5 8 L 4 9","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 L -4 -3 L -3 -4 L -1 -5 L 8 -5 L 10 -6 M -9 3 L -8 5 L -7 6 M 4 -5 L 8 -6 L 9 -7 L 10 -6 M 4 -12 L 6 -11 L 6 3 L 5 6 L 3 8 L 0 10 M 5 -11 L 6 -8 M 6 0 L 5 4 L 3 7 L 0 10","-14 13 M -5 -10 L -3 -9 L 0 -8 L 2 -8 L 5 -9 M -3 -9 L 2 -9 L 4 -10 L 5 -9 L -1 -6 M -7 1 L -7 3 L -6 5 L -4 6 L 0 7 L 7 7 M -4 6 L 6 6 L 7 7","-14 13 M -8 -7 L -7 -6 L -4 -5 L 0 -5 L 4 -6 L 6 -7 L 7 -8 M 4 -6 L 6 -8 L 7 -8 M -2 -12 L -1 -9 L 0 -7 L 3 -3 L 5 0 L 6 2 M -2 -12 L -1 -12 L -1 -10 L 0 -7 M 3 -3 L 6 0 L 7 2 L 7 3 M 7 3 L 6 2 L 4 1 L 0 0 L -4 0 L -7 1 L -8 3 L -8 5 L -7 7 L -5 8 L -1 9 L 3 9 M -8 5 L -7 6 L -5 7 L -1 8 L 4 8 L 3 9","-14 13 M -6 -12 L -4 -11 L -5 1 L -5 6 L -4 8 M -5 -11 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 L 1 9 L 4 8 L 7 6 L 9 4","-14 13 M 0 -12 L 2 -11 L 2 1 L 1 3 L -1 4 L -3 3 L -4 1 L -4 0 L -3 -2 L -1 -3 L 1 -2 L 2 0 L 2 4 L 1 8 L -1 10 M 1 -11 L 2 -6 M 2 4 L 1 7 L -1 10 M -10 -8 L -8 -6 L -5 -6 L 4 -7 L 8 -8 L 10 -7 M -9 -7 L -5 -6 M 4 -7 L 10 -7","-14 13 M -6 -8 L -4 -7 L -4 4 L -3 6 L -2 7 L 0 8 L 8 8 M -5 -7 L -4 -4 M 3 8 L 6 7 L 7 7 L 8 8 M 3 -11 L 5 -10 L 5 2 L 4 4 L 3 3 L 0 1 M 4 -10 L 5 -7 M 5 -1 L 4 2 L 3 3 M -10 -4 L -8 -2 L -6 -2 L -2 -3 L 3 -4 L 7 -5 L 9 -5 L 10 -4 M -9 -3 L -2 -3 M 3 -4 L 10 -4","-14 13 M -4 -11 L -2 -9 L 4 -11 M -3 -10 L -1 -10 L 4 -11 L 5 -10 M 5 -10 L 2 -7 L -4 -3 L -8 -1 M 4 -11 L 3 -9 L 1 -7 L -4 -3 M -9 -2 L -7 0 L -3 -2 M -8 -1 L -3 -2 L 3 -3 L 8 -4 L 9 -3 M 3 -3 L 9 -3 M 3 -3 L 1 -2 L -1 0 L -2 2 L -2 4 L -1 6 L 0 7 L 3 8 L 7 8 M -1 6 L 2 7 L 6 7 L 7 8","-14 13 M -4 -12 L -2 -11 L -2 -9 L -4 -3 L -5 0 L -7 5 L -9 9 M -3 -11 L -3 -8 L -4 -3 M -5 0 L -7 4 L -9 7 L -9 9 M -10 -5 L -8 -4 L -5 -4 L -2 -5 L 0 -6 L 2 -7 M 0 -6 L 1 -8 L 2 -7 M 3 -4 L 6 -4 L 9 -3 L 7 -3 L 5 -2 M 6 -4 L 7 -3 M 0 4 L 1 6 L 2 7 L 4 8 L 9 8 M 1 6 L 3 7 L 10 7 L 9 8","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 -4 L -6 0 L -6 2 L -5 3 M -4 -11 L -4 -7 M -5 -4 L -5 3 M -10 -8 L -7 -7 L -3 -7 L 1 -8 L 3 -9 M 1 -8 L 2 -10 L 3 -9 M -5 3 L -3 1 L 0 -1 L 3 -2 L 6 -2 L 8 -1 L 9 1 L 9 4 L 8 6 L 5 8 L 1 9 L -3 9 M 6 -2 L 7 -1 L 8 1 L 8 4 L 7 6 L 5 8","-14 13 M -10 -6 L -8 -4 L -3 -6 L 1 -7 L 5 -7 L 8 -6 L 9 -5 L 10 -3 L 10 0 L 9 2 L 8 3 L 6 4 L 3 5 L -2 6 M -9 -5 L -3 -6 M 5 -7 L 7 -6 L 8 -5 L 9 -3 L 9 0 L 8 2 L 6 4","-14 13 M -10 -9 L -8 -7 L -6 -7 L -2 -8 L 3 -9 L 7 -10 L 9 -10 L 10 -9 M -9 -8 L -2 -8 M 3 -9 L 10 -9 M 7 -9 L 4 -8 L 1 -6 L -1 -3 L -2 0 L -2 3 L -1 6 L 0 7 L 2 8 L 6 9 L 9 9 M -2 3 L -1 5 L 0 6 L 2 7 L 6 8 L 8 8 L 9 9","-14 13 M -3 -12 L -1 -11 L -1 -1 M -2 -11 L -2 -5 L -1 -1 M 5 -4 L 7 -2 L -1 -1 M 6 -3 L 2 -2 L -1 -1 L -4 0 L -6 1 L -7 3 L -7 5 L -6 7 L -5 8 L -3 9 L 8 9 M -6 7 L -4 8 L 7 8 L 8 9","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 -3 L -6 0 L -8 5 L -10 9 M -4 -11 L -4 -8 L -5 -3 M -6 0 L -8 4 L -10 7 L -10 9 M -10 -5 L -8 -4 L -6 -4 L -3 -5 L -1 -6 L 1 -7 M -1 -6 L 0 -8 L 1 -7 M 4 -8 L 6 -8 L 8 -7 L 10 -5 L 8 -6 L 6 -5 M 6 -8 L 8 -6 M 4 -3 L 4 -1 L 5 2 L 6 4 L 6 6 L 5 8 L 3 9 L 0 9 L -2 8 L -3 6 L -2 4 L 0 3 L 3 3 L 5 4 L 9 8 M 4 -1 L 5 4 L 5 7 L 3 9 M 7 6 L 8 8 L 9 8","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M 1 -8 L 4 -9 L 7 -9 L 9 -8 L 7 -8 L 5 -7 M 5 -9 L 7 -8 M -1 1 L -1 3 L 0 5 L 3 6 L 10 6 M -1 3 L 0 4 L 3 5 L 8 5 L 10 6","-14 13 M -8 -9 L -6 -8 L -6 -3 M -7 -8 L -6 -3 L -5 0 L -4 2 L -3 4 L -2 5 M -4 2 L -2 4 L -2 5 M 0 -11 L 2 -10 L 2 -8 L 0 -3 L -3 4 L -5 7 L -7 8 L -9 8 L -10 6 L -10 4 L -9 1 L -8 -1 L -6 -3 L -3 -5 L 1 -6 L 4 -6 L 7 -5 L 9 -3 L 10 0 L 10 3 L 9 6 L 8 7 L 6 8 L 4 8 L 2 7 L 1 6 L 1 5 L 2 4 L 4 3 L 6 3 L 8 4 L 10 7 M 1 -10 L 1 -8 L 0 -3 M -8 8 L -9 6 L -9 3 L -8 0 L -6 -3 M 4 -6 L 6 -5 L 8 -3 L 9 0 L 9 4 L 8 7 M 8 4 L 10 6 L 10 7","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 9 M -4 -11 L -4 9 L -5 9 L -6 6 L -7 5 L -9 4 M -10 -6 L -9 -4 L -7 -4 L -3 -6 L -3 -5 M -9 -5 L -6 -5 L -4 -6 L -5 -2 M -3 -5 L -5 -2 L -7 1 L -10 5 L -10 4 L -7 1 L -3 -3 L 1 -6 L 4 -7 L 6 -7 L 8 -6 L 9 -4 L 9 3 L 8 6 L 7 7 L 5 8 L 3 8 L 1 7 L 0 6 L 0 5 L 1 4 L 3 3 L 5 3 L 7 4 L 8 5 L 10 8 M 6 -7 L 7 -6 L 8 -4 L 8 4 L 7 7 M 8 5 L 10 7 L 10 8","-14 13 M -1 -10 L 0 -8 L 0 -5 L -1 -2 L -2 0 L -4 3 L -6 5 L -8 5 L -9 4 L -10 2 L -10 -1 L -9 -4 L -7 -7 L -4 -9 L -1 -10 L 2 -10 L 5 -9 L 7 -8 L 9 -6 L 10 -3 L 10 0 L 9 3 L 7 5 L 5 6 L 2 7 L -1 7 M -4 3 L -6 4 L -8 4 L -9 2 L -9 -1 L -8 -5 L -7 -7 M 5 -9 L 8 -6 L 9 -3 L 9 0 L 8 3 L 5 6","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M 3 -11 L 5 -10 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -10 L 5 -6 M 4 3 L 9 6 L 9 7 M -2 -5 L 0 -4 L 3 -4 L 7 -5 L 9 -6 M 7 -5 L 8 -7 L 9 -6","-14 13 M -9 -11 L -8 -10 L -6 -9 L -2 -9 M -8 -10 L -3 -10 L -2 -9 M -2 -9 L -5 -7 L -7 -5 L -9 -2 L -10 1 L -10 4 L -9 6 L -8 7 L -6 8 L -3 8 L 0 7 L 2 5 L 3 3 L 4 -1 L 4 -5 L 3 -9 L 4 -9 M -10 3 L -9 5 L -8 6 L -6 7 L -3 7 L 0 6 L 2 4 L 3 2 L 4 -1 M 4 -9 L 6 -6 L 7 -4 L 9 -1 L 10 1 L 8 1 L 7 2 M 3 -9 L 6 -6 M 7 -4 L 8 -1 L 8 1","-14 13 M -2 -12 L -1 -9 L 1 -8 M -1 -10 L 1 -9 L 2 -9 L 2 -8 M 2 -8 L -1 -7 L -3 -6 L -4 -5 L -4 -3 L -3 -2 L -1 -1 L 1 0 L 2 1 L 3 3 L 3 5 L 2 7 L 0 8 L -2 8 L -5 7 L -7 5 M -1 -1 L 1 1 L 2 3 L 2 5 L 1 7 L 0 8 M -9 7 L -6 4 L -3 2 L 0 1 M 4 1 L 7 2 L 9 4 L 10 6 L 7 6 M -9 7 L -9 6 L -6 4 M 4 1 L 6 2 L 8 4 L 9 6","-14 13 M -10 -2 L -8 0 L -5 -5 M -9 -1 L -4 -6 L -2 -6 L 3 -1 L 7 2 L 9 3 L 10 4 L 8 4 L 6 5 M 3 -1 L 8 4","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M -1 -11 L 1 -10 L 3 -10 L 7 -11 M 3 -10 L 5 -11 L 6 -12 L 7 -11 M -2 -3 L 1 -2 L 4 -2 L 7 -3 L 9 -4 M 7 -3 L 8 -5 L 9 -4 M 3 -10 L 5 -9 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -9 L 5 -5 M 4 3 L 9 6 L 9 7","-14 13 M 0 -12 L 2 -11 L 2 6 L 1 8 L -1 9 L -3 9 L -5 8 L -6 6 L -5 4 L -3 3 L -1 3 L 2 4 L 5 6 L 8 9 M 1 -11 L 2 -7 M 5 6 L 8 8 L 8 9 M -10 -9 L -8 -7 L 1 -7 L 8 -8 M -9 -8 L -4 -7 M 1 -7 L 5 -8 L 7 -9 L 8 -8 M -5 -2 L -3 -1 L 1 -1 L 5 -2 L 7 -3 M 5 -2 L 6 -4 L 7 -3","-14 13 M -8 -11 L -7 -9 L -5 -9 L -2 -10 L 1 -12 L 2 -11 M -7 -10 L -2 -10 M 2 -11 L -2 -5 L -5 1 L -7 4 L -8 5 L -9 5 L -10 4 L -10 2 L -9 0 L -7 -1 L -2 -1 L 2 0 L 5 1 L 10 3 M 1 -12 L -2 -5 M 2 0 L 10 2 L 10 3 M 4 -5 L 6 -4 L 6 2 L 5 5 L 3 7 L 1 8 L -2 9 M 5 -4 L 5 3 L 4 6","-14 13 M -5 -12 L -3 -11 L -3 -9 L -4 -5 L -5 -1 L -6 2 L -7 4 L -8 5 L -9 5 L -10 4 L -10 2 L -9 0 L -8 -1 L -7 -1 L -6 0 L -6 5 L -5 8 L -3 9 L 3 9 L 6 8 L 7 7 L 6 6 L 5 4 L 4 0 L 4 -4 L 5 -5 L 7 -5 L 9 -4 L 10 -2 L 10 -1 L 9 -1 L 7 0 M -4 -11 L -4 -5 M -6 5 L -5 7 L -3 8 L 3 8 L 5 7 L 6 6 M 7 -5 L 9 -3 L 9 -1 M -10 -7 L -7 -6 L -4 -6 L -1 -7 L 1 -8 M -1 -7 L 0 -9 L 1 -8","-14 13 M -8 -9 L -6 -8 L -6 -3 M -7 -8 L -6 -3 L -5 0 L -4 2 L -3 4 L -2 5 M -4 2 L -2 4 L -2 5 M 1 -11 L 3 -10 L 3 -8 L 2 -5 L 0 0 L -1 2 L -3 5 L -5 7 L -7 8 L -9 8 L -10 7 L -10 5 L -9 2 L -8 0 L -6 -2 L -3 -4 L 0 -5 L 4 -5 L 7 -4 L 9 -2 L 10 1 L 10 4 L 9 6 L 8 7 L 6 8 L 3 9 L 0 9 M 2 -10 L 2 -8 L 0 0 M -8 8 L -9 7 L -9 4 L -8 1 L -6 -2 M 4 -5 L 6 -4 L 8 -2 L 9 1 L 9 4 L 8 6 L 6 8","-14 13 M -3 -12 L -1 -11 L -1 -9 L -2 -5 M -2 -11 L -2 2 L -1 6 L 0 8 L 2 9 L 6 9 L 8 8 L 9 6 L 9 4 L 8 2 L 6 0 L 3 -2 M 5 9 L 7 8 L 8 6 L 8 3 L 7 1 M -6 -8 L -5 -7 L -2 -6 L 1 -6 M -5 -7 L 0 -7 L 1 -6 M 1 -6 L -2 -5 L -4 -4 L -6 -2 L -7 0 L -6 2 L -4 3 L 1 3","-14 13 M -2 -12 L 0 -11 L 1 -10 L 2 -8 L 1 -7 L -2 -8 L -5 -8 L -6 -7 L -6 -5 L -3 2 L -1 9 M 0 -11 L 1 -9 L 1 -7 M -3 2 L 0 8 L -1 9 M -10 -4 L -9 -2 L -7 -2 L -4 -4 L 0 -6 L 4 -7 L 7 -7 L 9 -6 L 10 -4 L 10 -2 L 9 0 L 8 1 L 5 2 L 2 2 L -1 1 M -9 -3 L -7 -3 L -4 -4 M 7 -7 L 8 -6 L 9 -4 L 9 -2 L 8 0 L 7 1 L 5 2","-14 13 M -10 -10 L -8 -9 L -8 -7 L -9 -5 L -10 -2 M -9 -9 L -9 -7 L -10 -2 L -10 1 L -9 4 L -8 5 L -6 6 L -5 6 L -5 4 L -4 1 L -3 -1 M -8 5 L -6 5 L -5 4 M 5 -6 L 7 -5 L 9 -2 L 10 1 L 10 3 L 8 2 L 5 3 M 9 -2 L 9 1 L 8 2","-14 13 M -10 -8 L -8 -7 L -8 -5 L -9 -2 M -9 -7 L -9 2 L -8 5 L -7 6 L -7 4 L -6 1 L -5 -1 L -3 -4 L 0 -7 L 3 -8 L 6 -8 L 8 -7 L 9 -6 L 10 -4 L 10 -1 L 9 1 L 7 3 L 5 4 L 2 4 L 0 3 L -2 1 L -3 -2 L -3 -5 L -2 -9 L -1 -11 L 1 -12 L 3 -12 L 4 -10 L 4 1 L 3 5 L 2 7 L -1 9 M -9 2 L -8 4 L -7 4 M 8 -7 L 9 -4 L 9 -1 L 8 2 M 4 1 L 3 4 L 2 6 L -1 9","-14 13 M -4 -13 L -3 -12 L -1 -11 L 3 -11 M -3 -12 L 2 -12 L 3 -11 L -1 -9 M -8 -5 L -8 -4 L -7 -3 L -5 -3 L 0 -5 L 3 -6 L 4 -5 M -8 -4 L -5 -4 L 0 -5 M 4 -5 L 0 -2 L -6 4 L -10 8 M 3 -6 L 0 -2 M -10 8 L -10 7 L -6 4 L -4 3 L 0 3 L 1 4 L 2 8 L 3 9 L 10 9 M 5 9 L 8 8 L 9 8 L 10 9","-14 13 M -2 -12 L 1 -11 L 1 -9 L 0 -4 M 0 -11 L 0 6 L -1 8 L -3 9 L -6 9 L -8 8 L -9 7 L -9 5 L -8 4 L -6 3 L -3 3 L 0 4 L 4 6 L 9 9 M 0 4 L 5 6 L 9 8 L 9 9 M 0 -4 L 3 -4 L 7 -5 M 3 -4 L 5 -5 L 6 -6 L 7 -5","-14 13 M -3 -12 L -1 -12 L 1 -11 L 2 -10 L 0 -10 L -2 -9 M -1 -12 L 0 -11 L 0 -10 M -6 -6 L -7 -4 L -8 0 L -8 2 L -7 3 L -3 0 L -1 -1 L 2 -2 L 5 -2 L 7 -1 L 8 1 L 8 3 L 7 5 L 5 7 L 3 8 L -1 9 L -3 9 M -8 0 L -7 2 L -6 2 M 5 -2 L 6 -1 L 7 1 L 7 3 L 6 5 L 4 7 L 2 8 L -1 9","-14 13 M -6 -12 L -4 -11 L -4 -9 L -6 -5 M -5 -11 L -5 -9 L -6 -5 L -6 -2 L -5 1 L -4 2 L -4 0 L -3 -3 L -1 -6 L 1 -8 L 3 -9 L 5 -9 L 6 -8 L 7 -5 L 7 0 L 6 4 L 4 7 L 1 9 L -3 10 M -6 -2 L -5 0 L -4 0 M 4 -9 L 5 -8 L 6 -5 L 6 0 L 5 4 L 3 7 L 1 9","-14 13 M -5 -11 L -4 -9 L -2 -9 L 3 -11 M -4 -10 L -2 -10 L 3 -11 L 4 -10 M 4 -10 L 0 -7 L -4 -2 L -7 3 M 3 -11 L 0 -7 M -4 -2 L -7 1 L -7 3 M -7 3 L -5 1 L -2 -1 L 1 -2 L 4 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 4 9 L 1 9 L -1 8 L -2 7 L -2 6 L -1 5 L 1 5 L 3 6 L 5 8 M 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 4 9","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 9 M -4 -11 L -4 9 L -5 9 L -6 6 L -7 5 L -9 4 M -10 -6 L -9 -4 L -7 -4 L -3 -6 L -3 -5 M -9 -5 L -6 -5 L -3 -6 L -5 -2 M -3 -5 L -5 -2 L -7 1 L -10 5 L -10 4 L -7 1 L -3 -3 L 1 -6 L 4 -7 L 5 -7 L 7 -6 L 8 -4 L 7 6 L 7 8 L 8 9 M 5 -7 L 6 -6 L 7 -4 L 6 6 L 6 8 L 7 9 L 8 9 L 9 8 L 10 6","-14 13 M -5 -11 L -4 -9 L -2 -9 L 3 -11 M -4 -10 L -2 -10 L 3 -11 L 4 -10 M 4 -10 L 0 -7 L -4 -2 L -7 3 M 3 -11 L 0 -7 M -4 -2 L -7 1 L -7 3 M -7 3 L -5 1 L -2 -1 L 1 -2 L 4 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 5 9 L 2 10 L 0 10 M 4 -2 L 6 0 L 7 2 L 7 5 L 6 8","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 9 M -4 -11 L -4 9 L -5 9 L -6 6 L -7 5 L -9 4 M -10 -6 L -9 -4 L -7 -4 L -3 -6 L -3 -5 M -9 -5 L -6 -5 L -3 -6 L -5 -2 M -3 -5 L -5 -2 L -7 1 L -10 5 L -10 4 L -7 1 L -4 -2 L -1 -4 L 2 -5 L 5 -5 L 7 -4 L 8 -3 L 9 -1 L 9 2 L 8 5 L 6 7 L 4 8 L 1 9 M 5 -5 L 7 -3 L 8 -1 L 8 2 L 7 5 L 4 8","-14 13 M -5 -11 L -4 -9 L -2 -9 L 2 -11 M -4 -10 L -2 -10 L 2 -11 L 3 -10 M 3 -10 L -1 -4 L -5 4 L -6 6 L -7 7 L -9 7 L -10 5 L -10 3 L -9 1 L -7 -1 L -4 -3 L 0 -4 L 4 -4 L 7 -3 L 9 -1 L 10 1 L 10 4 L 9 6 L 7 8 L 5 9 L 2 9 L 0 8 L -1 7 L -1 6 L 0 5 L 2 5 L 4 6 L 6 8 M 2 -11 L -1 -4 M -8 7 L -9 5 L -9 3 L -8 0 M 8 -2 L 9 1 L 9 4 L 8 7","-14 13 M -4 -13 L -3 -12 L -1 -11 L 3 -11 M -3 -12 L 2 -12 L 3 -11 L -1 -9 M -7 -5 L -7 -4 L -6 -3 L -5 -3 L -2 -5 L 0 -6 M -7 -4 L -6 -4 L -3 -5 L 0 -6 L 2 -6 L 5 -5 L 6 -3 L 6 0 L 5 3 L 3 6 L 0 8 L -4 10 M 2 -6 L 4 -5 L 5 -3 L 5 0 L 4 3 L 3 5 L 1 7 L -2 9","-14 13 M -6 -11 L -5 -9 L -3 -9 L -1 -10 L 2 -12 M -5 -10 L -3 -10 L 0 -11 L 2 -12 L 3 -11 M 3 -11 L -1 -8 L -5 -4 L -8 0 M 2 -12 L -1 -8 M -8 0 L -8 -2 L -5 -4 L -3 -5 L 0 -6 L 3 -6 L 5 -5 L 6 -3 L 6 -1 L 5 1 L 3 2 L -2 2 L -3 1 L -3 -1 L -2 -2 L 0 -2 L 1 -1 L 1 1 L 0 2 L -4 3 L -7 5 L -10 8 L -10 9 L -9 9 L -7 5 M -8 7 L -6 6 L -4 6 L -2 8 L -1 8 L 1 6 L 4 5 L 7 5 L 9 6 L 10 7 L 10 9 L 9 8 L 7 8 M -4 6 L -2 7 L -1 7 L 1 6 M 7 5 L 9 7 L 9 8","-14 13 M -2 -12 L 0 -11 L 0 -10 L -2 -6 L -4 -3 L -7 0 L -10 3 M -1 -11 L -1 -10 L -2 -6 M -7 0 L -10 2 L -10 3 M -5 -2 L -3 -3 L -1 -3 L 1 -2 L 2 0 L 2 4 M -1 -3 L 0 -2 L 1 0 L 1 5 L 2 4 M -9 -8 L -6 -7 L -3 -7 L 1 -8 L 5 -9 M 1 -8 L 4 -10 L 5 -9 M 9 -3 L 10 -1 L 2 0 L -1 1 L -3 2 L -4 4 L -4 6 L -3 8 L -1 9 L 7 9 M 9 -2 L 2 0 M 2 9 L 6 8 L 7 9","-14 13 M -1 -12 L 1 -10 L -2 -5 L -6 2 L -10 9 M 0 -11 L -2 -5 M -10 9 L -10 7 L -6 2 L -4 0 L -2 -1 L 0 -1 L 2 0 L 2 5 L 3 7 L 4 8 M 0 -1 L 1 0 L 1 5 L 2 7 L 4 8 L 6 8 L 8 7 L 9 5 L 10 2","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -4 -12 L -2 -11 L -2 -9 L -3 -6 L -5 -1 L -10 9 M -3 -11 L -3 -9 L -5 -3 L -7 2 L -10 9 M -10 -5 L -10 -4 L -9 -3 L -8 -3 L -5 -5 L -3 -6 L 0 -6 L 2 -5 L 3 -3 L 3 0 L 2 4 L 0 8 L -1 9 L -2 9 L -2 8 L -3 7 L -5 6 M -10 -4 L -8 -4 L -5 -5 M 0 -6 L 2 -4 L 2 0 L 1 4 L 0 6 L -2 8 M 5 -5 L 7 -4 L 9 -2 L 10 0 L 10 2 L 9 1 L 7 2 M 8 -3 L 9 -1 L 9 1 M 5 -10 L 7 -8 M 7 -12 L 9 -10","-14 13 M -4 -12 L -1 -11 L 0 -7 L 1 -4 L 3 0 L 6 4 L 5 5 M -2 -11 L 0 -7 M 3 0 L 5 5 M -6 -7 L -4 -6 L -1 -6 L 2 -7 M -9 -3 L -8 -2 L -5 -1 L 0 -1 L 5 -2 L 8 -3 M 5 -2 L 7 -4 L 8 -3 M 5 5 L 3 4 L 0 3 L -4 3 L -6 4 L -7 5 L -7 7 L -6 8 L -4 9 L -1 10 L 5 10 M -4 9 L 4 9 L 5 10 M 5 -10 L 7 -8 M 7 -12 L 9 -10","-14 13 M 2 -12 L 4 -11 L 4 -10 L -4 -2 M 3 -11 L 2 -9 L -4 -2 L -4 -1 L 1 4 L 3 7 L 4 9 M -4 -1 L 4 6 L 5 8 L 4 9 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 L -4 -3 L -3 -4 L -1 -5 L 8 -5 L 10 -6 M -9 3 L -8 5 L -7 6 M 4 -5 L 8 -6 L 9 -7 L 10 -6 M 4 -12 L 6 -11 L 6 3 L 5 6 L 3 8 L 0 10 M 5 -11 L 6 -8 M 6 0 L 5 4 L 3 7 L 0 10 M 9 -11 L 11 -9 M 11 -13 L 13 -11","-14 13 M -5 -10 L -3 -9 L 0 -8 L 2 -8 L 5 -9 M -3 -9 L 2 -9 L 4 -10 L 5 -9 L -1 -6 M -7 1 L -7 3 L -6 5 L -4 6 L 0 7 L 7 7 M -4 6 L 6 6 L 7 7 M 7 -11 L 9 -9 M 9 -13 L 11 -11","-14 13 M -8 -7 L -7 -6 L -4 -5 L 0 -5 L 4 -6 L 6 -7 L 7 -8 M 4 -6 L 6 -8 L 7 -8 M -2 -12 L -1 -9 L 0 -7 L 3 -3 L 5 0 L 6 2 M -2 -12 L -1 -12 L -1 -10 L 0 -7 M 3 -3 L 6 0 L 7 2 L 7 3 M 7 3 L 6 2 L 4 1 L 0 0 L -4 0 L -7 1 L -8 3 L -8 5 L -7 7 L -5 8 L -1 9 L 3 9 M -8 5 L -7 6 L -5 7 L -1 8 L 4 8 L 3 9 M 8 -11 L 10 -9 M 10 -13 L 12 -11","-14 13 M -6 -12 L -4 -11 L -5 1 L -5 6 L -4 8 M -5 -11 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 L 1 9 L 4 8 L 7 6 L 9 4 M 1 -10 L 3 -8 M 3 -12 L 5 -10","-14 13 M 0 -12 L 2 -11 L 2 1 L 1 3 L -1 4 L -3 3 L -4 1 L -4 0 L -3 -2 L -1 -3 L 1 -2 L 2 0 L 2 4 L 1 8 L -1 10 M 1 -11 L 2 -6 M 2 4 L 1 7 L -1 10 M -10 -8 L -8 -6 L -5 -6 L 4 -7 L 8 -8 L 10 -7 M -9 -7 L -5 -6 M 4 -7 L 10 -7 M 6 -12 L 8 -10 M 9 -13 L 11 -11","-14 13 M -6 -8 L -4 -7 L -4 4 L -3 6 L -2 7 L 0 8 L 8 8 M -5 -7 L -4 -4 M 3 8 L 6 7 L 7 7 L 8 8 M 3 -11 L 5 -10 L 5 2 L 4 4 L 3 3 L 0 1 M 4 -10 L 5 -7 M 5 -1 L 4 2 L 3 3 M -10 -4 L -8 -2 L -6 -2 L -2 -3 L 3 -4 L 7 -5 L 9 -5 L 10 -4 M -9 -3 L -2 -3 M 3 -4 L 10 -4 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -4 -11 L -2 -9 L 4 -11 M -3 -10 L -1 -10 L 4 -11 L 5 -10 M 5 -10 L 2 -7 L -4 -3 L -8 -1 M 4 -11 L 3 -9 L 1 -7 L -4 -3 M -9 -2 L -7 0 L -3 -2 M -8 -1 L -3 -2 L 3 -3 L 8 -4 L 9 -3 M 3 -3 L 9 -3 M 3 -3 L 1 -2 L -1 0 L -2 2 L -2 4 L -1 6 L 0 7 L 3 8 L 7 8 M -1 6 L 2 7 L 6 7 L 7 8 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -4 -12 L -2 -11 L -2 -9 L -4 -3 L -5 0 L -7 5 L -9 9 M -3 -11 L -3 -8 L -4 -3 M -5 0 L -7 4 L -9 7 L -9 9 M -10 -5 L -8 -4 L -5 -4 L -2 -5 L 0 -6 L 2 -7 M 0 -6 L 1 -8 L 2 -7 M 3 -4 L 6 -4 L 9 -3 L 7 -3 L 5 -2 M 6 -4 L 7 -3 M 0 4 L 1 6 L 2 7 L 4 8 L 9 8 M 1 6 L 3 7 L 10 7 L 9 8 M 6 -10 L 8 -8 M 8 -12 L 10 -10","-14 13 M -5 -12 L -3 -11 L -3 -9 L -5 -4 L -6 0 L -6 2 L -5 3 M -4 -11 L -4 -7 M -5 -4 L -5 3 M -10 -8 L -7 -7 L -3 -7 L 1 -8 L 3 -9 M 1 -8 L 2 -10 L 3 -9 M -5 3 L -3 1 L 0 -1 L 3 -2 L 6 -2 L 8 -1 L 9 1 L 9 4 L 8 6 L 5 8 L 1 9 L -3 9 M 6 -2 L 7 -1 L 8 1 L 8 4 L 7 6 L 5 8 M 6 -9 L 8 -7 M 8 -11 L 10 -9","-14 13 M -10 -6 L -8 -4 L -3 -6 L 1 -7 L 5 -7 L 8 -6 L 9 -5 L 10 -3 L 10 0 L 9 2 L 8 3 L 6 4 L 3 5 L -2 6 M -9 -5 L -3 -6 M 5 -7 L 7 -6 L 8 -5 L 9 -3 L 9 0 L 8 2 L 6 4 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -10 -9 L -8 -7 L -6 -7 L -2 -8 L 3 -9 L 7 -10 L 9 -10 L 10 -9 M -9 -8 L -2 -8 M 3 -9 L 10 -9 M 7 -9 L 4 -8 L 1 -6 L -1 -3 L -2 0 L -2 3 L -1 6 L 0 7 L 2 8 L 6 9 L 9 9 M -2 3 L -1 5 L 0 6 L 2 7 L 6 8 L 8 8 L 9 9 M 8 -5 L 10 -3 M 10 -7 L 12 -5","-14 13 M -3 -12 L -1 -11 L -1 -1 M -2 -11 L -2 -5 L -1 -1 M 5 -4 L 7 -2 L -1 -1 M 6 -3 L 2 -2 L -1 -1 L -4 0 L -6 1 L -7 3 L -7 5 L -6 7 L -5 8 L -3 9 L 8 9 M -6 7 L -4 8 L 7 8 L 8 9 M 6 -9 L 8 -7 M 8 -11 L 10 -9","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M 3 -11 L 5 -10 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -10 L 5 -6 M 4 3 L 9 6 L 9 7 M -2 -5 L 0 -4 L 3 -4 L 7 -5 L 9 -6 M 7 -5 L 8 -7 L 9 -6 M 8 -11 L 10 -9 M 10 -13 L 12 -11","-14 13 M -9 -11 L -8 -10 L -6 -9 L -2 -9 M -8 -10 L -3 -10 L -2 -9 M -2 -9 L -5 -7 L -7 -5 L -9 -2 L -10 1 L -10 4 L -9 6 L -8 7 L -6 8 L -3 8 L 0 7 L 2 5 L 3 3 L 4 -1 L 4 -5 L 3 -9 L 4 -9 M -10 3 L -9 5 L -8 6 L -6 7 L -3 7 L 0 6 L 2 4 L 3 2 L 4 -1 M 4 -9 L 6 -6 L 7 -4 L 9 -1 L 10 1 L 8 1 L 7 2 M 3 -9 L 6 -6 M 7 -4 L 8 -1 L 8 1 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -2 -12 L -1 -9 L 1 -8 M -1 -10 L 1 -9 L 2 -9 L 2 -8 M 2 -8 L -1 -7 L -3 -6 L -4 -5 L -4 -3 L -3 -2 L -1 -1 L 1 0 L 2 1 L 3 3 L 3 5 L 2 7 L 0 8 L -2 8 L -5 7 L -7 5 M -1 -1 L 1 1 L 2 3 L 2 5 L 1 7 L 0 8 M -9 7 L -6 4 L -3 2 L 0 1 M 4 1 L 7 2 L 9 4 L 10 6 L 7 6 M -9 7 L -9 6 L -6 4 M 4 1 L 6 2 L 8 4 L 9 6 M 5 -9 L 7 -7 M 7 -11 L 9 -9","-14 13 M -10 -2 L -8 0 L -5 -5 M -9 -1 L -4 -6 L -2 -6 L 3 -1 L 7 2 L 9 3 L 10 4 L 8 4 L 6 5 M 3 -1 L 8 4 M 3 -8 L 5 -6 M 5 -10 L 7 -8","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M -1 -11 L 1 -10 L 3 -10 L 7 -11 M 3 -10 L 5 -11 L 6 -12 L 7 -11 M -2 -3 L 1 -2 L 4 -2 L 7 -3 L 9 -4 M 7 -3 L 8 -5 L 9 -4 M 3 -10 L 5 -9 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -9 L 5 -5 M 4 3 L 9 6 L 9 7 M 9 -9 L 11 -7 M 11 -11 L 13 -9","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M 3 -11 L 5 -10 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -10 L 5 -6 M 4 3 L 9 6 L 9 7 M -2 -5 L 0 -4 L 3 -4 L 7 -5 L 9 -6 M 7 -5 L 8 -7 L 9 -6 M 9 -13 L 8 -12 L 8 -10 L 9 -9 L 11 -9 L 12 -10 L 12 -12 L 11 -13 L 9 -13","-14 13 M -9 -11 L -8 -10 L -6 -9 L -2 -9 M -8 -10 L -3 -10 L -2 -9 M -2 -9 L -5 -7 L -7 -5 L -9 -2 L -10 1 L -10 4 L -9 6 L -8 7 L -6 8 L -3 8 L 0 7 L 2 5 L 3 3 L 4 -1 L 4 -5 L 3 -9 L 4 -9 M -10 3 L -9 5 L -8 6 L -6 7 L -3 7 L 0 6 L 2 4 L 3 2 L 4 -1 M 4 -9 L 6 -6 L 7 -4 L 9 -1 L 10 1 L 8 1 L 7 2 M 3 -9 L 6 -6 M 7 -4 L 8 -1 L 8 1 M 8 -12 L 7 -11 L 7 -9 L 8 -8 L 10 -8 L 11 -9 L 11 -11 L 10 -12 L 8 -12","-14 13 M -2 -12 L -1 -9 L 1 -8 M -1 -10 L 1 -9 L 2 -9 L 2 -8 M 2 -8 L -1 -7 L -3 -6 L -4 -5 L -4 -3 L -3 -2 L -1 -1 L 1 0 L 2 1 L 3 3 L 3 5 L 2 7 L 0 8 L -2 8 L -5 7 L -7 5 M -1 -1 L 1 1 L 2 3 L 2 5 L 1 7 L 0 8 M -9 7 L -6 4 L -3 2 L 0 1 M 4 1 L 7 2 L 9 4 L 10 6 L 7 6 M -9 7 L -9 6 L -6 4 M 4 1 L 6 2 L 8 4 L 9 6 M 6 -11 L 5 -10 L 5 -8 L 6 -7 L 8 -7 L 9 -8 L 9 -10 L 8 -11 L 6 -11","-14 13 M -10 -2 L -8 0 L -5 -5 M -9 -1 L -4 -6 L -2 -6 L 3 -1 L 7 2 L 9 3 L 10 4 L 8 4 L 6 5 M 3 -1 L 8 4 M 4 -10 L 3 -9 L 3 -7 L 4 -6 L 6 -6 L 7 -7 L 7 -9 L 6 -10 L 4 -10","-14 13 M -9 -11 L -7 -10 L -7 -8 L -8 -5 L -9 -1 M -8 -10 L -8 -7 L -9 -1 L -9 3 L -8 7 L -7 8 L -7 6 L -6 2 L -5 -1 M -9 3 L -8 5 L -7 6 M -1 -11 L 1 -10 L 3 -10 L 7 -11 M 3 -10 L 5 -11 L 6 -12 L 7 -11 M -2 -3 L 1 -2 L 4 -2 L 7 -3 L 9 -4 M 7 -3 L 8 -5 L 9 -4 M 3 -10 L 5 -9 L 5 5 L 4 7 L 2 8 L 0 8 L -2 7 L -3 5 L -2 3 L 0 2 L 2 2 L 4 3 L 9 7 M 4 -9 L 5 -5 M 4 3 L 9 6 L 9 7 M 10 -11 L 9 -10 L 9 -8 L 10 -7 L 12 -7 L 13 -8 L 13 -10 L 12 -11 L 10 -11","-14 13 M -10 -11 L -8 -9 L -3 -10 L 3 -11 L 8 -12 L 10 -10 M -9 -10 L -3 -10 M 3 -11 L 9 -11 M 10 -10 L 8 -8 L 4 -5 L 2 -4 M 9 -11 L 7 -8 L 5 -6 L 2 -4 M 0 -5 L 2 -4 L 2 -1 L 1 3 L -1 6 L -4 9 M 0 -5 L 1 -4 L 1 -1 L 0 3 L -2 7","-14 13 M 4 -12 L 6 -10 L 3 -6 L 0 -3 L -4 0 L -7 2 M 5 -11 L 4 -9 L 1 -5 L -3 -1 L -7 2 M 1 -4 L 3 -3 L 3 10 M 1 -4 L 2 -3 L 2 9 L 3 10","-14 13 M -2 -12 L 1 -11 L 1 -9 L 0 -7 M -2 -12 L 0 -11 L 0 -7 M -8 -9 L -7 -7 L -7 -2 L -6 -1 M -6 -7 L -6 -1 M -6 -7 L 7 -7 M -8 -9 L -7 -8 L -3 -7 M 3 -7 L 6 -8 L 8 -6 M 8 -6 L 5 0 L 3 3 L 0 6 L -3 8 L -5 9 M 7 -7 L 6 -4 L 4 0 L 1 4 L -2 7 L -5 9","-14 13 M -1 -7 L 1 -6 L 1 5 M 0 -6 L 0 5 M -8 -8 L -6 -6 L 6 -8 L 8 -7 M -7 -7 L 8 -7 M -10 4 L -8 6 L 8 4 L 10 5 M -9 5 L 10 5","-14 13 M 0 -12 L 3 -11 L 3 7 L 2 9 L 1 7 L -2 5 M 2 -11 L 2 6 L 1 7 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -6 M -9 -5 L -3 -5 M 3 -6 L 10 -6 M 1 -5 L -2 -1 L -6 3 L -10 6 M 2 -5 L 0 -2 L -3 1 L -7 4 L -10 6","-14 13 M -1 -12 L 1 -10 L 0 -7 L -2 -2 L -4 2 L -6 5 L -9 9 M 0 -11 L -1 -8 L -3 -2 L -5 3 L -9 9 M -9 -6 L -7 -4 L -3 -5 L 2 -6 L 6 -7 L 8 -5 M -8 -5 L -3 -5 M 2 -6 L 7 -6 M 8 -5 L 7 1 L 6 5 L 5 7 L 3 9 L 2 8 L 0 7 M 7 -6 L 6 1 L 5 5 L 4 7 L 2 8","-14 13 M -3 -12 L 0 -11 L 2 9 M -1 -11 L 1 10 L 2 9 M -8 -6 L -6 -4 L -2 -5 L 2 -6 L 6 -7 L 8 -6 M -7 -5 L -2 -5 M 2 -6 L 8 -6 M -10 0 L -8 2 L -3 1 L 3 0 L 8 -1 L 10 0 M -9 1 L -3 1 M 3 0 L 10 0","-14 13 M -2 -12 L 0 -10 L -2 -6 L -4 -3 L -6 -1 L -8 1 M -1 -11 L -2 -8 L -4 -4 L -6 -1 M -1 -8 L 1 -7 L 6 -7 M 3 -7 L 5 -8 L 7 -6 M 7 -6 L 4 0 L 1 4 L -2 7 L -5 9 L -7 10 M 6 -7 L 5 -4 L 3 0 L 0 4 L -3 7 L -7 10","-14 13 M -4 -12 L -2 -10 L -4 -6 L -6 -3 L -8 -1 L -10 1 M -3 -11 L -4 -8 L -6 -4 L -8 -1 M -6 -3 L 2 -4 L 7 -5 L 10 -4 M 2 -4 L 10 -4 M 0 -3 L 2 -1 L 0 3 L -2 6 L -4 8 L -6 10 M 1 -2 L 0 1 L -2 5 L -4 8","-14 13 M -8 -8 L -6 -6 L 6 -8 L 8 -6 M -7 -7 L 7 -7 M 8 -6 L 7 -3 L 6 4 M 7 -7 L 6 -2 L 6 4 M -8 4 L -6 6 L 6 4 L 7 5 M -7 5 L 7 5","-14 13 M -6 -9 L -4 -8 L -4 -3 L -5 1 M -5 -8 L -5 1 M 2 -12 L 5 -11 L 5 -6 L 4 -1 L 3 2 L 2 4 L 0 7 L -2 9 M 4 -11 L 4 -6 L 3 -1 L 2 3 L 0 7 M -10 -5 L -8 -3 L -3 -4 L 3 -5 L 8 -6 L 10 -5 M -9 -4 L -3 -4 M 3 -5 L 10 -5","-14 13 M -5 -11 L -3 -10 L -2 -9 L -2 -8 L -3 -8 L -4 -10 L -5 -11 M -10 -4 L -8 -3 L -7 -2 L -7 -1 L -8 -1 L -9 -3 L -10 -4 M -9 6 L -7 8 L -3 6 L 1 3 L 5 -1 L 9 -6 M -8 7 L -3 5 L 1 2 L 9 -6","-14 13 M -8 -9 L -6 -7 L 5 -9 L 7 -7 M -7 -8 L 6 -8 M 7 -7 L 5 -4 L 2 -1 L -1 1 L -3 2 L -8 4 M 6 -8 L 5 -6 L 3 -3 L 1 -1 L -2 1 L -8 4 M 3 1 L 6 3 L 8 5 L 8 6 L 7 6 L 6 4 L 3 1","-14 13 M -3 -11 L 0 -10 L 0 -8 L -1 1 M -1 -10 L -1 4 L 0 6 L 2 7 L 9 7 M 4 7 L 8 6 L 9 7 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -3 M -9 -3 L -3 -3 M 3 -4 L 9 -4 M 10 -3 L 7 -1 L 4 2 M 9 -4 L 4 2","-14 13 M -9 -9 L -7 -8 L -6 -7 L -6 -6 L -7 -6 L -8 -8 L -9 -9 M 6 -10 L 8 -8 L 5 -2 L 2 2 L -1 5 L -4 7 L -6 8 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -6 8","-14 13 M -2 -12 L 0 -10 L -2 -6 L -4 -3 L -6 -1 L -8 1 M -1 -11 L -2 -8 L -4 -4 L -6 -1 M -1 -8 L 1 -7 L 6 -7 M 3 -7 L 5 -8 L 7 -6 M 7 -6 L 4 0 L 1 4 L -2 7 L -5 9 L -7 10 M 6 -7 L 5 -4 L 3 0 L 0 4 L -3 7 L -7 10 M -4 -2 L -1 -1 L 1 0 L 4 2 L 5 3 L 5 4 L 4 4 L 3 2 L 1 0","-14 13 M -6 -8 L -3 -8 L 2 -9 L 6 -11 M -3 -8 L 0 -9 L 2 -10 L 5 -12 L 6 -11 M -2 -8 L 1 -7 L 1 -1 L 0 3 L -2 6 L -5 9 M 0 -7 L 0 -1 L -1 3 L -3 7 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -4 M -9 -3 L -3 -3 M 3 -4 L 10 -4","-14 13 M -9 -9 L -7 -8 L -6 -7 L -6 -6 L -7 -6 L -8 -8 L -9 -9 M -3 -10 L -1 -9 L 0 -8 L 0 -7 L -1 -7 L -2 -9 L -3 -10 M 6 -10 L 8 -8 L 5 -2 L 2 2 L -1 5 L -4 7 L -6 8 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -6 8","-14 13 M -6 -12 L -4 -10 L 5 -12 L 6 -11 M -5 -11 L 6 -11 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -4 M -9 -3 L -3 -3 M 3 -4 L 10 -4 M 1 -3 L 1 -1 L 0 3 L -2 6 L -5 9 M 0 -3 L 0 -1 L -1 3 L -3 7","-14 13 M -5 -12 L -2 -11 L -2 10 M -3 -11 L -3 9 L -2 10 M -2 -3 L 0 -3 L 3 -2 L 4 -1 L 4 0 L 3 0 L 2 -2 L 0 -3","-14 13 M -1 -12 L 2 -11 L 2 -6 L 1 -1 L 0 2 L -1 4 L -3 7 L -5 9 M 1 -11 L 1 -6 L 0 -1 L -1 3 L -3 7 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -4 M -9 -3 L -3 -3 M 3 -4 L 10 -4","-14 13 M -6 -8 L -4 -6 L 5 -8 L 6 -7 M -5 -7 L 6 -7 M -10 4 L -8 6 L 8 4 L 10 5 M -9 5 L 10 5","-14 13 M -8 -9 L -6 -7 L 5 -9 L 7 -7 M -7 -8 L 6 -8 M 7 -7 L 5 -4 L 2 -1 L -1 1 L -3 2 L -8 4 M 6 -8 L 5 -6 L 3 -3 L 1 -1 L -2 1 L -8 4 M -5 -3 L -2 -2 L 2 0 L 5 2 L 7 4 L 7 5 L 6 5 L 4 2 L 2 0","-14 13 M -2 -12 L 0 -11 L 1 -10 L 1 -9 L 0 -9 L -1 -11 L -2 -12 M -8 -6 L -6 -4 L 4 -6 L 6 -4 M -7 -5 L 5 -5 M 6 -4 L 2 0 L -1 2 L -3 3 L -8 5 M 5 -5 L 3 -2 L 1 0 L -2 2 L -8 5 M 0 1 L 1 2 L 1 10 M 0 1 L 0 9 L 1 10 M 6 3 L 8 4 L 9 5 L 9 6 L 8 6 L 7 4 L 6 3","-14 13 M 5 -10 L 7 -8 L 4 -2 L 1 2 L -2 5 L -5 7 L -7 8 M 6 -9 L 5 -6 L 2 -1 L -1 3 L -4 6 L -7 8","-14 13 M -6 -6 L -4 -4 L -5 -1 L -6 1 L -8 3 L -10 4 M -5 -5 L -6 -1 L -8 3 M 4 -6 L 6 -4 L 8 -1 L 10 3 L 10 4 L 9 4 L 8 0 L 6 -4","-14 13 M -9 -11 L -6 -10 L -6 -8 L -7 1 M -7 -10 L -7 4 L -6 6 L -4 7 L 7 7 M -1 7 L 3 6 L 5 6 L 7 7 M -7 0 L -3 -1 L 0 -2 L 6 -4 M 0 -2 L 4 -4 L 6 -4","-14 13 M -8 -11 L -6 -9 L 7 -9 M -7 -10 L -3 -9 M 3 -9 L 6 -10 L 8 -8 M 8 -8 L 5 -2 L 3 1 L 0 4 L -3 6 L -5 7 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -5 7","-14 13 M -11 -1 L -9 1 L -2 -6 L -1 -6 L 9 4 M -10 0 L -8 -1 L -4 -4 M 3 -2 L 8 2 L 10 3 L 9 4","-14 13 M -2 -12 L 1 -11 L 1 7 L 0 9 L -1 7 L -3 6 M 0 -11 L 0 6 L -1 7 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -6 M -9 -5 L -3 -5 M 3 -6 L 10 -6 M -6 1 L -8 4 L -9 5 L -10 5 L -10 4 L -8 3 L -6 1 M 6 1 L 9 3 L 10 4 L 10 5 L 9 5 L 8 3 L 6 1","-14 13 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -5 M -9 -5 L -3 -5 M 3 -6 L 9 -6 M 10 -5 L 8 -3 L 4 0 L 2 1 M 9 -6 L 7 -3 L 5 -1 L 2 1 M -1 0 L 2 2 L 4 4 L 4 5 L 3 5 L 2 3 L -1 0","-14 13 M -2 -12 L 1 -11 L 3 -10 L 4 -9 L 4 -8 L 3 -8 L 1 -10 L -2 -12 M -5 -5 L -2 -4 L 0 -3 L 1 -2 L 1 -1 L 0 -1 L -2 -3 L -5 -5 M -4 4 L 1 6 L 3 7 L 4 8 L 4 9 L 3 9 L 1 7 L -2 5 L -4 4","-14 13 M 0 -9 L 2 -7 L -5 5 M 1 -8 L -5 5 M -10 5 L -8 7 L 7 4 M -9 6 L 7 4 M 4 1 L 6 3 L 8 6 L 9 6 L 9 5 L 7 3 L 4 1","-14 13 M 5 -10 L 7 -8 L 4 -2 L 1 2 L -2 5 L -5 7 L -7 8 M 6 -9 L 5 -6 L 3 -2 L 0 2 L -3 5 L -7 8 M -3 -4 L 1 -2 L 4 0 L 6 2 L 6 3 L 5 3 L 4 1 L 2 -1 L -1 -3","-14 13 M -6 -9 L -4 -7 L 5 -9 L 6 -8 M -5 -8 L 6 -8 M -1 -7 L -1 4 L 0 6 L 2 7 L 9 7 M 0 -7 L 0 -5 L -1 1 M 4 7 L 8 6 L 9 7 M -10 -1 L -8 1 L -3 0 L 3 -1 L 8 -2 L 10 -1 M -9 0 L -3 0 M 3 -1 L 10 -1","-14 13 M -3 -12 L 0 -11 L 2 9 M -1 -11 L 1 10 L 2 9 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -5 M -9 -5 L -3 -5 M 3 -6 L 9 -6 M 10 -5 L 7 -2 L 4 0 L 2 1 M 9 -6 L 8 -4 L 5 -1 L 2 1","-14 13 M 4 -12 L 6 -10 L 3 -6 L 0 -3 L -4 0 L -7 2 M 5 -11 L 4 -9 L 1 -5 L -3 -1 L -7 2 M 1 -4 L 3 -3 L 3 10 M 1 -4 L 2 -3 L 2 9 L 3 10","-14 13 M -9 -8 L -7 -6 L 3 -8 L 5 -6 M -8 -7 L 4 -7 M 5 -6 L 4 -3 L 3 4 M 4 -7 L 3 -2 L 3 4 M -10 4 L -8 6 L 8 4 L 10 5 M -9 5 L 10 5","-14 13 M -1 -7 L 1 -6 L 1 5 M 0 -6 L 0 5 M -8 -8 L -6 -6 L 6 -8 L 8 -7 M -7 -7 L 8 -7 M -10 4 L -8 6 L 8 4 L 10 5 M -9 5 L 10 5","-14 13 M -8 -8 L -6 -6 L 6 -8 L 8 -6 M -7 -7 L 7 -7 M -8 -2 L -6 0 L 6 -2 M -7 -1 L 6 -1 M -8 4 L -6 6 L 6 4 M -7 5 L 6 5 M 8 -6 L 7 -3 L 7 7 M 7 -7 L 6 -2 L 6 7","-14 13 M -6 -12 L -4 -10 L 5 -12 L 6 -11 M -5 -11 L 6 -11 M -8 -5 L -6 -3 L 5 -5 L 7 -3 M -7 -4 L 6 -4 M 7 -3 L 5 0 L 2 3 L -1 5 L -3 6 L -6 7 M 6 -4 L 5 -2 L 3 1 L 1 3 L -2 5 L -6 7","-14 13 M -6 -9 L -4 -8 L -4 -3 L -5 1 M -5 -8 L -5 1 M 2 -12 L 5 -11 L 5 -1 L 4 3 L 2 6 L -1 9 M 4 -11 L 4 -1 L 3 3 L 2 5 L -1 9","-14 13 M -6 -8 L -4 -7 L -4 -4 L -5 0 L -7 3 L -10 6 M -5 -7 L -5 -4 L -6 0 L -7 2 L -10 6 M -1 -9 L 1 -8 L 1 -5 L 0 1 M 0 -8 L 0 4 L 1 6 L 3 6 L 5 5 L 7 3 L 10 -1 M 0 4 L 1 5 L 4 5 L 6 4","-14 13 M -10 -9 L -7 -8 L -7 -5 L -8 1 M -8 -8 L -8 4 L -7 6 L -4 6 L -1 5 L 2 3 L 6 0 L 9 -3 M -8 4 L -7 5 L -4 5 L -1 4 L 3 2 L 6 0","-14 13 M -8 -8 L -6 -6 L 6 -8 L 8 -6 M -7 -7 L 7 -7 M -7 -7 L -7 8 M -6 -6 L -6 6 L -7 8 M 8 -6 L 7 -3 L 6 4 M 7 -7 L 6 -2 L 6 4 M -6 6 L 6 4 L 7 5 M -6 5 L 7 5","-14 13 M -8 -11 L -7 -9 L -7 -4 L -6 -3 M -6 -9 L -6 -3 M -6 -9 L 7 -9 M -8 -11 L -7 -10 L -3 -9 M 3 -9 L 6 -10 L 8 -8 M 8 -8 L 5 -2 L 3 1 L 0 4 L -3 6 L -5 7 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -5 7","-14 13 M -1 -12 L 2 -11 L 2 9 M 1 -11 L 1 10 L 2 9 M -8 -8 L -6 -6 L 6 -8 L 8 -7 M -7 -7 L 8 -7 M -6 -6 L -4 -5 L -4 0 M -5 -5 L -5 0 M -10 -1 L -8 1 L 8 -1 L 10 0 M -9 0 L 10 0","-14 13 M -2 -12 L 1 -11 L 1 -9 L 0 -7 M -2 -12 L 0 -11 L 0 -7 M -8 -9 L -7 -7 L -7 -2 L -6 -1 M -6 -7 L -6 -1 M -6 -7 L 7 -7 M -8 -9 L -7 -8 L -3 -7 M 3 -7 L 6 -8 L 8 -6 M 8 -6 L 5 0 L 3 3 L 0 6 L -3 8 L -5 9 M 7 -7 L 6 -4 L 4 0 L 1 4 L -2 7 L -5 9","-14 13 M -8 -8 L -6 -6 L 6 -8 L 8 -6 M -7 -7 L 7 -7 M 8 -6 L 5 -4 L 1 -1 M 7 -7 L 1 -1 M -1 -2 L 1 -1 L 1 5 M 0 -1 L 0 5 M -10 4 L -8 6 L 8 4 L 10 5 M -9 5 L 10 5","-14 13 M -8 -11 L -6 -9 L 7 -9 M -7 -10 L -3 -9 M 3 -9 L 6 -10 L 8 -8 M -6 -4 L -4 -2 L 4 -3 M -5 -3 L 4 -3 M 8 -8 L 5 -2 L 3 1 L 0 4 L -3 6 L -5 7 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -5 7","-14 13 M -8 -10 L -6 -9 L -5 -8 L -5 -7 L -6 -7 L -7 -9 L -8 -10 M -9 5 L -7 7 L -3 5 L 1 2 L 5 -2 L 9 -7 M -8 6 L -3 4 L 1 1 L 9 -7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -10 7 L -11 8 L -10 9 L -9 8 L -10 7","-14 13 M -1 -12 L 1 -10 L 0 -7 L -2 -2 L -4 2 L -6 5 L -9 9 M 0 -11 L -1 -8 L -3 -2 L -5 3 L -9 9 M -9 -6 L -7 -4 L -3 -5 L 2 -6 L 6 -7 L 8 -5 M -8 -5 L -3 -5 M 2 -6 L 7 -6 M 8 -5 L 7 1 L 6 5 L 5 7 L 3 9 L 2 8 L 0 7 M 7 -6 L 6 1 L 5 5 L 4 7 L 2 8 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -3 -12 L 0 -11 L 2 9 M -1 -11 L 1 10 L 2 9 M -8 -6 L -6 -4 L -2 -5 L 2 -6 L 6 -7 L 8 -6 M -7 -5 L -2 -5 M 2 -6 L 8 -6 M -10 0 L -8 2 L -3 1 L 3 0 L 8 -1 L 10 0 M -9 1 L -3 1 M 3 0 L 10 0 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -2 -12 L 0 -10 L -2 -6 L -4 -3 L -6 -1 L -8 1 M -1 -11 L -2 -8 L -4 -4 L -6 -1 M -1 -8 L 1 -7 L 6 -7 M 3 -7 L 5 -8 L 7 -6 M 7 -6 L 4 0 L 1 4 L -2 7 L -5 9 L -7 10 M 6 -7 L 5 -4 L 3 0 L 0 4 L -3 7 L -7 10 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -4 -12 L -2 -10 L -4 -6 L -6 -3 L -8 -1 L -10 1 M -3 -11 L -4 -8 L -6 -4 L -8 -1 M -6 -3 L 2 -4 L 7 -5 L 10 -4 M 2 -4 L 10 -4 M 0 -3 L 2 -1 L 0 3 L -2 6 L -4 8 L -6 10 M 1 -2 L 0 1 L -2 5 L -4 8 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -8 -8 L -6 -6 L 6 -8 L 8 -6 M -7 -7 L 7 -7 M 8 -6 L 7 -3 L 6 4 M 7 -7 L 6 -2 L 6 4 M -8 4 L -6 6 L 6 4 L 7 5 M -7 5 L 7 5 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -6 -9 L -4 -8 L -4 -3 L -5 1 M -5 -8 L -5 1 M 2 -12 L 5 -11 L 5 -6 L 4 -1 L 3 2 L 2 4 L 0 7 L -2 9 M 4 -11 L 4 -6 L 3 -1 L 2 3 L 0 7 M -10 -5 L -8 -3 L -3 -4 L 3 -5 L 8 -6 L 10 -5 M -9 -4 L -3 -4 M 3 -5 L 10 -5 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -5 -11 L -3 -10 L -2 -9 L -2 -8 L -3 -8 L -4 -10 L -5 -11 M -10 -4 L -8 -3 L -7 -2 L -7 -1 L -8 -1 L -9 -3 L -10 -4 M -9 6 L -7 8 L -3 6 L 1 3 L 5 -1 L 9 -6 M -8 7 L -3 5 L 1 2 L 9 -6 M 4 -10 L 6 -8 M 6 -12 L 8 -10","-14 13 M -8 -9 L -6 -7 L 5 -9 L 7 -7 M -7 -8 L 6 -8 M 7 -7 L 5 -4 L 2 -1 L -1 1 L -3 2 L -8 4 M 6 -8 L 5 -6 L 3 -3 L 1 -1 L -2 1 L -8 4 M 3 1 L 6 3 L 8 5 L 8 6 L 7 6 L 6 4 L 3 1 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -3 -11 L 0 -10 L 0 -8 L -1 1 M -1 -10 L -1 4 L 0 6 L 2 7 L 9 7 M 4 7 L 8 6 L 9 7 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -3 M -9 -3 L -3 -3 M 3 -4 L 9 -4 M 10 -3 L 7 -1 L 4 2 M 9 -4 L 4 2 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -9 -9 L -7 -8 L -6 -7 L -6 -6 L -7 -6 L -8 -8 L -9 -9 M 6 -10 L 8 -8 L 5 -2 L 2 2 L -1 5 L -4 7 L -6 8 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -6 8 M 9 -11 L 11 -9 M 11 -13 L 13 -11","-14 13 M -2 -12 L 0 -10 L -2 -6 L -4 -3 L -6 -1 L -8 1 M -1 -11 L -2 -8 L -4 -4 L -6 -1 M -1 -8 L 1 -7 L 6 -7 M 3 -7 L 5 -8 L 7 -6 M 7 -6 L 4 0 L 1 4 L -2 7 L -5 9 L -7 10 M 6 -7 L 5 -4 L 3 0 L 0 4 L -3 7 L -7 10 M -4 -2 L -1 -1 L 1 0 L 4 2 L 5 3 L 5 4 L 4 4 L 3 2 L 1 0 M 7 -10 L 9 -8 M 9 -12 L 11 -10","-14 13 M -6 -8 L -3 -8 L 2 -9 L 6 -11 M -3 -8 L 0 -9 L 2 -10 L 5 -12 L 6 -11 M -2 -8 L 1 -7 L 1 -1 L 0 3 L -2 6 L -5 9 M 0 -7 L 0 -1 L -1 3 L -3 7 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -4 M -9 -3 L -3 -3 M 3 -4 L 10 -4 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -9 -9 L -7 -8 L -6 -7 L -6 -6 L -7 -6 L -8 -8 L -9 -9 M -3 -10 L -1 -9 L 0 -8 L 0 -7 L -1 -7 L -2 -9 L -3 -10 M 6 -10 L 8 -8 L 5 -2 L 2 2 L -1 5 L -4 7 L -6 8 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -6 8 M 9 -11 L 11 -9 M 11 -13 L 13 -11","-14 13 M -6 -12 L -4 -10 L 5 -12 L 6 -11 M -5 -11 L 6 -11 M -10 -4 L -8 -2 L -3 -3 L 3 -4 L 8 -5 L 10 -4 M -9 -3 L -3 -3 M 3 -4 L 10 -4 M 1 -3 L 1 -1 L 0 3 L -2 6 L -5 9 M 0 -3 L 0 -1 L -1 3 L -3 7 M 8 -10 L 10 -8 M 10 -12 L 12 -10","-14 13 M -5 -12 L -2 -11 L -2 10 M -3 -11 L -3 9 L -2 10 M -2 -3 L 0 -3 L 3 -2 L 4 -1 L 4 0 L 3 0 L 2 -2 L 0 -3 M 2 -10 L 4 -8 M 4 -12 L 6 -10","-14 13 M -6 -6 L -4 -4 L -5 -1 L -6 1 L -8 3 L -10 4 M -5 -5 L -6 -1 L -8 3 M 4 -6 L 6 -4 L 8 -1 L 10 3 L 10 4 L 9 4 L 8 0 L 6 -4 M 7 -9 L 9 -7 M 9 -11 L 11 -9","-14 13 M -9 -11 L -6 -10 L -6 -8 L -7 1 M -7 -10 L -7 4 L -6 6 L -4 7 L 7 7 M -1 7 L 3 6 L 5 6 L 7 7 M -7 0 L -3 -1 L 0 -2 L 6 -4 M 0 -2 L 4 -4 L 6 -4 M 7 -9 L 9 -7 M 9 -11 L 11 -9","-14 13 M -8 -11 L -6 -9 L 7 -9 M -7 -10 L -3 -9 M 3 -9 L 6 -10 L 8 -8 M 8 -8 L 5 -2 L 3 1 L 0 4 L -3 6 L -5 7 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -5 7 M 9 -11 L 11 -9 M 11 -13 L 13 -11","-14 13 M -11 -1 L -9 1 L -2 -6 L -1 -6 L 9 4 M -10 0 L -8 -1 L -4 -4 M 3 -2 L 8 2 L 10 3 L 9 4 M 4 -8 L 6 -6 M 6 -10 L 8 -8","-14 13 M -2 -12 L 1 -11 L 1 7 L 0 9 L -1 7 L -3 6 M 0 -11 L 0 6 L -1 7 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -6 M -9 -5 L -3 -5 M 3 -6 L 10 -6 M -6 1 L -8 4 L -9 5 L -10 5 L -10 4 L -8 3 L -6 1 M 6 1 L 9 3 L 10 4 L 10 5 L 9 5 L 8 3 L 6 1 M 8 -11 L 10 -9 M 10 -13 L 12 -11","-14 13 M -6 -6 L -4 -4 L -5 -1 L -6 1 L -8 3 L -10 4 M -5 -5 L -6 -1 L -8 3 M 4 -6 L 6 -4 L 8 -1 L 10 3 L 10 4 L 9 4 L 8 0 L 6 -4 M 8 -11 L 7 -10 L 7 -8 L 8 -7 L 10 -7 L 11 -8 L 11 -10 L 10 -11 L 8 -11","-14 13 M -9 -11 L -6 -10 L -6 -8 L -7 1 M -7 -10 L -7 4 L -6 6 L -4 7 L 7 7 M -1 7 L 3 6 L 5 6 L 7 7 M -7 0 L -3 -1 L 0 -2 L 6 -4 M 0 -2 L 4 -4 L 6 -4 M 8 -11 L 7 -10 L 7 -8 L 8 -7 L 10 -7 L 11 -8 L 11 -10 L 10 -11 L 8 -11","-14 13 M -8 -11 L -6 -9 L 7 -9 M -7 -10 L -3 -9 M 3 -9 L 6 -10 L 8 -8 M 8 -8 L 5 -2 L 3 1 L 0 4 L -3 6 L -5 7 M 7 -9 L 6 -6 L 4 -2 L 1 2 L -2 5 L -5 7 M 10 -13 L 9 -12 L 9 -10 L 10 -9 L 12 -9 L 13 -10 L 13 -12 L 12 -13 L 10 -13","-14 13 M -11 -1 L -9 1 L -2 -6 L -1 -6 L 9 4 M -10 0 L -8 -1 L -4 -4 M 3 -2 L 8 2 L 10 3 L 9 4 M 5 -10 L 4 -9 L 4 -7 L 5 -6 L 7 -6 L 8 -7 L 8 -9 L 7 -10 L 5 -10","-14 13 M -2 -12 L 1 -11 L 1 7 L 0 9 L -1 7 L -3 6 M 0 -11 L 0 6 L -1 7 M -10 -6 L -8 -4 L -3 -5 L 3 -6 L 8 -7 L 10 -6 M -9 -5 L -3 -5 M 3 -6 L 10 -6 M -6 1 L -8 4 L -9 5 L -10 5 L -10 4 L -8 3 L -6 1 M 6 1 L 9 3 L 10 4 L 10 5 L 9 5 L 8 3 L 6 1 M 9 -13 L 8 -12 L 8 -10 L 9 -9 L 11 -9 L 12 -10 L 12 -12 L 11 -13 L 9 -13"] -markers = ["-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-7 7 M -1 -7 L -4 -6 L -6 -4 L -7 -1 L -7 1 L -6 4 L -4 6 L -1 7 L 1 7 L 4 6 L 6 4 L 7 1 L 7 -1 L 6 -4 L 4 -6 L 1 -7 L -1 -7","-6 6 M -6 -6 L -6 6 L 6 6 L 6 -6 L -6 -6","-7 7 M 0 -8 L -7 4 L 7 4 L 0 -8","-6 6 M 0 -10 L -6 0 L 0 10 L 6 0 L 0 -10","-8 8 M 0 -9 L -2 -3 L -8 -3 L -3 1 L -5 7 L 0 3 L 5 7 L 3 1 L 8 -3 L 2 -3 L 0 -9","-6 6 M -2 -6 L -2 -2 L -6 -2 L -6 2 L -2 2 L -2 6 L 2 6 L 2 2 L 6 2 L 6 -2 L 2 -2 L 2 -6 L -2 -6","-7 7 M 0 -7 L 0 7 M -7 0 L 7 0","-5 5 M -5 -5 L 5 5 M 5 -5 L -5 5","-5 5 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-4 4 M -1 -4 L -3 -3 L -4 -1 L -4 1 L -3 3 L -1 4 L 1 4 L 3 3 L 4 1 L 4 -1 L 3 -3 L 1 -4 L -1 -4 M -3 -1 L -3 1 M -2 -2 L -2 2 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -2 L 2 2 M 3 -1 L 3 1","-4 4 M -4 -4 L -4 4 L 4 4 L 4 -4 L -4 -4 M -3 -3 L -3 3 M -2 -3 L -2 3 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -3 L 2 3 M 3 -3 L 3 3","-5 5 M 0 -6 L -5 3 L 5 3 L 0 -6 M 0 -3 L -3 2 M 0 -3 L 3 2 M 0 0 L -1 2 M 0 0 L 1 2","-6 3 M -6 0 L 3 5 L 3 -5 L -6 0 M -3 0 L 2 3 M -3 0 L 2 -3 M 0 0 L 2 1 M 0 0 L 2 -1","-5 5 M 0 6 L 5 -3 L -5 -3 L 0 6 M 0 3 L 3 -2 M 0 3 L -3 -2 M 0 0 L 1 -2 M 0 0 L -1 -2","-3 6 M 6 0 L -3 -5 L -3 5 L 6 0 M 3 0 L -2 -3 M 3 0 L -2 3 M 0 0 L -2 -1 M 0 0 L -2 1","-14 14 M -14 0 L 14 0 M -14 0 L 0 16 M 14 0 L 0 16","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-7 7 M -1 -7 L -4 -6 L -6 -4 L -7 -1 L -7 1 L -6 4 L -4 6 L -1 7 L 1 7 L 4 6 L 6 4 L 7 1 L 7 -1 L 6 -4 L 4 -6 L 1 -7 L -1 -7","-6 6 M -6 -6 L -6 6 L 6 6 L 6 -6 L -6 -6","-7 7 M 0 -8 L -7 4 L 7 4 L 0 -8","-6 6 M 0 -10 L -6 0 L 0 10 L 6 0 L 0 -10","-8 8 M 0 -9 L -2 -3 L -8 -3 L -3 1 L -5 7 L 0 3 L 5 7 L 3 1 L 8 -3 L 2 -3 L 0 -9","-6 6 M -2 -6 L -2 -2 L -6 -2 L -6 2 L -2 2 L -2 6 L 2 6 L 2 2 L 6 2 L 6 -2 L 2 -2 L 2 -6 L -2 -6","-7 7 M 0 -7 L 0 7 M -7 0 L 7 0","-5 5 M -5 -5 L 5 5 M 5 -5 L -5 5","-5 5 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-4 4 M -1 -4 L -3 -3 L -4 -1 L -4 1 L -3 3 L -1 4 L 1 4 L 3 3 L 4 1 L 4 -1 L 3 -3 L 1 -4 L -1 -4 M -3 -1 L -3 1 M -2 -2 L -2 2 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -2 L 2 2 M 3 -1 L 3 1","-4 4 M -4 -4 L -4 4 L 4 4 L 4 -4 L -4 -4 M -3 -3 L -3 3 M -2 -3 L -2 3 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -3 L 2 3 M 3 -3 L 3 3","-5 5 M 0 -6 L -5 3 L 5 3 L 0 -6 M 0 -3 L -3 2 M 0 -3 L 3 2 M 0 0 L -1 2 M 0 0 L 1 2","-6 3 M -6 0 L 3 5 L 3 -5 L -6 0 M -3 0 L 2 3 M -3 0 L 2 -3 M 0 0 L 2 1 M 0 0 L 2 -1","-5 5 M 0 6 L 5 -3 L -5 -3 L 0 6 M 0 3 L 3 -2 M 0 3 L -3 -2 M 0 0 L 1 -2 M 0 0 L -1 -2","-3 6 M 6 0 L -3 -5 L -3 5 L 6 0 M 3 0 L -2 -3 M 3 0 L -2 3 M 0 0 L -2 -1 M 0 0 L -2 1","-14 14 M -14 0 L 14 0 M -14 0 L 0 16 M 14 0 L 0 16","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8","-8 8"] -mathlow = ["-8 8","-12 12 M 0 -8 L 0 9 M -8 0 L 8 0 M -8 9 L 8 9","-12 12 M 0 -8 L 0 9 M -8 -8 L 8 -8 M -8 0 L 8 0","-11 11 M -7 -7 L 7 7 M 7 -7 L -7 7","-2 3 M 0 -1 L 0 0 L 1 0 L 1 -1 L 0 -1","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 12 M 8 -12 L -8 -5 L 8 2 M -8 4 L 8 4 M -8 9 L 8 9","-12 12 M -8 -12 L 8 -5 L -8 2 M -8 4 L 8 4 M -8 9 L 8 9","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16 M 2 -14 L 0 -10 L -1 -7 L -2 -2 L -2 2 L -1 7 L 0 10 L 2 14","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 M -2 -14 L 0 -10 L 1 -7 L 2 -2 L 2 2 L 1 7 L 0 10 L -2 14","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-17 17 M -10 -16 L -10 16 M -9 -16 L -9 16 M 9 -16 L 9 16 M 10 -16 L 10 16 M -14 -16 L 14 -16 M -14 16 L -5 16 M 5 16 L 14 16","-16 15 M -11 -16 L -1 -2 L -12 16 M -12 -16 L -2 -2 M -13 -16 L -2 -1 M -13 -16 L 10 -16 L 12 -9 L 9 -16 M -11 15 L 10 15 M -12 16 L 10 16 L 12 9 L 9 16","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-13 13 M 7 -9 L -7 9 M -9 -3 L 9 -3 M -9 3 L 9 3","-13 13 M -9 -5 L 9 -5 M -9 0 L 9 0 M -9 5 L 9 5","-9 10 M 6 -5 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-10 9 M -6 -12 L -6 9 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M 6 -12 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 9 M -6 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-5 7 M 5 -12 L 3 -12 L 1 -11 L 0 -8 L 0 9 M -3 -5 L 4 -5","-9 10 M 6 -5 L 6 11 L 5 14 L 4 15 L 2 16 L -1 16 L -3 15 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M -5 -12 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-4 4 M -1 -12 L 0 -11 L 1 -12 L 0 -13 L -1 -12 M 0 -5 L 0 9","-5 5 M 0 -12 L 1 -11 L 2 -12 L 1 -13 L 0 -12 M 1 -5 L 1 12 L 0 15 L -2 16 L -4 16","-9 8 M -5 -12 L -5 9 M 5 -5 L -5 5 M -1 1 L 6 9","-4 4 M 0 -12 L 0 9","-15 15 M -11 -5 L -11 9 M -11 -1 L -8 -4 L -6 -5 L -3 -5 L -1 -4 L 0 -1 L 0 9 M 0 -1 L 3 -4 L 5 -5 L 8 -5 L 10 -4 L 11 -1 L 11 9","-9 10 M -5 -5 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-9 10 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 2 -5 L -1 -5","-10 9 M -6 -5 L -6 16 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 10 M 6 -5 L 6 16 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-7 6 M -3 -5 L -3 9 M -3 1 L -2 -2 L 0 -4 L 2 -5 L 5 -5","-8 9 M 6 -2 L 5 -4 L 2 -5 L -1 -5 L -4 -4 L -5 -2 L -4 0 L -2 1 L 3 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -1 9 L -4 8 L -5 6","-5 7 M 0 -12 L 0 5 L 1 8 L 3 9 L 5 9 M -3 -5 L 4 -5","-9 10 M -5 -5 L -5 5 L -4 8 L -2 9 L 1 9 L 3 8 L 6 5 M 6 -5 L 6 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9","-11 11 M -8 -5 L -4 9 M 0 -5 L -4 9 M 0 -5 L 4 9 M 8 -5 L 4 9","-8 9 M -5 -5 L 6 9 M 6 -5 L -5 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9 L -2 13 L -4 15 L -6 16 L -7 16","-8 9 M 6 -5 L -5 9 M -5 -5 L 6 -5 M -5 9 L 6 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-12 13 M 9 5 L 7 5 L 5 4 L 3 2 L 0 -2 L -1 -3 L -3 -4 L -5 -4 L -7 -3 L -8 -1 L -8 1 L -7 3 L -5 4 L -3 4 L -1 3 L 0 2 L 3 -2 L 5 -4 L 7 -5 L 9 -5","-12 13 M 10 1 L 9 3 L 7 4 L 5 4 L 3 3 L 2 2 L -1 -2 L -2 -3 L -4 -4 L -6 -4 L -8 -3 L -9 -1 L -9 1 L -8 3 L -6 4 L -4 4 L -2 3 L -1 2 L 2 -2 L 3 -3 L 5 -4 L 7 -4 L 9 -3 L 10 -1 L 10 1","-7 7 M -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -4 L 1 -4 L 3 -5 L 4 -7 L 4 -9 L 3 -11 L 1 -12 L -1 -12","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-13 9 M -10 -5 L -6 -5 L 0 7 M -7 -5 L 0 9 M 9 -16 L 0 9","-17 16 M -14 -5 L -9 -5 L 0 7 M -10 -4 L 0 9 M 16 -24 L 0 9","-12 12 M 8 -8 L 1 -8 L -3 -7 L -5 -6 L -7 -4 L -8 -1 L -8 1 L -7 4 L -5 6 L -3 7 L 1 8 L 8 8","-12 12 M -8 -8 L -8 -1 L -7 3 L -6 5 L -4 7 L -1 8 L 1 8 L 4 7 L 6 5 L 7 3 L 8 -1 L 8 -8","-12 12 M -8 -8 L -1 -8 L 3 -7 L 5 -6 L 7 -4 L 8 -1 L 8 1 L 7 4 L 5 6 L 3 7 L -1 8 L -8 8","-12 12 M -8 8 L -8 1 L -7 -3 L -6 -5 L -4 -7 L -1 -8 L 1 -8 L 4 -7 L 6 -5 L 7 -3 L 8 1 L 8 8","-12 12 M 8 -8 L 1 -8 L -3 -7 L -5 -6 L -7 -4 L -8 -1 L -8 1 L -7 4 L -5 6 L -3 7 L 1 8 L 8 8 M -8 0 L 4 0","-13 13 M 6 -2 L 9 0 L 6 2 M 3 -5 L 8 0 L 3 5 M -9 0 L 8 0","-8 8 M -2 -6 L 0 -9 L 2 -6 M -5 -3 L 0 -8 L 5 -3 M 0 -8 L 0 9","-13 13 M -6 -2 L -9 0 L -6 2 M -3 -5 L -8 0 L -3 5 M -8 0 L 9 0","-8 8 M -2 6 L 0 9 L 2 6 M -5 3 L 0 8 L 5 3 M 0 -9 L 0 8","-9 10 M 6 0 L 5 -3 L 4 -4 L 2 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 L 6 3 L 7 -2 L 7 -7 L 6 -10 L 5 -11 L 3 -12 L 0 -12 L -2 -11 L -3 -10 L -3 -9 L -2 -9 L -2 -10 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 6 L 5 3 L 6 -2 L 6 -7 L 5 -10 L 3 -12","-10 10 M -8 -12 L 0 9 M -7 -12 L 0 7 M 8 -12 L 0 9 M -8 -12 L 8 -12 M -7 -11 L 7 -11","-17 16 M -14 -5 L -9 -5 L 0 7 M -10 -4 L 0 9 M 16 -24 L 0 9","-12 12 M 9 -15 L 8 -14 L 9 -13 L 10 -14 L 10 -15 L 9 -16 L 7 -16 L 5 -15 L 3 -13 L 2 -11 L 1 -8 L 0 -4 L -2 8 L -3 12 L -4 14 M 4 -14 L 3 -12 L 2 -8 L 0 4 L -1 8 L -2 11 L -3 13 L -5 15 L -7 16 L -9 16 L -10 15 L -10 14 L -9 13 L -8 14 L -9 15","-15 15 M 11 -36 L 10 -36 L 9 -35 L 9 -34 L 10 -33 L 11 -33 L 12 -34 L 12 -36 L 11 -38 L 9 -39 L 7 -39 L 5 -38 L 3 -36 L 2 -34 L 1 -31 L 0 -24 L -1 -8 L -1 24 L -2 33 L -3 36 M 10 -35 L 10 -34 L 11 -34 L 11 -35 L 10 -35 M 0 -24 L 0 24 M 3 -36 L 2 -33 L 1 -24 L 1 8 L 0 24 L -1 31 L -2 34 L -3 36 L -5 38 L -7 39 L -9 39 L -11 38 L -12 36 L -12 34 L -11 33 L -10 33 L -9 34 L -9 35 L -10 36 L -11 36 M -11 34 L -11 35 L -10 35 L -10 34 L -11 34","-9 9 M 6 -39 L 3 -33 L 0 -26 L -2 -21 L -3 -17 L -4 -12 L -5 -4 L -5 4 L -4 12 L -3 17 L -2 21 L 0 26 L 3 33 L 6 39 M 3 -33 L 1 -28 L -1 -22 L -2 -18 L -3 -12 L -4 -4 L -4 4 L -3 12 L -2 18 L -1 22 L 1 28 L 3 33","-9 9 M -6 -39 L -3 -33 L 0 -26 L 2 -21 L 3 -17 L 4 -12 L 5 -4 L 5 4 L 4 12 L 3 17 L 2 21 L 0 26 L -3 33 L -6 39 M -3 -33 L -1 -28 L 1 -22 L 2 -18 L 3 -12 L 4 -4 L 4 4 L 3 12 L 2 18 L 1 22 L -1 28 L -3 33","-9 9 M -5 -39 L -5 0 L -5 39 M -4 -39 L -4 0 L -4 39 M -5 -39 L 6 -39 M -5 39 L 6 39","-9 9 M 4 -39 L 4 0 L 4 39 M 5 -39 L 5 0 L 5 39 M -6 -39 L 5 -39 M -6 39 L 5 39","-9 10 M 6 -12 L 6 9 M -7 -12 L 6 -12 M -2 -2 L 6 -2 M -7 9 L 6 9","-10 10 M -7 -9 L -6 -7 L 6 5 L 7 7 L 7 9 M -6 -6 L 6 6 M -7 -9 L -7 -7 L -6 -5 L 6 7 L 7 9 M -2 -2 L -6 2 L -7 4 L -7 6 L -6 8 L -7 9 M -7 4 L -5 8 M -6 2 L -6 4 L -5 6 L -5 8 L -7 9 M 1 1 L 6 -4 M 4 -9 L 4 -6 L 5 -4 L 7 -4 L 7 -6 L 5 -7 L 4 -9 M 4 -9 L 5 -6 L 7 -4","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 0 L 9 0 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-7 7 M -3 -16 L -3 16 M 3 -16 L 3 16","-12 12 M 0 -16 L 0 9 M -9 9 L 9 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-12 12 M 9 -16 L -9 9 L 9 9","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 7 L -10 8 L -9 9 L -8 8 L -9 7 M 9 7 L 8 8 L 9 9 L 10 8 L 9 7","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -mathupp = ["-8 8","-12 12 M 0 -8 L 0 9 M -8 0 L 8 0 M -8 9 L 8 9","-12 12 M 0 -8 L 0 9 M -8 -8 L 8 -8 M -8 0 L 8 0","-11 11 M -7 -7 L 7 7 M 7 -7 L -7 7","-2 3 M 0 -1 L 0 0 L 1 0 L 1 -1 L 0 -1","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 12 M 8 -12 L -8 -5 L 8 2 M -8 4 L 8 4 M -8 9 L 8 9","-12 12 M -8 -12 L 8 -5 L -8 2 M -8 4 L 8 4 M -8 9 L 8 9","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16 M 2 -14 L 0 -10 L -1 -7 L -2 -2 L -2 2 L -1 7 L 0 10 L 2 14","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 M -2 -14 L 0 -10 L 1 -7 L 2 -2 L 2 2 L 1 7 L 0 10 L -2 14","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-5 5 M 1 8 L 0 9 L -1 8 L 0 7 L 1 8 L 1 10 L 0 12 L -1 13","-13 13 M -9 0 L 9 0","-5 5 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-17 17 M -10 -16 L -10 16 M -9 -16 L -9 16 M 9 -16 L 9 16 M 10 -16 L 10 16 M -14 -16 L 14 -16 M -14 16 L -5 16 M 5 16 L 14 16","-16 15 M -11 -16 L -1 -2 L -12 16 M -12 -16 L -2 -2 M -13 -16 L -2 -1 M -13 -16 L 10 -16 L 12 -9 L 9 -16 M -11 15 L 10 15 M -12 16 L 10 16 L 12 9 L 9 16","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-13 13 M 7 -9 L -7 9 M -9 -3 L 9 -3 M -9 3 L 9 3","-13 13 M -9 -5 L 9 -5 M -9 0 L 9 0 M -9 5 L 9 5","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9 M -5 2 L 5 2","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 M -7 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -7 9","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4","-11 10 M -7 -12 L -7 9 M -7 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 0 9 L -7 9","-10 9 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2 M -6 9 L 7 9","-10 8 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4 L 8 1 M 3 1 L 8 1","-11 11 M -7 -12 L -7 9 M 7 -12 L 7 9 M -7 -2 L 7 -2","-4 4 M 0 -12 L 0 9","-8 8 M 4 -12 L 4 4 L 3 7 L 2 8 L 0 9 L -2 9 L -4 8 L -5 7 L -6 4 L -6 2","-11 10 M -7 -12 L -7 9 M 7 -12 L -7 2 M -2 -3 L 7 9","-10 7 M -6 -12 L -6 9 M -6 9 L 6 9","-12 12 M -8 -12 L -8 9 M -8 -12 L 0 9 M 8 -12 L 0 9 M 8 -12 L 8 9","-11 11 M -7 -12 L -7 9 M -7 -12 L 7 9 M 7 -12 L 7 9","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 L -7 -1","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M 1 5 L 7 11","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 L -7 -2 M 0 -2 L 7 9","-10 10 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-8 8 M 0 -12 L 0 9 M -7 -12 L 7 -12","-11 11 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -12","-9 9 M -8 -12 L 0 9 M 8 -12 L 0 9","-12 12 M -10 -12 L -5 9 M 0 -12 L -5 9 M 0 -12 L 5 9 M 10 -12 L 5 9","-10 10 M -7 -12 L 7 9 M 7 -12 L -7 9","-9 9 M -8 -12 L 0 -2 L 0 9 M 8 -12 L 0 -2","-10 10 M 7 -12 L -7 9 M -7 -12 L 7 -12 M -7 9 L 7 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-12 13 M 9 5 L 7 5 L 5 4 L 3 2 L 0 -2 L -1 -3 L -3 -4 L -5 -4 L -7 -3 L -8 -1 L -8 1 L -7 3 L -5 4 L -3 4 L -1 3 L 0 2 L 3 -2 L 5 -4 L 7 -5 L 9 -5","-12 13 M 10 1 L 9 3 L 7 4 L 5 4 L 3 3 L 2 2 L -1 -2 L -2 -3 L -4 -4 L -6 -4 L -8 -3 L -9 -1 L -9 1 L -8 3 L -6 4 L -4 4 L -2 3 L -1 2 L 2 -2 L 3 -3 L 5 -4 L 7 -4 L 9 -3 L 10 -1 L 10 1","-7 7 M -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -4 L 1 -4 L 3 -5 L 4 -7 L 4 -9 L 3 -11 L 1 -12 L -1 -12","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 9 M -10 -5 L -6 -5 L 0 7 M -7 -5 L 0 9 M 9 -16 L 0 9","-17 16 M -14 -5 L -9 -5 L 0 7 M -10 -4 L 0 9 M 16 -24 L 0 9","-12 12 M 8 -8 L 1 -8 L -3 -7 L -5 -6 L -7 -4 L -8 -1 L -8 1 L -7 4 L -5 6 L -3 7 L 1 8 L 8 8","-12 12 M -8 -8 L -8 -1 L -7 3 L -6 5 L -4 7 L -1 8 L 1 8 L 4 7 L 6 5 L 7 3 L 8 -1 L 8 -8","-12 12 M -8 -8 L -1 -8 L 3 -7 L 5 -6 L 7 -4 L 8 -1 L 8 1 L 7 4 L 5 6 L 3 7 L -1 8 L -8 8","-12 12 M -8 8 L -8 1 L -7 -3 L -6 -5 L -4 -7 L -1 -8 L 1 -8 L 4 -7 L 6 -5 L 7 -3 L 8 1 L 8 8","-12 12 M 8 -8 L 1 -8 L -3 -7 L -5 -6 L -7 -4 L -8 -1 L -8 1 L -7 4 L -5 6 L -3 7 L 1 8 L 8 8 M -8 0 L 4 0","-13 13 M 6 -2 L 9 0 L 6 2 M 3 -5 L 8 0 L 3 5 M -9 0 L 8 0","-8 8 M -2 -6 L 0 -9 L 2 -6 M -5 -3 L 0 -8 L 5 -3 M 0 -8 L 0 9","-13 13 M -6 -2 L -9 0 L -6 2 M -3 -5 L -8 0 L -3 5 M -8 0 L 9 0","-8 8 M -2 6 L 0 9 L 2 6 M -5 3 L 0 8 L 5 3 M 0 -9 L 0 8","-9 10 M 6 0 L 5 -3 L 4 -4 L 2 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 L 6 3 L 7 -2 L 7 -7 L 6 -10 L 5 -11 L 3 -12 L 0 -12 L -2 -11 L -3 -10 L -3 -9 L -2 -9 L -2 -10 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 6 L 5 3 L 6 -2 L 6 -7 L 5 -10 L 3 -12","-10 10 M -8 -12 L 0 9 M -7 -12 L 0 7 M 8 -12 L 0 9 M -8 -12 L 8 -12 M -7 -11 L 7 -11","-17 16 M -14 -5 L -9 -5 L 0 7 M -10 -4 L 0 9 M 16 -24 L 0 9","-12 12 M 9 -15 L 8 -14 L 9 -13 L 10 -14 L 10 -15 L 9 -16 L 7 -16 L 5 -15 L 3 -13 L 2 -11 L 1 -8 L 0 -4 L -2 8 L -3 12 L -4 14 M 4 -14 L 3 -12 L 2 -8 L 0 4 L -1 8 L -2 11 L -3 13 L -5 15 L -7 16 L -9 16 L -10 15 L -10 14 L -9 13 L -8 14 L -9 15","-15 15 M 11 -36 L 10 -36 L 9 -35 L 9 -34 L 10 -33 L 11 -33 L 12 -34 L 12 -36 L 11 -38 L 9 -39 L 7 -39 L 5 -38 L 3 -36 L 2 -34 L 1 -31 L 0 -24 L -1 -8 L -1 24 L -2 33 L -3 36 M 10 -35 L 10 -34 L 11 -34 L 11 -35 L 10 -35 M 0 -24 L 0 24 M 3 -36 L 2 -33 L 1 -24 L 1 8 L 0 24 L -1 31 L -2 34 L -3 36 L -5 38 L -7 39 L -9 39 L -11 38 L -12 36 L -12 34 L -11 33 L -10 33 L -9 34 L -9 35 L -10 36 L -11 36 M -11 34 L -11 35 L -10 35 L -10 34 L -11 34","-9 9 M 6 -39 L 3 -33 L 0 -26 L -2 -21 L -3 -17 L -4 -12 L -5 -4 L -5 4 L -4 12 L -3 17 L -2 21 L 0 26 L 3 33 L 6 39 M 3 -33 L 1 -28 L -1 -22 L -2 -18 L -3 -12 L -4 -4 L -4 4 L -3 12 L -2 18 L -1 22 L 1 28 L 3 33","-9 9 M -6 -39 L -3 -33 L 0 -26 L 2 -21 L 3 -17 L 4 -12 L 5 -4 L 5 4 L 4 12 L 3 17 L 2 21 L 0 26 L -3 33 L -6 39 M -3 -33 L -1 -28 L 1 -22 L 2 -18 L 3 -12 L 4 -4 L 4 4 L 3 12 L 2 18 L 1 22 L -1 28 L -3 33","-9 9 M -5 -39 L -5 0 L -5 39 M -4 -39 L -4 0 L -4 39 M -5 -39 L 6 -39 M -5 39 L 6 39","-9 9 M 4 -39 L 4 0 L 4 39 M 5 -39 L 5 0 L 5 39 M -6 -39 L 5 -39 M -6 39 L 5 39","-9 10 M 6 -12 L 6 9 M -7 -12 L 6 -12 M -2 -2 L 6 -2 M -7 9 L 6 9","-10 10 M -7 -9 L -6 -7 L 6 5 L 7 7 L 7 9 M -6 -6 L 6 6 M -7 -9 L -7 -7 L -6 -5 L 6 7 L 7 9 M -2 -2 L -6 2 L -7 4 L -7 6 L -6 8 L -7 9 M -7 4 L -5 8 M -6 2 L -6 4 L -5 6 L -5 8 L -7 9 M 1 1 L 6 -4 M 4 -9 L 4 -6 L 5 -4 L 7 -4 L 7 -6 L 5 -7 L 4 -9 M 4 -9 L 5 -6 L 7 -4","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 0 L 9 0 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-7 7 M -3 -16 L -3 16 M 3 -16 L 3 16","-12 12 M 0 -16 L 0 9 M -9 9 L 9 9","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-12 12 M 9 -16 L -9 9 L 9 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 7 L -10 8 L -9 9 L -8 8 L -9 7 M 9 7 L 8 8 L 9 9 L 10 8 L 9 7","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -meteorology = ["-8 8","-2 1 M 1 0 L 0 1 L -1 1 L -2 0 L -2 -1 L -1 -2 L 0 -2 L 1 -1 L 1 1 L 0 3 L -1 4 M -1 -1 L -1 0 L 0 0 L 0 -1 L -1 -1","-2 2 M -1 -2 L -2 -1 L -2 1 L -1 2 L 1 2 L 2 1 L 2 -1 L 1 -2 L -1 -2 M 0 -1 L -1 0 L 0 1 L 1 0 L 0 -1","-4 4 M -2 -3 L 2 3 M 2 -3 L -2 3 M -4 0 L 4 0","-5 5 M 0 -7 L -1 -5 L -3 -2 L -5 0 M 0 -7 L 1 -5 L 3 -2 L 5 0 M 0 -5 L -3 -1 M 0 -5 L 3 -1 M 0 -3 L -2 -1 M 0 -3 L 2 -1 M -1 -1 L 1 -1 M -5 0 L 5 0","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-5 5 M -5 0 L -5 -1 L -4 -3 L -3 -4 L -1 -5 L 1 -5 L 3 -4 L 4 -3 L 5 -1 L 5 0 M -2 -4 L 2 -4 M -3 -3 L 3 -3 M -4 -2 L 4 -2 M -4 -1 L 4 -1 M -5 0 L 5 0","-6 0 M -6 -12 L -6 0 L 0 0 L -6 -12 M -6 -9 L -2 -1 M -6 -6 L -3 0 M -6 -3 L -5 -1","-5 5 M 0 -7 L -1 -5 L -3 -2 L -5 0 M 0 -7 L 1 -5 L 3 -2 L 5 0","-5 5 M 5 0 L 5 -1 L 4 -3 L 3 -4 L 1 -5 L -1 -5 L -3 -4 L -4 -3 L -5 -1 L -5 0","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-11 11 M 11 0 L 11 -2 L 10 -5 L 8 -8 L 5 -10 L 2 -11 L -2 -11 L -5 -10 L -8 -8 L -10 -5 L -11 -2 L -11 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9","-10 10 M -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 3 -1 L -7 9 L 7 9","-10 10 M -5 -12 L 6 -12 L 0 -4 L 3 -4 L 5 -3 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 3 -12 L -7 2 L 8 2 M 3 -12 L 3 9","-10 10 M 5 -12 L -5 -12 L -6 -3 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5","-10 10 M 6 -9 L 5 -11 L 2 -12 L 0 -12 L -3 -11 L -5 -8 L -6 -3 L -6 2 L -5 6 L -3 8 L 0 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2","-10 10 M 7 -12 L -3 9 M -7 -12 L 7 -12","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 1 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 2 L -6 0 L -4 -2 L -1 -3 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 2 -12 L -2 -12","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -5 L 6 0 L 5 5 L 3 8 L 0 9 L -2 9 L -5 8 L -6 6","-5 5 M -5 0 L -5 1 L -4 3 L -3 4 L -1 5 L 1 5 L 3 4 L 4 3 L 5 1 L 5 0","-6 6 M -6 -2 L -4 0 L -1 1 L 1 1 L 4 0 L 6 -2","0 3 M 0 3 L 2 2 L 3 0 L 2 -2 L 0 -3","0 4 M 0 0 L 3 -2 L 4 -4 L 4 -6 L 3 -7 L 2 -7","-4 0 M 0 0 L -3 -2 L -4 -4 L -4 -6 L -3 -7 L -2 -7","-9 9 M -5 -8 L -4 -7 L -5 -6 L -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 1 -12 L 3 -11 L 4 -10 L 5 -8 L 5 -6 L 4 -4 L 2 -2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-9 9 M 0 -12 L -8 9 M 0 -12 L 8 9 M -5 2 L 5 2","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 M -7 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -7 9","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4","-11 10 M -7 -12 L -7 9 M -7 -12 L 0 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 0 9 L -7 9","-10 9 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2 M -6 9 L 7 9","-10 8 M -6 -12 L -6 9 M -6 -12 L 7 -12 M -6 -2 L 2 -2","-10 11 M 8 -7 L 7 -9 L 5 -11 L 3 -12 L -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 L 3 9 L 5 8 L 7 6 L 8 4 L 8 1 M 3 1 L 8 1","-11 11 M -7 -12 L -7 9 M 7 -12 L 7 9 M -7 -2 L 7 -2","-4 4 M 0 -12 L 0 9","-8 8 M 4 -12 L 4 4 L 3 7 L 2 8 L 0 9 L -2 9 L -4 8 L -5 7 L -6 4 L -6 2","-11 10 M -7 -12 L -7 9 M 7 -12 L -7 2 M -2 -3 L 7 9","-10 7 M -6 -12 L -6 9 M -6 9 L 6 9","-12 12 M -8 -12 L -8 9 M -8 -12 L 0 9 M 8 -12 L 0 9 M 8 -12 L 8 9","-11 11 M -7 -12 L -7 9 M -7 -12 L 7 9 M 7 -12 L 7 9","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 2 -1 L -7 -1","-11 11 M -2 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -2 9 L 2 9 L 4 8 L 6 6 L 7 4 L 8 1 L 8 -4 L 7 -7 L 6 -9 L 4 -11 L 2 -12 L -2 -12 M 1 5 L 7 11","-11 10 M -7 -12 L -7 9 M -7 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 2 -2 L -7 -2 M 0 -2 L 7 9","-10 10 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-8 8 M 0 -12 L 0 9 M -7 -12 L 7 -12","-11 11 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -12","-9 9 M -8 -12 L 0 9 M 8 -12 L 0 9","-12 12 M -10 -12 L -5 9 M 0 -12 L -5 9 M 0 -12 L 5 9 M 10 -12 L 5 9","-10 10 M -7 -12 L 7 9 M 7 -12 L -7 9","-9 9 M -8 -12 L 0 -2 L 0 9 M 8 -12 L 0 -2","-10 10 M 7 -12 L -7 9 M -7 -12 L 7 -12 M -7 9 L 7 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-10 10 M 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 1 L 7 3 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6","-11 11 M 0 0 L 2 3 L 3 4 L 5 5 L 7 5 L 9 4 L 10 3 L 11 1 L 11 -1 L 10 -3 L 9 -4 L 7 -5 L 5 -5 L 3 -4 L 2 -3 L -2 3 L -3 4 L -5 5 L -7 5 L -9 4 L -10 3 L -11 1 L -11 -1 L -10 -3 L -9 -4 L -7 -5 L -5 -5 L -3 -4 L -2 -3 L 0 0","-11 11 M -9 5 L -10 4 L -11 2 L -11 -1 L -10 -3 L -9 -4 L -7 -5 L -5 -5 L -3 -4 L -2 -3 L 2 3 L 3 4 L 5 5 L 7 5 L 9 4 L 10 3 L 11 1 L 11 -2 L 10 -4 L 9 -5","-9 10 M 6 -5 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-10 9 M -6 -12 L -6 9 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M 6 -12 L 6 9 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 9 M -6 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-5 7 M 5 -12 L 3 -12 L 1 -11 L 0 -8 L 0 9 M -3 -5 L 4 -5","-9 10 M 6 -5 L 6 11 L 5 14 L 4 15 L 2 16 L -1 16 L -3 15 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-9 10 M -5 -12 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-4 4 M -1 -12 L 0 -11 L 1 -12 L 0 -13 L -1 -12 M 0 -5 L 0 9","-5 5 M 0 -12 L 1 -11 L 2 -12 L 1 -13 L 0 -12 M 1 -5 L 1 12 L 0 15 L -2 16 L -4 16","-9 8 M -5 -12 L -5 9 M 5 -5 L -5 5 M -1 1 L 6 9","-4 4 M 0 -12 L 0 9","-15 15 M -11 -5 L -11 9 M -11 -1 L -8 -4 L -6 -5 L -3 -5 L -1 -4 L 0 -1 L 0 9 M 0 -1 L 3 -4 L 5 -5 L 8 -5 L 10 -4 L 11 -1 L 11 9","-9 10 M -5 -5 L -5 9 M -5 -1 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -1 L 6 9","-9 10 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 2 -5 L -1 -5","-10 9 M -6 -5 L -6 16 M -6 -2 L -4 -4 L -2 -5 L 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 L -2 9 L -4 8 L -6 6","-9 10 M 6 -5 L 6 16 M 6 -2 L 4 -4 L 2 -5 L -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 L 2 9 L 4 8 L 6 6","-7 6 M -3 -5 L -3 9 M -3 1 L -2 -2 L 0 -4 L 2 -5 L 5 -5","-8 9 M 6 -2 L 5 -4 L 2 -5 L -1 -5 L -4 -4 L -5 -2 L -4 0 L -2 1 L 3 2 L 5 3 L 6 5 L 6 6 L 5 8 L 2 9 L -1 9 L -4 8 L -5 6","-5 7 M 0 -12 L 0 5 L 1 8 L 3 9 L 5 9 M -3 -5 L 4 -5","-9 10 M -5 -5 L -5 5 L -4 8 L -2 9 L 1 9 L 3 8 L 6 5 M 6 -5 L 6 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9","-11 11 M -8 -5 L -4 9 M 0 -5 L -4 9 M 0 -5 L 4 9 M 8 -5 L 4 9","-8 9 M -5 -5 L 6 9 M 6 -5 L -5 9","-8 8 M -6 -5 L 0 9 M 6 -5 L 0 9 L -2 13 L -4 15 L -6 16 L -7 16","-8 9 M 6 -5 L -5 9 M -5 -5 L 6 -5 M -5 9 L 6 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-10 10 M -7 -12 L -7 9 M -10 -12 L 9 -12 L -1 -2 L 9 8 M 8 4 L 9 7 L 10 9 M 8 4 L 8 7 M 5 7 L 8 7 M 5 7 L 8 8 L 10 9","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-7 7 M 3 -17 L 0 -16 L -2 -15 L -4 -13 L -6 -10 L -7 -6 L -7 0 L -6 3 L -4 5 L -1 6 L 1 6 L 4 5 L 6 3 L 7 0 M -7 -2 L -6 -5 L -4 -7 L -1 -8 L 1 -8 L 4 -7 L 6 -5 L 7 -2 L 7 4 L 6 8 L 4 11 L 2 13 L 0 14 L -3 15","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -music = ["-8 8","-5 5 M 0 -12 L -1 -10 L 0 2 L 1 -10 L 0 -12 M 0 -10 L 0 -4 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -5 -2 L -1 0 L 2 2 L 4 4 L 5 7 L 5 9 L 4 11 L 3 12 M -5 -1 L 1 2 M -5 0 L -2 1 L 2 3 L 4 5 L 5 7","-8 8 M 5 -7 L 4 -5 L 2 -3 L -2 -1 L -5 0 M 1 -2 L -5 1 M 3 -12 L 4 -11 L 5 -9 L 5 -7 L 4 -4 L 2 -2 L -1 0 L -5 2","-10 10 M 1 -5 L -3 -4 L -6 -2 L -7 0 L -7 2 L -6 4 L -4 5 L -1 5 L 3 4 L 6 2 L 7 0 L 7 -2 L 6 -4 L 4 -5 L 1 -5 M 6 -4 L 1 -5 M 4 -5 L -1 -4 L -6 -2 M -3 -4 L -7 0 M -6 4 L -1 5 M -4 5 L 1 4 L 6 2 M 3 4 L 7 0","-10 10 M 1 -5 L -3 -4 L -6 -2 L -7 0 L -7 2 L -6 4 L -4 5 L -1 5 L 3 4 L 6 2 L 7 0 L 7 -2 L 6 -4 L 4 -5 L 1 -5 M 6 -4 L 1 -5 M 4 -5 L -1 -4 L -6 -2 M -3 -4 L -7 0 M -6 4 L -1 5 M -4 5 L 1 4 L 6 2 M 3 4 L 7 0","-8 9 M 1 -5 L -2 -4 L -4 -2 L -5 0 L -5 2 L -4 4 L -2 5 L 0 5 L 3 4 L 5 2 L 6 0 L 6 -2 L 5 -4 L 3 -5 L 1 -5 M -3 -2 L 3 -5 M -4 0 L 4 -4 M -5 2 L 5 -3 M -4 3 L 6 -2 M -3 4 L 5 0 M -2 5 L 4 2","-8 8 M -3 -11 L -3 12 M 3 -12 L 3 11 M -5 -4 L 5 -6 M -5 -3 L 5 -5 M -5 5 L 5 3 M -5 6 L 5 4","-8 8 M -4 -12 L -4 6 M 4 -6 L 4 12 M -4 -4 L 4 -6 M -4 -3 L 4 -5 M -4 5 L 4 3 M -4 6 L 4 4","-8 8 M -4 -16 L -4 5 M -4 -4 L -1 -6 L 2 -6 L 4 -5 L 5 -3 L 5 -1 L 4 1 L 1 3 L -1 4 L -4 5 M -4 -4 L -1 -5 L 2 -5 L 4 -4 M 3 -5 L 4 -3 L 4 -1 L 3 1 L 1 3","-13 13 M -10 -9 L -10 -6 M 10 -9 L 10 -6 M -10 -9 L 10 -9 M -10 -8 L 10 -8 M -10 -7 L 10 -7 M -10 -6 L 10 -6","-8 8 M -5 -4 L -5 -1 M 5 -4 L 5 -1 M -5 -4 L 5 -4 M -5 -3 L 5 -3 M -5 -2 L 5 -2 M -5 -1 L 5 -1","-8 8 M -5 -6 L 5 6 M -5 -6 L -3 -4 L -1 -3 L 2 -3 L 4 -4 L 5 -5 L 5 -7 L 3 -7 L 3 -5 L 2 -3 M -3 -4 L 2 -3 M -1 -3 L 5 -5 M 4 -7 L 4 -4 M 3 -6 L 5 -6 M 5 6 L 3 4 L 1 3 L -2 3 L -4 4 L -5 5 L -5 7 L -3 7 L -3 5 L -2 3 M 3 4 L -2 3 M 1 3 L -5 5 M -4 4 L -4 7 M -5 6 L -3 6","-8 8 M -2 -3 L -3 -5 L -3 -7 L -5 -7 L -5 -5 L -4 -4 L -2 -3 L 1 -3 L 3 -4 L 5 -6 M -4 -7 L -4 -4 M -5 -6 L -3 -6 M -5 -5 L 1 -3 M -2 -3 L 3 -4 M 5 -6 L 5 7","-8 8 M -1 -15 L 4 -5 L 0 2 L 0 3 M 3 -6 L -1 1 M 2 -9 L 2 -7 L -2 0 L 0 3 L 3 7 M 5 10 L 3 7 L 1 6 L -1 6 L -3 7 L -4 9 L -4 11 L -3 13 L 0 15 M 5 10 L 3 8 L 1 7 L -3 7 L -3 11 L -2 13 L 0 15 M 1 6 L -2 8 L -4 11","-13 20 M -4 1 L -3 3 L -1 4 L 1 4 L 3 3 L 4 1 L 4 -1 L 3 -3 L 1 -4 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 4 L -4 7 L -2 9 L 1 10 L 4 10 L 7 9 L 9 7 L 10 5 L 11 2 L 11 -2 L 10 -5 L 8 -8 L 6 -9 L 3 -10 L 0 -10 L -3 -9 L -5 -8 L -7 -6 L -9 -3 L -10 1 L -10 6 L -9 11 L -7 15 L -5 17 L -2 19 L 2 20 L 7 20 L 11 19 L 14 17 L 16 15 M -7 -6 L -8 -4 L -9 0 L -9 6 L -8 10 L -6 14 L -4 16 L -1 18 L 3 19 L 7 19 L 11 18 L 13 17 L 16 15 M -2 -3 L 2 -3 M -3 -2 L 3 -2 M -4 -1 L 4 -1 M -4 0 L 4 0 M -4 1 L 4 1 M -3 2 L 3 2 M -2 3 L 2 3 M 15 -6 L 15 -4 L 17 -4 L 17 -6 L 15 -6 M 16 -6 L 16 -4 M 15 -5 L 17 -5 M 15 4 L 15 6 L 17 6 L 17 4 L 15 4 M 16 4 L 16 6 M 15 5 L 17 5","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -4 -10 L -5 -8 L -6 -3 L -6 0 L -5 5 L -4 7 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 5 L 6 0 L 6 -3 L 5 -8 L 4 -10 L 3 -11 L 1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9 M 0 -11 L 0 9 M -4 9 L 5 9","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 3 -2 L -2 0 L -4 1 L -6 3 L -7 6 L -7 9 M 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 2 -2 L -2 0 M -7 7 L -6 6 L -4 6 L 1 8 L 4 8 L 6 7 L 7 6 M -4 6 L 1 9 L 5 9 L 6 8 L 7 6 L 7 4","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 L -1 -3 M 2 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -4 L 2 -3 M 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 5 -1 L 6 2 L 6 5 L 5 7 L 4 8 L 2 9","-10 10 M 2 -10 L 2 9 M 3 -12 L 3 9 M 3 -12 L -8 3 L 8 3 M -1 9 L 6 9","-10 10 M -5 -12 L -7 -2 M -7 -2 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -5 -12 L 5 -12 M -5 -11 L 0 -11 L 5 -12","-10 10 M 5 -9 L 4 -8 L 5 -7 L 6 -8 L 6 -9 L 5 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2 M 0 -12 L -2 -11 L -4 -9 L -5 -7 L -6 -3 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 2 L 5 -1 L 3 -3 L 1 -4","-10 10 M -7 -12 L -7 -6 M -7 -8 L -6 -10 L -4 -12 L -2 -12 L 3 -9 L 5 -9 L 6 -10 L 7 -12 M -6 -10 L -4 -11 L -2 -11 L 3 -9 M 7 -12 L 7 -9 L 6 -6 L 2 -1 L 1 1 L 0 4 L 0 9 M 6 -6 L 1 -1 L 0 1 L -1 4 L -1 9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 6 -6 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -2 -12 L -4 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -3 M 2 -3 L 4 -4 L 5 -6 L 5 -9 L 4 -11 L 2 -12 M -2 -3 L -5 -2 L -6 -1 L -7 1 L -7 5 L -6 7 L -5 8 L -2 9 L 2 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 2 -3 M -2 -3 L -4 -2 L -5 -1 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 M 2 9 L 4 8 L 5 7 L 6 5 L 6 1 L 5 -1 L 4 -2 L 2 -3","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 0 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 5 L -5 6 M -1 1 L -3 0 L -5 -2 L -6 -5 L -6 -6 L -5 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 5 -9 L 6 -6 L 6 0 L 5 4 L 4 6 L 2 8 L 0 9","-5 5 M 0 -5 L -1 -4 L 0 -3 L 1 -4 L 0 -5 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-17 12 M -11 20 L -10 20 L -9 19 L -9 18 L -10 17 L -11 17 L -12 18 L -12 20 L -11 22 L -9 23 L -7 23 L -4 22 L -2 20 L -1 18 L 0 14 L 0 3 L -1 -23 L -1 -30 L 0 -35 L 1 -37 L 3 -38 L 4 -38 L 6 -37 L 7 -35 L 7 -31 L 6 -28 L 5 -26 L 3 -23 L -2 -19 L -8 -15 L -10 -13 L -12 -10 L -13 -8 L -14 -4 L -14 0 L -13 4 L -11 7 L -8 9 L -4 10 L 0 10 L 4 9 L 6 8 L 8 5 L 9 2 L 9 -2 L 8 -5 L 7 -7 L 5 -9 L 2 -10 L -2 -10 L -5 -9 L -7 -7 L -8 -4 L -8 0 L -7 3 L -5 5 M -11 18 L -11 19 L -10 19 L -10 18 L -11 18 M 3 -23 L -1 -19 L -6 -15 L -9 -12 L -11 -9 L -12 -7 L -13 -4 L -13 0 L -12 4 L -11 6 L -8 9 M 0 10 L 3 9 L 5 8 L 7 5 L 8 2 L 8 -2 L 7 -5 L 6 -7 L 4 -9 L 2 -10","-13 20 M -4 1 L -3 3 L -1 4 L 1 4 L 3 3 L 4 1 L 4 -1 L 3 -3 L 1 -4 L -1 -4 L -3 -3 L -4 -2 L -5 1 L -5 4 L -4 7 L -2 9 L 1 10 L 4 10 L 7 9 L 9 7 L 10 5 L 11 2 L 11 -2 L 10 -5 L 8 -8 L 6 -9 L 3 -10 L 0 -10 L -3 -9 L -5 -8 L -7 -6 L -9 -3 L -10 1 L -10 6 L -9 11 L -7 15 L -5 17 L -2 19 L 2 20 L 7 20 L 11 19 L 14 17 L 16 15 M -7 -6 L -8 -4 L -9 0 L -9 6 L -8 10 L -6 14 L -4 16 L -1 18 L 3 19 L 7 19 L 11 18 L 13 17 L 16 15 M -2 -3 L 2 -3 M -3 -2 L 3 -2 M -4 -1 L 4 -1 M -4 0 L 4 0 M -4 1 L 4 1 M -3 2 L 3 2 M -2 3 L 2 3 M 15 -6 L 15 -4 L 17 -4 L 17 -6 L 15 -6 M 16 -6 L 16 -4 M 15 -5 L 17 -5 M 15 4 L 15 6 L 17 6 L 17 4 L 15 4 M 16 4 L 16 6 M 15 5 L 17 5","-9 24 M -4 -1 L -3 -3 L -1 -4 L 1 -4 L 3 -3 L 4 -1 L 4 1 L 3 3 L 1 4 L -1 4 L -3 3 L -4 2 L -5 -1 L -5 -4 L -4 -7 L -2 -9 L 1 -10 L 5 -10 L 9 -9 L 12 -7 L 14 -4 L 15 0 L 15 5 L 14 9 L 13 11 L 11 14 L 8 17 L 4 20 L -1 23 L -5 25 M 5 -10 L 8 -9 L 11 -7 L 13 -4 L 14 0 L 14 5 L 13 9 L 12 11 L 10 14 L 7 17 L 2 21 L -1 23 M -2 -3 L 2 -3 M -3 -2 L 3 -2 M -4 -1 L 4 -1 M -4 0 L 4 0 M -4 1 L 4 1 M -3 2 L 3 2 M -2 3 L 2 3 M 19 -6 L 19 -4 L 21 -4 L 21 -6 L 19 -6 M 20 -6 L 20 -4 M 19 -5 L 21 -5 M 19 4 L 19 6 L 21 6 L 21 4 L 19 4 M 20 4 L 20 6 M 19 5 L 21 5","-14 14 M -10 -18 L -10 18 M -5 -18 L -5 18 M 5 -18 L 5 18 M 10 -18 L 10 18 M -5 -5 L 5 -7 M -5 -4 L 5 -6 M -5 -3 L 5 -5 M -5 5 L 5 3 M -5 6 L 5 4 M -5 7 L 5 5","-14 14 M -10 -20 L -10 20 M -9 -20 L -9 20 M -5 -20 L -5 20 M -1 -16 L 1 -16 L 1 -14 L -1 -14 L -1 -17 L 0 -19 L 2 -20 L 5 -20 L 7 -19 L 9 -17 L 10 -14 L 10 -9 L 9 -6 L 7 -4 L 5 -3 L 3 -3 L 1 -4 L 0 -6 L -1 -4 L -3 -1 L -4 0 L -3 1 L -1 4 L 0 6 L 1 4 L 3 3 L 5 3 L 7 4 L 9 6 L 10 9 L 10 14 L 9 17 L 7 19 L 5 20 L 2 20 L 0 19 L -1 17 L -1 14 L 1 14 L 1 16 L -1 16 M 0 -16 L 0 -14 M -1 -15 L 1 -15 M 7 -19 L 8 -17 L 9 -14 L 9 -9 L 8 -6 L 7 -4 M 0 -6 L 0 -4 L -2 -1 L -4 0 L -2 1 L 0 4 L 0 6 M 7 4 L 8 6 L 9 9 L 9 14 L 8 17 L 7 19 M 0 14 L 0 16 M -1 15 L 1 15","-8 8 M -5 -4 L -5 -1 M 5 -4 L 5 -1 M -5 -4 L 5 -4 M -5 -3 L 5 -3 M -5 -2 L 5 -2 M -5 -1 L 5 -1","-10 10 M 3 -12 L -10 9 M 3 -12 L 4 9 M 2 -10 L 3 9 M -6 3 L 3 3 M -12 9 L -6 9 M 0 9 L 6 9","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 L 4 -2 M -5 -2 L 4 -2 L 6 -1 L 7 1 L 7 3 L 6 6 L 4 8 L 0 9 L -12 9 M 4 -2 L 5 -1 L 6 1 L 6 3 L 5 6 L 3 8 L 0 9","-10 11 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 L 6 4 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -7 L 8 -3 L 7 1 L 5 5 L 3 7 L 1 8 L -3 9 L -12 9 M 3 -12 L 5 -11 L 6 -10 L 7 -7 L 7 -3 L 6 1 L 4 5 L 2 7 L 0 8 L -3 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M 2 -6 L 0 2 M -6 -12 L 9 -12 L 8 -6 L 8 -12 M -5 -2 L 1 -2 M -12 9 L 3 9 L 5 4 L 2 9","-12 10 M -3 -12 L -9 9 M -2 -12 L -8 9 M 2 -6 L 0 2 M -6 -12 L 9 -12 L 8 -6 L 8 -12 M -5 -2 L 1 -2 M -12 9 L -5 9","-10 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 0 9 L 3 8 L 5 6 L 7 2 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9 M 0 9 L 2 8 L 4 6 L 6 2 M 3 2 L 10 2","-13 13 M -4 -12 L -10 9 M -3 -12 L -9 9 M 9 -12 L 3 9 M 10 -12 L 4 9 M -7 -12 L 0 -12 M 6 -12 L 13 -12 M -6 -2 L 6 -2 M -13 9 L -6 9 M 0 9 L 7 9","-6 7 M 3 -12 L -3 9 M 4 -12 L -2 9 M 0 -12 L 7 -12 M -6 9 L 1 9","-9 9 M 6 -12 L 1 5 L 0 7 L -1 8 L -3 9 L -5 9 L -7 8 L -8 6 L -8 4 L -7 3 L -6 4 L -7 5 M 5 -12 L 0 5 L -1 7 L -3 9 M 2 -12 L 9 -12","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M 11 -12 L -6 1 M 1 -3 L 5 9 M 0 -3 L 4 9 M -6 -12 L 1 -12 M 7 -12 L 13 -12 M -12 9 L -5 9 M 1 9 L 7 9","-10 10 M -1 -12 L -7 9 M 0 -12 L -6 9 M -4 -12 L 3 -12 M -10 9 L 5 9 L 7 3 L 4 9","-13 14 M -4 -12 L -10 9 M -4 -12 L -3 9 M -3 -12 L -2 7 M 10 -12 L -3 9 M 10 -12 L 4 9 M 11 -12 L 5 9 M -7 -12 L -3 -12 M 10 -12 L 14 -12 M -13 9 L -7 9 M 1 9 L 8 9","-12 13 M -3 -12 L -9 9 M -3 -12 L 4 6 M -3 -9 L 4 9 M 10 -12 L 4 9 M -6 -12 L -3 -12 M 7 -12 L 13 -12 M -12 9 L -6 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -4 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 6 -12 L 9 -11 L 10 -9 L 10 -7 L 9 -4 L 7 -2 L 3 -1 L -5 -1 M 6 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 6 -2 L 3 -1 M -12 9 L -5 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -4 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12 M -6 7 L -6 6 L -5 4 L -3 3 L -2 3 L 0 4 L 1 6 L 1 13 L 2 14 L 4 14 L 5 12 L 5 11 M 1 6 L 2 12 L 3 13 L 4 13 L 5 12","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 L -5 -2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 L 4 -2 M 0 -2 L 2 -1 L 3 0 L 4 8 L 5 9 L 7 9 L 8 7 L 8 6 M 3 0 L 5 7 L 6 8 L 7 8 L 8 7 M -12 9 L -5 9","-11 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -7 L -4 -5 L -3 -4 L 4 0 L 6 2 M -5 -7 L -3 -5 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -9 9 L -8 7 L -7 7","-10 11 M 3 -12 L -3 9 M 4 -12 L -2 9 M -3 -12 L -6 -6 L -4 -12 L 11 -12 L 10 -6 L 10 -12 M -6 9 L 1 9","-12 13 M -4 -12 L -7 -1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 3 8 L 5 6 L 6 3 L 10 -12 M -3 -12 L -6 -1 L -7 3 L -7 6 L -6 8 L -4 9 M -7 -12 L 0 -12 M 7 -12 L 13 -12","-10 10 M -4 -12 L -3 9 M -3 -12 L -2 7 M 10 -12 L -3 9 M -6 -12 L 0 -12 M 6 -12 L 12 -12","-13 13 M -5 -12 L -7 9 M -4 -12 L -6 7 M 3 -12 L -7 9 M 3 -12 L 1 9 M 4 -12 L 2 7 M 11 -12 L 1 9 M -8 -12 L -1 -12 M 8 -12 L 14 -12","-11 11 M -4 -12 L 3 9 M -3 -12 L 4 9 M 10 -12 L -10 9 M -6 -12 L 0 -12 M 6 -12 L 12 -12 M -12 9 L -6 9 M 0 9 L 6 9","-10 11 M -4 -12 L 0 -2 L -3 9 M -3 -12 L 1 -2 L -2 9 M 11 -12 L 1 -2 M -6 -12 L 0 -12 M 7 -12 L 13 -12 M -6 9 L 1 9","-11 11 M 9 -12 L -10 9 M 10 -12 L -9 9 M -3 -12 L -6 -6 L -4 -12 L 10 -12 M -10 9 L 4 9 L 6 3 L 3 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-6 6 M 2 -12 L -3 -6 M 2 -12 L 3 -11 L -3 -6","-13 13 M -9 0 L 9 0","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-10 11 M 6 -5 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8","-10 9 M -2 -12 L -6 1 L -6 4 L -5 7 L -4 8 M -1 -12 L -5 1 M -5 1 L -4 -2 L -2 -4 L 0 -5 L 2 -5 L 4 -4 L 5 -3 L 6 -1 L 6 2 L 5 5 L 3 8 L 0 9 L -2 9 L -4 8 L -5 5 L -5 1 M 4 -4 L 5 -2 L 5 2 L 4 5 L 2 8 L 0 9 M -5 -12 L -1 -12","-9 9 M 5 -2 L 5 -1 L 6 -1 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8","-10 11 M 8 -12 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 9 -12 L 5 2 L 4 6 L 4 8 L 5 9 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8 M 5 -12 L 9 -12","-9 9 M -5 4 L -1 3 L 2 2 L 5 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8","-7 8 M 8 -11 L 7 -10 L 8 -9 L 9 -10 L 9 -11 L 8 -12 L 6 -12 L 4 -11 L 3 -10 L 2 -8 L 1 -5 L -2 9 L -3 13 L -4 15 M 6 -12 L 4 -10 L 3 -8 L 2 -4 L 0 5 L -1 9 L -2 12 L -3 14 L -4 15 L -6 16 L -8 16 L -9 15 L -9 14 L -8 13 L -7 14 L -8 15 M -3 -5 L 7 -5","-10 10 M 7 -5 L 3 9 L 2 12 L 0 15 L -3 16 L -6 16 L -8 15 L -9 14 L -9 13 L -8 12 L -7 13 L -8 14 M 6 -5 L 2 9 L 1 12 L -1 15 L -3 16 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8","-10 11 M -2 -12 L -8 9 M -1 -12 L -7 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 6 -1 L 4 5 L 4 8 L 5 9 M 3 -5 L 5 -3 L 5 -1 L 3 5 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M -5 -12 L -1 -12","-6 7 M 3 -12 L 2 -11 L 3 -10 L 4 -11 L 3 -12 M -5 -1 L -4 -3 L -2 -5 L 1 -5 L 2 -4 L 2 -1 L 0 5 L 0 8 L 1 9 M 0 -5 L 1 -4 L 1 -1 L -1 5 L -1 8 L 0 9 L 3 9 L 5 7 L 6 5","-6 7 M 4 -12 L 3 -11 L 4 -10 L 5 -11 L 4 -12 M -4 -1 L -3 -3 L -1 -5 L 2 -5 L 3 -4 L 3 -1 L 0 9 L -1 12 L -2 14 L -3 15 L -5 16 L -7 16 L -8 15 L -8 14 L -7 13 L -6 14 L -7 15 M 1 -5 L 2 -4 L 2 -1 L -1 9 L -2 12 L -3 14 L -5 16","-10 10 M -2 -12 L -8 9 M -1 -12 L -7 9 M 6 -4 L 5 -3 L 6 -2 L 7 -3 L 7 -4 L 6 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 L -5 1 M -3 1 L -1 2 L 1 8 L 2 9 M -3 1 L -2 2 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 M -5 -12 L -1 -12","-5 7 M 3 -12 L -1 2 L -2 6 L -2 8 L -1 9 L 2 9 L 4 7 L 5 5 M 4 -12 L 0 2 L -1 6 L -1 8 L 0 9 M 0 -12 L 4 -12","-17 16 M -16 -1 L -15 -3 L -13 -5 L -10 -5 L -9 -4 L -9 -2 L -10 2 L -12 9 M -11 -5 L -10 -4 L -10 -2 L -11 2 L -13 9 M -10 2 L -8 -2 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -3 L 1 -1 L -2 9 M -2 -5 L 0 -3 L 0 -1 L -3 9 M 0 2 L 2 -2 L 4 -4 L 6 -5 L 8 -5 L 10 -4 L 11 -3 L 11 -1 L 9 5 L 9 8 L 10 9 M 8 -5 L 10 -3 L 10 -1 L 8 5 L 8 8 L 9 9 L 12 9 L 14 7 L 15 5","-12 11 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -2 L -5 2 L -7 9 M -6 -5 L -5 -4 L -5 -2 L -6 2 L -8 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 6 -1 L 4 5 L 4 8 L 5 9 M 3 -5 L 5 -3 L 5 -1 L 3 5 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5","-9 9 M 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 L 6 2 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L 0 -5 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 5 L 5 2 L 5 -2 L 4 -4","-11 10 M -10 -1 L -9 -3 L -7 -5 L -4 -5 L -3 -4 L -3 -2 L -4 2 L -8 16 M -5 -5 L -4 -4 L -4 -2 L -5 2 L -9 16 M -4 2 L -3 -1 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 7 -1 L 7 2 L 6 5 L 4 8 L 1 9 L -1 9 L -3 8 L -4 5 L -4 2 M 5 -4 L 6 -2 L 6 2 L 5 5 L 3 8 L 1 9 M -12 16 L -5 16","-10 10 M 6 -5 L 0 16 M 7 -5 L 1 16 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8 M -3 16 L 4 16","-9 8 M -8 -1 L -7 -3 L -5 -5 L -2 -5 L -1 -4 L -1 -2 L -2 2 L -4 9 M -3 -5 L -2 -4 L -2 -2 L -3 2 L -5 9 M -2 2 L 0 -2 L 2 -4 L 4 -5 L 6 -5 L 7 -4 L 7 -3 L 6 -2 L 5 -3 L 6 -4","-8 9 M 6 -3 L 6 -2 L 7 -2 L 7 -3 L 6 -4 L 3 -5 L 0 -5 L -3 -4 L -4 -3 L -4 -1 L -3 0 L 4 4 L 5 5 M -4 -2 L -3 -1 L 4 3 L 5 4 L 5 7 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -6 6 L -5 6 L -5 7","-7 7 M 2 -12 L -2 2 L -3 6 L -3 8 L -2 9 L 1 9 L 3 7 L 4 5 M 3 -12 L -1 2 L -2 6 L -2 8 L -1 9 M -4 -5 L 5 -5","-12 11 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -1 L -6 5 L -6 7 L -4 9 M -6 -5 L -5 -4 L -5 -1 L -7 5 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 2 M 6 -5 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9","-10 10 M -9 -1 L -8 -3 L -6 -5 L -3 -5 L -2 -4 L -2 -1 L -4 5 L -4 7 L -2 9 M -4 -5 L -3 -4 L -3 -1 L -5 5 L -5 7 L -4 8 L -2 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 -1 L 7 -5 L 6 -5 L 7 -3","-15 14 M -14 -1 L -13 -3 L -11 -5 L -8 -5 L -7 -4 L -7 -1 L -9 5 L -9 7 L -7 9 M -9 -5 L -8 -4 L -8 -1 L -10 5 L -10 7 L -9 8 L -7 9 L -5 9 L -3 8 L -1 6 L 0 4 M 2 -5 L 0 4 L 0 7 L 1 8 L 3 9 L 5 9 L 7 8 L 9 6 L 10 4 L 11 0 L 11 -5 L 10 -5 L 11 -3 M 3 -5 L 1 4 L 1 7 L 3 9","-10 10 M -7 -1 L -5 -4 L -3 -5 L 0 -5 L 1 -3 L 1 0 M -1 -5 L 0 -3 L 0 0 L -1 4 L -2 6 L -4 8 L -6 9 L -7 9 L -8 8 L -8 7 L -7 6 L -6 7 L -7 8 M -1 4 L -1 7 L 0 9 L 3 9 L 5 8 L 7 5 M 7 -4 L 6 -3 L 7 -2 L 8 -3 L 8 -4 L 7 -5 L 6 -5 L 4 -4 L 2 -2 L 1 0 L 0 4 L 0 7 L 1 9","-11 10 M -10 -1 L -9 -3 L -7 -5 L -4 -5 L -3 -4 L -3 -1 L -5 5 L -5 7 L -3 9 M -5 -5 L -4 -4 L -4 -1 L -6 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 6 L 5 2 M 8 -5 L 4 9 L 3 12 L 1 15 L -2 16 L -5 16 L -7 15 L -8 14 L -8 13 L -7 12 L -6 13 L -7 14 M 7 -5 L 3 9 L 2 12 L 0 15 L -2 16","-10 10 M 7 -5 L 6 -3 L 4 -1 L -4 5 L -6 7 L -7 9 M -6 -1 L -5 -3 L -3 -5 L 0 -5 L 4 -3 M -5 -3 L -3 -4 L 0 -4 L 4 -3 L 6 -3 M -6 7 L -4 7 L 0 8 L 3 8 L 5 7 M -4 7 L 0 9 L 3 9 L 5 7 L 6 5","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -scriptc = ["-8 8","-5 6 M 3 -12 L 2 -11 L 0 1 M 3 -11 L 0 1 M 3 -12 L 4 -11 L 0 1 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-9 9 M -2 -12 L -4 -5 M -1 -12 L -4 -5 M 7 -12 L 5 -5 M 8 -12 L 5 -5","-10 11 M 1 -12 L -6 16 M 7 -12 L 0 16 M -6 -1 L 8 -1 M -7 5 L 7 5","-10 11 M 2 -16 L -6 13 M 7 -16 L -1 13 M 8 -8 L 7 -7 L 8 -6 L 9 -7 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -7 L -4 -5 L -3 -4 L 4 0 L 6 2 M -5 -7 L -3 -5 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -4 L 9 -3 L 10 -2 L 11 -3 L 11 -4 L 10 -5 L 9 -5 L 7 -4 L 5 -2 L 0 6 L -2 8 L -4 9 L -7 9 L -10 8 L -11 6 L -11 4 L -10 2 L -9 1 L -7 0 L -2 -2 L 0 -3 L 2 -5 L 3 -7 L 3 -9 L 2 -11 L 0 -12 L -2 -11 L -3 -9 L -3 -6 L -2 0 L -1 3 L 1 6 L 3 8 L 5 9 L 7 9 L 8 7 L 8 6 M -7 9 L -9 8 L -10 6 L -10 4 L -9 2 L -8 1 L -2 -2 M -3 -6 L -2 -1 L -1 2 L 1 5 L 3 7 L 5 8 L 7 8 L 8 7","-5 6 M 3 -10 L 2 -11 L 3 -12 L 4 -11 L 4 -10 L 3 -8 L 1 -6","-7 8 M 8 -16 L 4 -13 L 1 -10 L -1 -7 L -3 -3 L -4 2 L -4 6 L -3 11 L -2 14 L -1 16 M 4 -13 L 1 -9 L -1 -5 L -2 -2 L -3 3 L -3 8 L -2 13 L -1 16","-8 7 M 1 -16 L 2 -14 L 3 -11 L 4 -6 L 4 -2 L 3 3 L 1 7 L -1 10 L -4 13 L -8 16 M 1 -16 L 2 -13 L 3 -8 L 3 -3 L 2 2 L 1 5 L -1 9 L -4 13","-8 9 M 2 -12 L 2 0 M -3 -9 L 7 -3 M 7 -9 L -3 -3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-5 6 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-13 13 M -9 0 L 9 0","-5 6 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-11 11 M 13 -16 L -13 16","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -3 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12","-10 11 M 2 -8 L -3 9 M 4 -12 L -2 9 M 4 -12 L 1 -9 L -2 -7 L -4 -6 M 3 -9 L -1 -7 L -4 -6","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 5 -3 L 2 -1 L -2 1 L -5 3 L -7 5 L -9 9 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 L -2 1 M -8 7 L -7 6 L -5 6 L 0 8 L 3 8 L 5 7 L 6 5 M -5 6 L 0 9 L 3 9 L 5 8 L 6 5","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 4 -3 L 1 -2 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 M -1 -2 L 1 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -2 L 3 -1 L 4 0 L 5 2 L 5 5 L 4 7 L 3 8 L 1 9","-10 11 M 6 -11 L 0 9 M 7 -12 L 1 9 M 7 -12 L -8 3 L 8 3","-10 11 M -1 -12 L -6 -2 M -1 -12 L 9 -12 M -1 -11 L 4 -11 L 9 -12 M -6 -2 L -5 -3 L -2 -4 L 1 -4 L 4 -3 L 5 -2 L 6 0 L 6 3 L 5 6 L 3 8 L 0 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -4 L 3 -3 L 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 L 0 9","-10 11 M 7 -9 L 6 -8 L 7 -7 L 8 -8 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 5 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 L -1 -3 L -3 -2 L -5 0 L -6 2 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 6 L -5 8 M 0 9 L 2 8 L 4 6 L 5 4 L 5 0 L 4 -2","-10 11 M -4 -12 L -6 -6 M 9 -12 L 8 -9 L 6 -6 L 1 0 L -1 3 L -2 5 L -3 9 M 6 -6 L 0 0 L -2 3 L -3 5 L -4 9 M -5 -9 L -2 -12 L 0 -12 L 5 -9 M -4 -10 L -2 -11 L 0 -11 L 5 -9 L 7 -9 L 8 -10 L 9 -12","-10 11 M 1 -12 L -2 -11 L -3 -10 L -4 -8 L -4 -5 L -3 -3 L -1 -2 L 2 -2 L 6 -3 L 7 -4 L 8 -6 L 8 -9 L 7 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -2 -10 L -3 -8 L -3 -5 L -2 -3 L -1 -2 M 2 -2 L 5 -3 L 6 -4 L 7 -6 L 7 -9 L 6 -11 L 4 -12 M -1 -2 L -5 -1 L -7 1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 4 8 L 5 7 L 6 5 L 6 2 L 5 0 L 4 -1 L 2 -2 M -1 -2 L -4 -1 L -6 1 L -7 3 L -7 6 L -6 8 L -4 9 M 0 9 L 3 8 L 4 7 L 5 5 L 5 1 L 4 -1","-10 11 M 7 -5 L 6 -3 L 4 -1 L 2 0 L -1 0 L -3 -1 L -4 -2 L -5 -4 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 4 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -4 L 7 0 L 6 3 L 4 6 L 2 8 L -1 9 L -4 9 L -6 8 L -7 6 L -7 5 L -6 4 L -5 5 L -6 6 M -3 -1 L -4 -3 L -4 -7 L -3 -9 L -1 -11 L 1 -12 M 6 -11 L 7 -9 L 7 -4 L 6 0 L 5 3 L 3 6 L 1 8 L -1 9","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 7 L -3 8 L -2 9 L -1 8","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 1 -2 L -1 -1 L -1 1 L 0 2 L 2 2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-13 10 M 6 -12 L 4 -10 L 2 -7 L -1 -2 L -3 1 L -6 5 L -9 8 L -11 9 L -13 9 L -14 8 L -14 6 L -13 5 L -12 6 L -13 7 M 6 -12 L 5 -8 L 3 2 L 2 9 M 6 -12 L 3 9 M 2 9 L 2 7 L 1 4 L 0 2 L -2 0 L -4 -1 L -6 -1 L -7 0 L -7 2 L -6 5 L -3 8 L 0 9 L 4 9 L 6 8","-12 12 M 3 -11 L 2 -10 L 1 -8 L -1 -3 L -3 3 L -4 5 L -6 8 L -8 9 M 2 -10 L 1 -7 L -1 1 L -2 4 L -3 6 L -5 8 L -8 9 L -10 9 L -11 8 L -11 6 L -10 5 L -9 6 L -10 7 M -3 -6 L -4 -4 L -5 -3 L -7 -3 L -8 -4 L -8 -6 L -7 -8 L -5 -10 L -3 -11 L 0 -12 L 6 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 6 -4 L 2 -3 L 0 -3 M 6 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 M 2 -3 L 5 -2 L 6 -1 L 7 1 L 7 4 L 6 7 L 5 8 L 3 9 L 1 9 L 0 8 L 0 6 L 1 3 M 2 -3 L 4 -2 L 5 -1 L 6 1 L 6 4 L 5 7 L 3 9","-10 11 M -7 -10 L -8 -8 L -8 -6 L -7 -4 L -4 -3 L -1 -3 L 3 -4 L 5 -5 L 7 -7 L 8 -9 L 8 -11 L 7 -12 L 5 -12 L 2 -11 L -1 -8 L -3 -5 L -5 -1 L -6 3 L -6 6 L -5 8 L -2 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 2 L 5 0 L 3 0 L 1 1 L 0 3 M 5 -12 L 3 -11 L 0 -8 L -2 -5 L -4 -1 L -5 3 L -5 6 L -4 8 L -2 9","-12 11 M 3 -11 L 2 -10 L 1 -8 L -1 -3 L -3 3 L -4 5 L -6 8 L -8 9 M 2 -10 L 1 -7 L -1 1 L -2 4 L -3 6 L -5 8 L -8 9 L -10 9 L -11 8 L -11 6 L -10 5 L -8 5 L -6 6 L -4 8 L -2 9 L 1 9 L 3 8 L 5 6 L 7 2 L 8 -3 L 8 -6 L 7 -9 L 5 -11 L 3 -12 L -2 -12 L -5 -11 L -7 -9 L -8 -7 L -8 -5 L -7 -4 L -5 -4 L -4 -5 L -3 -7","-9 10 M 5 -9 L 4 -8 L 4 -6 L 5 -5 L 7 -5 L 8 -7 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L 0 -11 L -1 -10 L -2 -8 L -2 -6 L -1 -4 L 1 -3 M 2 -12 L 0 -10 L -1 -8 L -1 -5 L 1 -3 M 1 -3 L -1 -3 L -4 -2 L -6 0 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 2 L 5 0 L 3 0 L 1 1 L 0 3 M -1 -3 L -3 -2 L -5 0 L -6 2 L -6 6 L -5 8","-11 10 M 5 -10 L 4 -8 L 2 -3 L 0 3 L -1 5 L -3 8 L -5 9 M -1 -6 L -2 -4 L -4 -3 L -6 -3 L -7 -5 L -7 -7 L -6 -9 L -4 -11 L -1 -12 L 9 -12 L 6 -11 L 5 -10 L 4 -7 L 2 1 L 1 4 L 0 6 L -2 8 L -5 9 L -7 9 L -9 8 L -10 7 L -10 6 L -9 5 L -8 6 L -9 7 M 1 -12 L 5 -11 L 6 -11 M -3 1 L -2 0 L 0 -1 L 4 -1 L 6 -2 L 8 -5 L 6 2","-11 11 M -8 -9 L -9 -7 L -9 -5 L -8 -3 L -6 -2 L -3 -2 L 0 -3 L 2 -4 L 5 -7 L 6 -10 L 6 -11 L 5 -12 L 4 -12 L 2 -11 L 0 -9 L -1 -7 L -2 -4 L -2 -1 L -1 1 L 1 2 L 3 2 L 5 1 L 7 -1 L 8 -3 M 5 -12 L 3 -11 L 1 -9 L 0 -7 L -1 -4 L -1 0 L 1 2 M 8 -3 L 7 1 L 5 5 L 3 7 L 1 8 L -3 9 L -6 9 L -8 8 L -9 6 L -9 5 L -8 4 L -7 5 L -8 6 M 7 1 L 5 4 L 3 6 L 0 8 L -3 9","-12 12 M -6 -6 L -7 -7 L -7 -9 L -6 -11 L -3 -12 L 0 -12 L -3 -1 L -5 5 L -6 7 L -7 8 L -9 9 L -11 9 L -12 8 L -12 6 L -11 5 L -10 6 L -11 7 M 0 -12 L -3 -3 L -4 0 L -6 5 L -7 7 L -9 9 M -8 2 L -7 1 L -5 0 L 4 -3 L 6 -4 L 9 -6 L 11 -8 L 12 -10 L 12 -11 L 11 -12 L 10 -12 L 8 -11 L 6 -8 L 5 -6 L 3 0 L 2 4 L 2 7 L 4 9 L 5 9 L 7 8 L 9 6 M 10 -12 L 8 -10 L 6 -6 L 4 0 L 3 4 L 3 7 L 4 9","-9 7 M 5 -10 L 3 -7 L 1 -2 L -1 3 L -2 5 L -4 8 L -6 9 M 7 -6 L 5 -4 L 2 -3 L -1 -3 L -3 -4 L -4 -6 L -4 -8 L -3 -10 L -1 -11 L 3 -12 L 7 -12 L 5 -10 L 4 -8 L 2 -2 L 0 4 L -1 6 L -3 8 L -6 9 L -8 9 L -9 8 L -9 6 L -8 5 L -7 6 L -8 7","-9 8 M 7 -12 L 5 -10 L 3 -7 L 1 -2 L -2 7 L -4 11 M 7 -5 L 5 -3 L 2 -2 L -1 -2 L -3 -3 L -4 -5 L -4 -7 L -3 -9 L -1 -11 L 3 -12 L 7 -12 L 5 -9 L 4 -7 L 1 2 L -1 6 L -2 8 L -4 11 L -5 12 L -7 13 L -8 12 L -8 10 L -7 8 L -5 6 L -3 5 L 0 4 L 4 3","-12 12 M -6 -6 L -7 -7 L -7 -9 L -5 -11 L -2 -12 L 0 -12 L -3 -1 L -5 5 L -6 7 L -7 8 L -9 9 L -11 9 L -12 8 L -12 6 L -11 5 L -10 6 L -11 7 M 0 -12 L -3 -3 L -4 0 L -6 5 L -7 7 L -9 9 M 8 -11 L 5 -7 L 3 -5 L 1 -4 L -2 -3 M 11 -11 L 10 -10 L 11 -9 L 12 -10 L 12 -11 L 11 -12 L 10 -12 L 8 -11 L 5 -6 L 4 -5 L 2 -4 L -2 -3 M -2 -3 L 1 -2 L 2 0 L 3 7 L 4 9 M -2 -3 L 0 -2 L 1 0 L 2 7 L 4 9 L 5 9 L 7 8 L 9 6","-9 9 M -5 -9 L -6 -7 L -6 -5 L -5 -3 L -3 -2 L 0 -2 L 3 -3 L 5 -4 L 8 -7 L 9 -10 L 9 -11 L 8 -12 L 7 -12 L 5 -11 L 4 -10 L 2 -7 L -2 3 L -3 5 L -5 8 L -7 9 M 4 -10 L 2 -6 L 0 1 L -1 4 L -2 6 L -4 8 L -7 9 L -9 9 L -10 8 L -10 6 L -9 5 L -7 5 L -5 6 L -2 8 L 0 9 L 3 9 L 5 8 L 7 6","-14 14 M 0 -12 L -4 -3 L -7 3 L -9 6 L -11 8 L -13 9 L -15 9 L -16 8 L -16 6 L -15 5 L -14 6 L -15 7 M 0 -12 L -2 -5 L -3 -1 L -4 4 L -4 8 L -2 9 M 0 -12 L -1 -8 L -2 -3 L -3 4 L -3 8 L -2 9 M 9 -12 L 5 -3 L 0 6 L -2 9 M 9 -12 L 7 -5 L 6 -1 L 5 4 L 5 8 L 7 9 L 8 9 L 10 8 L 12 6 M 9 -12 L 8 -8 L 7 -3 L 6 4 L 6 8 L 7 9","-11 12 M 0 -12 L -1 -8 L -3 -2 L -5 3 L -6 5 L -8 8 L -10 9 L -12 9 L -13 8 L -13 6 L -12 5 L -11 6 L -12 7 M 0 -12 L 0 -7 L 1 4 L 2 9 M 0 -12 L 1 -7 L 2 4 L 2 9 M 14 -11 L 13 -10 L 14 -9 L 15 -10 L 15 -11 L 14 -12 L 12 -12 L 10 -11 L 8 -8 L 7 -6 L 5 -1 L 3 5 L 2 9","-10 11 M 1 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -4 L -7 0 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 1 L 8 -3 L 8 -7 L 7 -10 L 6 -11 L 5 -11 L 3 -10 L 1 -8 L -1 -4 L -2 1 L -2 4 M -1 -11 L -3 -8 L -5 -4 L -6 0 L -6 4 L -5 7 L -3 9","-12 11 M 3 -11 L 2 -10 L 1 -8 L -1 -3 L -3 3 L -4 5 L -6 8 L -8 9 M 2 -10 L 1 -7 L -1 1 L -2 4 L -3 6 L -5 8 L -8 9 L -10 9 L -11 8 L -11 6 L -10 5 L -9 6 L -10 7 M -3 -6 L -4 -4 L -5 -3 L -7 -3 L -8 -4 L -8 -6 L -7 -8 L -5 -10 L -3 -11 L 0 -12 L 4 -12 L 7 -11 L 8 -10 L 9 -8 L 9 -5 L 8 -3 L 7 -2 L 4 -1 L 2 -1 L 0 -2 M 4 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 4 -1","-10 11 M 3 -8 L 3 -6 L 2 -4 L 1 -3 L -1 -2 L -3 -2 L -4 -4 L -4 -6 L -3 -9 L -1 -11 L 2 -12 L 5 -12 L 7 -11 L 8 -9 L 8 -5 L 7 -2 L 5 1 L 1 5 L -2 7 L -4 8 L -7 9 L -9 9 L -10 8 L -10 6 L -9 5 L -7 5 L -5 6 L -2 8 L 1 9 L 4 9 L 6 8 L 8 6 M 5 -12 L 6 -11 L 7 -9 L 7 -5 L 6 -2 L 4 1 L 1 4 L -3 7 L -7 9","-12 12 M 3 -11 L 2 -10 L 1 -8 L -1 -3 L -3 3 L -4 5 L -6 8 L -8 9 M 2 -10 L 1 -7 L -1 1 L -2 4 L -3 6 L -5 8 L -8 9 L -10 9 L -11 8 L -11 6 L -10 5 L -9 6 L -10 7 M -3 -6 L -4 -4 L -5 -3 L -7 -3 L -8 -4 L -8 -6 L -7 -8 L -5 -10 L -3 -11 L 0 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 4 -3 L 0 -3 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 M 0 -3 L 3 -2 L 4 0 L 5 7 L 6 9 M 0 -3 L 2 -2 L 3 0 L 4 7 L 6 9 L 7 9 L 9 8 L 11 6","-10 10 M -4 -9 L -5 -7 L -5 -5 L -4 -3 L -2 -2 L 1 -2 L 4 -3 L 6 -4 L 9 -7 L 10 -10 L 10 -11 L 9 -12 L 8 -12 L 6 -11 L 5 -10 L 4 -8 L 3 -5 L 1 2 L 0 5 L -2 8 L -4 9 M 4 -8 L 3 -4 L 2 3 L 1 6 L -1 8 L -4 9 L -7 9 L -9 8 L -10 6 L -10 5 L -9 4 L -8 5 L -9 6","-9 9 M 7 -10 L 6 -8 L 4 -3 L 2 3 L 1 5 L -1 8 L -3 9 M 1 -6 L 0 -4 L -2 -3 L -4 -3 L -5 -5 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 10 -12 L 8 -11 L 7 -10 L 6 -7 L 4 1 L 3 4 L 2 6 L 0 8 L -3 9 L -5 9 L -7 8 L -8 7 L -8 6 L -7 5 L -6 6 L -7 7 M 3 -12 L 7 -11 L 8 -11","-11 11 M -10 -8 L -8 -11 L -6 -12 L -5 -12 L -3 -10 L -3 -7 L -4 -4 L -7 4 L -7 7 L -6 9 M -5 -12 L -4 -10 L -4 -7 L -7 1 L -8 4 L -8 7 L -6 9 L -4 9 L -2 8 L 1 5 L 3 2 L 4 0 M 8 -12 L 4 0 L 3 4 L 3 7 L 5 9 L 6 9 L 8 8 L 10 6 M 9 -12 L 5 0 L 4 4 L 4 7 L 5 9","-11 10 M -10 -8 L -8 -11 L -6 -12 L -5 -12 L -3 -10 L -3 -7 L -4 -3 L -6 4 L -6 7 L -5 9 M -5 -12 L -4 -10 L -4 -7 L -6 0 L -7 4 L -7 7 L -5 9 L -4 9 L -1 8 L 2 5 L 4 2 L 6 -2 L 7 -5 L 8 -9 L 8 -11 L 7 -12 L 6 -12 L 5 -11 L 4 -9 L 4 -6 L 5 -4 L 7 -2 L 9 -1 L 11 -1","-12 11 M -9 -6 L -10 -6 L -11 -7 L -11 -9 L -10 -11 L -8 -12 L -4 -12 L -5 -10 L -6 -6 L -7 3 L -8 9 M -6 -6 L -6 3 L -7 9 M 4 -12 L 2 -10 L 0 -6 L -3 3 L -5 7 L -7 9 M 4 -12 L 3 -10 L 2 -6 L 1 3 L 0 9 M 2 -6 L 2 3 L 1 9 M 14 -12 L 12 -11 L 10 -9 L 8 -6 L 5 3 L 3 7 L 1 9","-10 10 M -2 -7 L -3 -6 L -5 -6 L -6 -7 L -6 -9 L -5 -11 L -3 -12 L -1 -12 L 1 -11 L 2 -9 L 2 -6 L 1 -2 L -1 3 L -3 6 L -5 8 L -8 9 L -10 9 L -11 8 L -11 6 L -10 5 L -9 6 L -10 7 M -1 -12 L 0 -11 L 1 -9 L 1 -6 L 0 -2 L -2 3 L -4 6 L -6 8 L -8 9 M 11 -11 L 10 -10 L 11 -9 L 12 -10 L 12 -11 L 11 -12 L 9 -12 L 7 -11 L 5 -9 L 3 -6 L 1 -2 L 0 3 L 0 6 L 1 8 L 2 9 L 3 9 L 5 8 L 7 6","-11 11 M -8 -8 L -6 -11 L -4 -12 L -3 -12 L -1 -11 L -1 -9 L -3 -3 L -3 0 L -2 2 M -3 -12 L -2 -11 L -2 -9 L -4 -3 L -4 0 L -2 2 L 0 2 L 3 1 L 5 -1 L 7 -4 L 8 -6 M 10 -12 L 8 -6 L 5 2 L 3 6 M 11 -12 L 9 -6 L 7 -1 L 5 3 L 3 6 L 1 8 L -2 9 L -6 9 L -8 8 L -9 6 L -9 5 L -8 4 L -7 5 L -8 6","-11 10 M 8 -10 L 7 -8 L 5 -3 L 4 0 L 3 2 L 1 5 L -1 7 L -3 8 L -6 9 M 1 -6 L 0 -4 L -2 -3 L -4 -3 L -5 -5 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 11 -12 L 9 -11 L 8 -10 L 7 -7 L 6 -3 L 4 3 L 2 6 L -1 8 L -6 9 L -10 9 L -11 8 L -11 6 L -10 5 L -8 5 L -6 6 L -3 8 L -1 9 L 2 9 L 5 8 L 7 6 M 4 -12 L 8 -11 L 9 -11","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-8 8 M -2 -6 L 0 -9 L 2 -6 M -5 -3 L 0 -8 L 5 -3 M 0 -8 L 0 9","-8 8 M -8 11 L 8 11","-5 6 M 4 -12 L 2 -10 L 1 -8 L 1 -7 L 2 -6 L 3 -7 L 2 -8","-7 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 M -2 0 L -4 2 L -5 4 L -5 7 L -3 9 M 4 0 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4 M 5 0 L 3 6 L 3 8 L 4 9","-6 8 M -6 4 L -4 1 L -2 -3 M 1 -12 L -5 6 L -5 8 L -3 9 L -2 9 L 0 8 L 2 6 L 3 3 L 3 0 L 4 4 L 5 5 L 6 5 L 8 4 M 2 -12 L -4 6 L -4 8 L -3 9","-6 6 M 2 1 L 1 2 L 2 2 L 2 1 L 1 0 L -1 0 L -3 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9 L 1 9 L 4 7 L 6 4 M -1 0 L -3 2 L -4 4 L -4 7 L -2 9","-7 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 M -2 0 L -4 2 L -5 4 L -5 7 L -3 9 M 8 -12 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4 M 9 -12 L 3 6 L 3 8 L 4 9","-6 6 M -3 7 L -1 6 L 0 5 L 1 3 L 1 1 L 0 0 L -1 0 L -3 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9 L 1 9 L 4 7 L 6 4 M -1 0 L -3 2 L -4 4 L -4 7 L -2 9","-3 6 M 0 0 L 3 -3 L 5 -6 L 6 -9 L 6 -11 L 5 -12 L 3 -11 L 2 -9 L -7 18 L -7 20 L -6 21 L -4 20 L -3 17 L -2 8 L -1 9 L 1 9 L 3 8 L 4 7 L 6 4 M 2 -9 L 1 -4 L 0 0 L -3 9 L -5 14 L -7 18","-7 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 M -2 0 L -4 2 L -5 4 L -5 7 L -3 9 M 4 0 L -2 18 M 5 0 L 2 9 L 0 14 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -3 13 L 0 11 L 4 9 L 7 7 L 9 4","-6 9 M -6 4 L -4 1 L -2 -3 M 1 -12 L -6 9 M 2 -12 L -5 9 M -3 3 L -1 1 L 1 0 L 2 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 M 2 0 L 3 1 L 3 3 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4","-4 4 M 1 -6 L 0 -5 L 1 -4 L 2 -5 L 1 -6 M -1 0 L -3 6 L -3 8 L -1 9 L 1 8 L 2 7 L 4 4 M 0 0 L -2 6 L -2 8 L -1 9","-4 4 M 1 -6 L 0 -5 L 1 -4 L 2 -5 L 1 -6 M -1 0 L -7 18 M 0 0 L -3 9 L -5 14 L -7 18 L -8 20 L -10 21 L -11 20 L -11 18 L -10 15 L -8 13 L -5 11 L -1 9 L 2 7 L 4 4","-6 8 M -6 4 L -4 1 L -2 -3 M 1 -12 L -6 9 M 2 -12 L -5 9 M 3 0 L 3 1 L 4 1 L 3 0 L 2 0 L 0 2 L -3 3 M -3 3 L 0 4 L 1 8 L 2 9 M -3 3 L -1 4 L 0 8 L 2 9 L 3 9 L 6 7 L 8 4","-4 4 M -4 4 L -2 1 L 0 -3 M 3 -12 L -3 6 L -3 8 L -1 9 L 1 8 L 2 7 L 4 4 M 4 -12 L -2 6 L -2 8 L -1 9","-13 12 M -13 4 L -11 1 L -9 0 L -7 1 L -7 3 L -9 9 M -9 0 L -8 1 L -8 3 L -10 9 M -7 3 L -5 1 L -3 0 L -2 0 L 0 1 L 0 3 L -2 9 M -2 0 L -1 1 L -1 3 L -3 9 M 0 3 L 2 1 L 4 0 L 5 0 L 7 1 L 7 3 L 6 6 L 6 8 L 7 9 M 5 0 L 6 1 L 6 3 L 5 6 L 5 8 L 7 9 L 9 8 L 10 7 L 12 4","-9 9 M -9 4 L -7 1 L -5 0 L -3 1 L -3 3 L -5 9 M -5 0 L -4 1 L -4 3 L -6 9 M -3 3 L -1 1 L 1 0 L 2 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 M 2 0 L 3 1 L 3 3 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4","-7 7 M 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 L 3 5 L 3 3 L 2 1 L 0 0 L -1 1 L -1 3 L 0 5 L 2 6 L 4 6 L 6 5 L 7 4 M -2 0 L -4 2 L -5 4 L -5 7 L -3 9","-6 9 M -6 4 L -4 1 L -2 -3 M -1 -6 L -10 21 M 0 -6 L -9 21 M -3 3 L -1 1 L 1 0 L 2 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 M 2 0 L 3 1 L 3 3 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4","-7 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 M -2 0 L -4 2 L -5 4 L -5 7 L -3 9 M 4 0 L -2 18 L -2 20 L -1 21 L 1 20 L 2 17 L 2 9 L 4 9 L 7 7 L 9 4 M 5 0 L 2 9 L 0 14 L -2 18","-6 8 M -6 4 L -4 1 L -2 0 L 0 1 L 0 3 L -2 9 M -2 0 L -1 1 L -1 3 L -3 9 M 0 3 L 2 1 L 4 0 L 5 0 L 4 3 M 4 0 L 4 3 L 5 5 L 6 5 L 8 4","-4 8 M -4 4 L -2 1 L -1 -1 L -1 1 L 2 3 L 3 5 L 3 7 L 2 8 L 0 9 M -1 1 L 1 3 L 2 5 L 2 7 L 0 9 M -4 8 L -2 9 L 3 9 L 6 7 L 8 4","-4 4 M -4 4 L -2 1 L 0 -3 M 3 -12 L -3 6 L -3 8 L -1 9 L 1 8 L 2 7 L 4 4 M 4 -12 L -2 6 L -2 8 L -1 9 M -2 -4 L 4 -4","-7 9 M -4 0 L -6 6 L -6 8 L -4 9 L -3 9 L -1 8 L 1 6 L 3 3 M -3 0 L -5 6 L -5 8 L -4 9 M 4 0 L 2 6 L 2 8 L 4 9 L 6 8 L 7 7 L 9 4 M 5 0 L 3 6 L 3 8 L 4 9","-7 8 M -4 0 L -5 2 L -6 5 L -6 8 L -4 9 L -3 9 L 0 8 L 2 6 L 3 3 L 3 0 M -3 0 L -4 2 L -5 5 L -5 8 L -4 9 M 3 0 L 4 4 L 5 5 L 6 5 L 8 4","-10 11 M -6 0 L -8 2 L -9 5 L -9 8 L -7 9 L -6 9 L -4 8 L -2 6 M -5 0 L -7 2 L -8 5 L -8 8 L -7 9 M 0 0 L -2 6 L -2 8 L 0 9 L 1 9 L 3 8 L 5 6 L 6 3 L 6 0 M 1 0 L -1 6 L -1 8 L 0 9 M 6 0 L 7 4 L 8 5 L 9 5 L 11 4","-8 8 M -8 4 L -6 1 L -4 0 L -2 0 L -1 1 L -1 3 L -2 6 L -3 8 L -5 9 L -6 9 L -7 8 L -7 7 L -6 7 L -7 8 M 5 1 L 4 2 L 5 2 L 5 1 L 4 0 L 3 0 L 1 1 L 0 3 L -1 6 L -1 8 L 0 9 L 3 9 L 6 7 L 8 4 M -1 1 L 0 3 M 1 1 L -1 3 M -2 6 L -1 8 M -1 6 L -3 8","-7 9 M -4 0 L -6 6 L -6 8 L -4 9 L -3 9 L -1 8 L 1 6 L 3 3 M -3 0 L -5 6 L -5 8 L -4 9 M 4 0 L -2 18 M 5 0 L 2 9 L 0 14 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -3 13 L 0 11 L 4 9 L 7 7 L 9 4","-6 7 M -6 4 L -4 1 L -2 0 L 0 0 L 2 1 L 2 4 L 1 6 L -2 8 L -4 9 M 0 0 L 1 1 L 1 4 L 0 6 L -2 8 M -4 9 L -2 10 L -1 12 L -1 15 L -2 18 L -4 20 L -6 21 L -7 20 L -7 18 L -6 15 L -3 12 L 0 10 L 4 7 L 7 4 M -4 9 L -3 10 L -2 12 L -2 15 L -3 18 L -4 20","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-7 8 M 1 -12 L -1 -11 L -2 -9 L -2 -7 L -1 -5 L 1 -4 L 3 -4 L 5 -5 L 6 -7 L 6 -9 L 5 -11 L 3 -12 L 1 -12"] -scripts = ["-8 8","-5 6 M 3 -12 L 2 -11 L 0 1 M 3 -11 L 0 1 M 3 -12 L 4 -11 L 0 1 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-9 9 M -2 -12 L -4 -5 M -1 -12 L -4 -5 M 7 -12 L 5 -5 M 8 -12 L 5 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 11 M 2 -16 L -6 13 M 7 -16 L -1 13 M 8 -8 L 7 -7 L 8 -6 L 9 -7 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -7 L -4 -5 L -3 -4 L 4 0 L 6 2 M -5 -7 L -3 -5 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -4 L 9 -3 L 10 -2 L 11 -3 L 11 -4 L 10 -5 L 9 -5 L 7 -4 L 5 -2 L 0 6 L -2 8 L -4 9 L -7 9 L -10 8 L -11 6 L -11 4 L -10 2 L -9 1 L -7 0 L -2 -2 L 0 -3 L 2 -5 L 3 -7 L 3 -9 L 2 -11 L 0 -12 L -2 -11 L -3 -9 L -3 -6 L -2 0 L -1 3 L 1 6 L 3 8 L 5 9 L 7 9 L 8 7 L 8 6 M -7 9 L -9 8 L -10 6 L -10 4 L -9 2 L -8 1 L -2 -2 M -3 -6 L -2 -1 L -1 2 L 1 5 L 3 7 L 5 8 L 7 8 L 8 7","-5 6 M 3 -10 L 2 -11 L 3 -12 L 4 -11 L 4 -10 L 3 -8 L 1 -6","-7 8 M 8 -16 L 4 -13 L 1 -10 L -1 -7 L -3 -3 L -4 2 L -4 6 L -3 11 L -2 14 L -1 16 M 4 -13 L 1 -9 L -1 -5 L -2 -2 L -3 3 L -3 8 L -2 13 L -1 16","-8 7 M 1 -16 L 2 -14 L 3 -11 L 4 -6 L 4 -2 L 3 3 L 1 7 L -1 10 L -4 13 L -8 16 M 1 -16 L 2 -13 L 3 -8 L 3 -3 L 2 2 L 1 5 L -1 9 L -4 13","-8 9 M 2 -12 L 2 0 M -3 -9 L 7 -3 M 7 -9 L -3 -3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-5 6 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-13 13 M -9 0 L 9 0","-5 5 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-11 11 M 13 -16 L -13 16","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -3 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12","-10 11 M 2 -8 L -3 9 M 4 -12 L -2 9 M 4 -12 L 1 -9 L -2 -7 L -4 -6 M 3 -9 L -1 -7 L -4 -6","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 5 -3 L 2 -1 L -2 1 L -5 3 L -7 5 L -9 9 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 L -2 1 M -8 7 L -7 6 L -5 6 L 0 8 L 3 8 L 5 7 L 6 5 M -5 6 L 0 9 L 3 9 L 5 8 L 6 5","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 4 -3 L 1 -2 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 M -1 -2 L 1 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -2 L 3 -1 L 4 0 L 5 2 L 5 5 L 4 7 L 3 8 L 1 9","-10 11 M 6 -11 L 0 9 M 7 -12 L 1 9 M 7 -12 L -8 3 L 8 3","-10 11 M -1 -12 L -6 -2 M -1 -12 L 9 -12 M -1 -11 L 4 -11 L 9 -12 M -6 -2 L -5 -3 L -2 -4 L 1 -4 L 4 -3 L 5 -2 L 6 0 L 6 3 L 5 6 L 3 8 L 0 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -4 L 3 -3 L 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 L 0 9","-10 11 M 7 -9 L 6 -8 L 7 -7 L 8 -8 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 5 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 L -1 -3 L -3 -2 L -5 0 L -6 2 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 6 L -5 8 M 0 9 L 2 8 L 4 6 L 5 4 L 5 0 L 4 -2","-10 11 M -4 -12 L -6 -6 M 9 -12 L 8 -9 L 6 -6 L 1 0 L -1 3 L -2 5 L -3 9 M 6 -6 L 0 0 L -2 3 L -3 5 L -4 9 M -5 -9 L -2 -12 L 0 -12 L 5 -9 M -4 -10 L -2 -11 L 0 -11 L 5 -9 L 7 -9 L 8 -10 L 9 -12","-10 11 M 1 -12 L -2 -11 L -3 -10 L -4 -8 L -4 -5 L -3 -3 L -1 -2 L 2 -2 L 6 -3 L 7 -4 L 8 -6 L 8 -9 L 7 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -2 -10 L -3 -8 L -3 -5 L -2 -3 L -1 -2 M 2 -2 L 5 -3 L 6 -4 L 7 -6 L 7 -9 L 6 -11 L 4 -12 M -1 -2 L -5 -1 L -7 1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 4 8 L 5 7 L 6 5 L 6 2 L 5 0 L 4 -1 L 2 -2 M -1 -2 L -4 -1 L -6 1 L -7 3 L -7 6 L -6 8 L -4 9 M 0 9 L 3 8 L 4 7 L 5 5 L 5 1 L 4 -1","-10 11 M 7 -5 L 6 -3 L 4 -1 L 2 0 L -1 0 L -3 -1 L -4 -2 L -5 -4 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 4 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -4 L 7 0 L 6 3 L 4 6 L 2 8 L -1 9 L -4 9 L -6 8 L -7 6 L -7 5 L -6 4 L -5 5 L -6 6 M -3 -1 L -4 -3 L -4 -7 L -3 -9 L -1 -11 L 1 -12 M 6 -11 L 7 -9 L 7 -4 L 6 0 L 5 3 L 3 6 L 1 8 L -1 9","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 7 L -3 8 L -2 9 L -1 8","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 1 -2 L -1 -1 L -1 1 L 0 2 L 2 2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-11 9 M -11 9 L -9 8 L -6 5 L -3 1 L 1 -6 L 4 -12 L 4 9 L 3 6 L 1 3 L -1 1 L -4 -1 L -6 -1 L -7 0 L -7 2 L -6 4 L -4 6 L -1 8 L 2 9 L 7 9","-12 11 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 6 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 5 -3 L 2 -2 M 1 -2 L 2 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9 L 0 9 L -2 8 L -3 6","-10 10 M 2 -6 L 2 -5 L 3 -4 L 5 -4 L 7 -5 L 8 -7 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -4 L -7 0 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 5 4","-11 12 M 2 -12 L 0 -11 L -1 -9 L -2 -5 L -3 1 L -4 4 L -5 6 L -7 8 L -9 9 L -11 9 L -12 8 L -12 6 L -11 5 L -9 5 L -7 6 L -5 8 L -2 9 L 1 9 L 4 8 L 6 6 L 8 2 L 9 -3 L 9 -7 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L 0 -10 L 0 -8 L 1 -5 L 3 -2 L 5 0 L 8 2 L 10 3","-10 10 M 4 -8 L 4 -7 L 5 -6 L 7 -6 L 8 -7 L 8 -9 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -4 -9 L -4 -6 L -3 -4 L -2 -3 L 1 -2 L -2 -2 L -5 -1 L -6 0 L -7 2 L -7 5 L -6 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 6 L 7 4","-10 10 M 0 -6 L -2 -6 L -4 -7 L -5 -9 L -4 -11 L -1 -12 L 2 -12 L 6 -11 L 9 -11 L 11 -12 M 6 -11 L 4 -4 L 2 2 L 0 6 L -2 8 L -4 9 L -6 9 L -8 8 L -9 6 L -9 4 L -8 3 L -6 3 L -4 4 M -1 -2 L 8 -2","-11 12 M -11 9 L -9 8 L -5 4 L -2 -1 L -1 -4 L 0 -8 L 0 -11 L -1 -12 L -2 -12 L -3 -11 L -4 -9 L -4 -6 L -3 -4 L -1 -3 L 3 -3 L 6 -4 L 7 -5 L 8 -7 L 8 -1 L 7 4 L 6 6 L 4 8 L 1 9 L -3 9 L -6 8 L -8 6 L -9 4 L -9 2","-12 12 M -5 -5 L -7 -6 L -8 -8 L -8 -9 L -7 -11 L -5 -12 L -4 -12 L -2 -11 L -1 -9 L -1 -7 L -2 -3 L -4 3 L -6 7 L -8 9 L -10 9 L -11 8 L -11 6 M -5 0 L 4 -3 L 6 -4 L 9 -6 L 11 -8 L 12 -10 L 12 -11 L 11 -12 L 10 -12 L 8 -10 L 6 -6 L 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-9 8 M 5 4 L 3 2 L 1 -1 L 0 -3 L -1 -6 L -1 -9 L 0 -11 L 1 -12 L 3 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -1 L 2 4 L 1 6 L -1 8 L -3 9 L -5 9 L -7 8 L -8 6 L -8 4 L -7 3 L -5 3 L -3 4","-8 7 M 2 12 L 0 9 L -2 4 L -3 -2 L -3 -8 L -2 -11 L 0 -12 L 2 -12 L 3 -11 L 4 -8 L 4 -5 L 3 0 L 0 9 L -2 15 L -3 18 L -4 20 L -6 21 L -7 20 L -7 18 L -6 15 L -4 12 L -2 10 L 1 8 L 5 6","-12 12 M -5 -5 L -7 -6 L -8 -8 L -8 -9 L -7 -11 L -5 -12 L -4 -12 L -2 -11 L -1 -9 L -1 -7 L -2 -3 L -4 3 L -6 7 L -8 9 L -10 9 L -11 8 L -11 6 M 12 -9 L 12 -11 L 11 -12 L 10 -12 L 8 -11 L 6 -9 L 4 -6 L 2 -4 L 0 -3 L -2 -3 M 0 -3 L 1 -1 L 1 6 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-9 10 M -5 0 L -3 0 L 1 -1 L 4 -3 L 6 -5 L 7 -7 L 7 -10 L 6 -12 L 4 -12 L 3 -11 L 2 -9 L 1 -4 L 0 1 L -1 4 L -2 6 L -4 8 L -6 9 L -8 9 L -9 8 L -9 6 L -8 5 L -6 5 L -4 6 L -1 8 L 2 9 L 4 9 L 7 8 L 9 6","-18 15 M -13 -5 L -15 -6 L -16 -8 L -16 -9 L -15 -11 L -13 -12 L -12 -12 L -10 -11 L -9 -9 L -9 -7 L -10 -2 L -11 2 L -13 9 M -11 2 L -8 -6 L -6 -10 L -5 -11 L -3 -12 L -2 -12 L 0 -11 L 1 -9 L 1 -7 L 0 -2 L -1 2 L -3 9 M -1 2 L 2 -6 L 4 -10 L 5 -11 L 7 -12 L 8 -12 L 10 -11 L 11 -9 L 11 -7 L 10 -2 L 8 5 L 8 8 L 9 9 L 10 9 L 12 8 L 13 7 L 15 4","-13 11 M -8 -5 L -10 -6 L -11 -8 L -11 -9 L -10 -11 L -8 -12 L -7 -12 L -5 -11 L -4 -9 L -4 -7 L -5 -2 L -6 2 L -8 9 M -6 2 L -3 -6 L -1 -10 L 0 -11 L 2 -12 L 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -2 L 4 5 L 4 8 L 5 9 L 6 9 L 8 8 L 9 7 L 11 4","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -4 L -7 0 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 1 L 8 -3 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 L 0 -10 L 0 -7 L 1 -4 L 3 -1 L 5 1 L 8 3 L 10 4","-12 13 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 8 -12 L 10 -11 L 11 -10 L 12 -8 L 12 -5 L 11 -3 L 10 -2 L 8 -1 L 5 -1 L 3 -2 L 2 -3","-10 12 M 3 -6 L 2 -4 L 1 -3 L -1 -2 L -3 -2 L -4 -4 L -4 -6 L -3 -9 L -1 -11 L 2 -12 L 5 -12 L 7 -11 L 8 -9 L 8 -5 L 7 -2 L 5 1 L 1 5 L -2 7 L -4 8 L -7 9 L -9 9 L -10 8 L -10 6 L -9 5 L -7 5 L -5 6 L -2 8 L 1 9 L 4 9 L 7 8 L 9 6","-12 13 M 1 -10 L 2 -9 L 2 -6 L 1 -2 L 0 1 L -1 3 L -3 6 L -5 8 L -7 9 L -8 9 L -9 8 L -9 5 L -8 0 L -7 -3 L -6 -5 L -4 -8 L -2 -10 L 0 -11 L 3 -12 L 7 -12 L 9 -11 L 10 -10 L 11 -8 L 11 -5 L 10 -3 L 9 -2 L 7 -1 L 4 -1 L 1 -2 L 2 -1 L 3 1 L 3 6 L 4 8 L 6 9 L 8 8 L 9 7 L 11 4","-10 10 M -10 9 L -8 8 L -6 6 L -3 2 L -1 -1 L 1 -5 L 2 -8 L 2 -11 L 1 -12 L 0 -12 L -1 -11 L -2 -9 L -2 -7 L -1 -5 L 1 -3 L 4 -1 L 6 1 L 7 3 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6 L -8 4 L -8 2","-10 9 M 0 -6 L -2 -6 L -4 -7 L -5 -9 L -4 -11 L -1 -12 L 2 -12 L 6 -11 L 9 -11 L 11 -12 M 6 -11 L 4 -4 L 2 2 L 0 6 L -2 8 L -4 9 L -6 9 L -8 8 L -9 6 L -9 4 L -8 3 L -6 3 L -4 4","-13 11 M -8 -5 L -10 -6 L -11 -8 L -11 -9 L -10 -11 L -8 -12 L -7 -12 L -5 -11 L -4 -9 L -4 -7 L -5 -3 L -6 0 L -7 4 L -7 6 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 3 3 L 6 -5 L 8 -12 M 6 -5 L 5 -1 L 4 5 L 4 8 L 5 9 L 6 9 L 8 8 L 9 7 L 11 4","-12 11 M -7 -5 L -9 -6 L -10 -8 L -10 -9 L -9 -11 L -7 -12 L -6 -12 L -4 -11 L -3 -9 L -3 -7 L -4 -3 L -5 0 L -6 4 L -6 7 L -5 9 L -3 9 L -1 8 L 2 5 L 4 2 L 6 -2 L 7 -5 L 8 -9 L 8 -11 L 7 -12 L 6 -12 L 5 -11 L 4 -9 L 4 -7 L 5 -4 L 7 -2 L 9 -1","-15 13 M -10 -5 L -12 -6 L -13 -8 L -13 -9 L -12 -11 L -10 -12 L -9 -12 L -7 -11 L -6 -9 L -6 -6 L -7 9 M 3 -12 L -7 9 M 3 -12 L 1 9 M 15 -12 L 13 -11 L 10 -8 L 7 -4 L 4 2 L 1 9","-12 12 M -4 -6 L -6 -6 L -7 -7 L -7 -9 L -6 -11 L -4 -12 L -2 -12 L 0 -11 L 1 -9 L 1 -6 L -1 3 L -1 6 L 0 8 L 2 9 L 4 9 L 6 8 L 7 6 L 7 4 L 6 3 L 4 3 M 11 -9 L 11 -11 L 10 -12 L 8 -12 L 6 -11 L 4 -9 L 2 -6 L -2 3 L -4 6 L -6 8 L -8 9 L -10 9 L -11 8 L -11 6","-12 11 M -7 -5 L -9 -6 L -10 -8 L -10 -9 L -9 -11 L -7 -12 L -6 -12 L -4 -11 L -3 -9 L -3 -7 L -4 -3 L -5 0 L -6 4 L -6 6 L -5 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 3 L 5 1 L 7 -5 M 9 -12 L 7 -5 L 4 5 L 2 11 L 0 16 L -2 20 L -4 21 L -5 20 L -5 18 L -4 15 L -2 12 L 1 9 L 4 7 L 9 4","-10 11 M 3 -6 L 2 -4 L 1 -3 L -1 -2 L -3 -2 L -4 -4 L -4 -6 L -3 -9 L -1 -11 L 2 -12 L 5 -12 L 7 -11 L 8 -9 L 8 -5 L 7 -2 L 5 2 L 2 5 L -2 8 L -4 9 L -7 9 L -8 8 L -8 6 L -7 5 L -4 5 L -2 6 L -1 7 L 0 9 L 0 12 L -1 15 L -2 17 L -4 20 L -6 21 L -7 20 L -7 18 L -6 15 L -4 12 L -1 9 L 2 7 L 8 4","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-8 8 M -2 -6 L 0 -9 L 2 -6 M -5 -3 L 0 -8 L 5 -3 M 0 -8 L 0 9","-8 8 M -8 11 L 8 11","-5 6 M 4 -12 L 2 -10 L 1 -8 L 1 -7 L 2 -6 L 3 -7 L 2 -8","-6 10 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 L 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-5 9 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 2 L -4 8 L -3 9 L -2 9 L 0 8 L 2 6 L 3 3 L 3 0 L 4 4 L 5 5 L 7 5 L 9 4","-5 6 M 2 2 L 2 1 L 1 0 L -1 0 L -3 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9 L 1 9 L 4 7 L 6 4","-6 10 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 6 L 8 -12 M 4 0 L 3 5 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-4 6 M -3 7 L -1 6 L 0 5 L 1 3 L 1 1 L 0 0 L -1 0 L -3 1 L -4 3 L -4 6 L -3 8 L -1 9 L 1 9 L 3 8 L 4 7 L 6 4","-3 5 M -3 4 L 1 -1 L 3 -4 L 4 -6 L 5 -9 L 5 -11 L 4 -12 L 2 -11 L 1 -9 L -1 -1 L -4 8 L -7 15 L -8 18 L -8 20 L -7 21 L -5 20 L -4 17 L -3 8 L -2 9 L 0 9 L 2 8 L 3 7 L 5 4","-6 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 M 4 0 L 2 7 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 3 9 L 6 7 L 9 4","-5 10 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 1 L -5 9 M -5 9 L -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-2 5 M 1 -5 L 1 -4 L 2 -4 L 2 -5 L 1 -5 M -2 4 L 0 0 L -2 6 L -2 8 L -1 9 L 0 9 L 2 8 L 3 7 L 5 4","-2 5 M 1 -5 L 1 -4 L 2 -4 L 2 -5 L 1 -5 M -2 4 L 0 0 L -6 18 L -7 20 L -9 21 L -10 20 L -10 18 L -9 15 L -6 12 L -3 10 L -1 9 L 2 7 L 5 4","-5 9 M -5 4 L -3 1 L 0 -4 L 1 -6 L 2 -9 L 2 -11 L 1 -12 L -1 -11 L -2 -9 L -3 -5 L -4 1 L -5 9 M -5 9 L -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 2 4 L -1 4 M -1 4 L 1 5 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-3 5 M -3 4 L -1 1 L 2 -4 L 3 -6 L 4 -9 L 4 -11 L 3 -12 L 1 -11 L 0 -9 L -1 -5 L -2 2 L -2 8 L -1 9 L 0 9 L 2 8 L 3 7 L 5 4","-13 12 M -13 4 L -11 1 L -9 0 L -8 1 L -8 2 L -9 6 L -10 9 M -9 6 L -8 4 L -6 1 L -4 0 L -2 0 L -1 1 L -1 2 L -2 6 L -3 9 M -2 6 L -1 4 L 1 1 L 3 0 L 5 0 L 6 1 L 6 3 L 5 6 L 5 8 L 6 9 L 7 9 L 9 8 L 10 7 L 12 4","-8 10 M -8 4 L -6 1 L -4 0 L -3 1 L -3 2 L -4 6 L -5 9 M -4 6 L -3 4 L -1 1 L 1 0 L 3 0 L 4 1 L 4 3 L 3 6 L 3 8 L 4 9 L 5 9 L 7 8 L 8 7 L 10 4","-6 8 M 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 L 3 5 L 3 3 L 2 1 L 0 0 L -1 1 L -1 3 L 0 5 L 2 6 L 5 6 L 7 5 L 8 4","-7 8 M -7 4 L -5 1 L -4 -1 L -5 3 L -11 21 M -5 3 L -4 1 L -2 0 L 0 0 L 2 1 L 3 3 L 3 5 L 2 7 L 1 8 L -1 9 M -5 8 L -3 9 L 0 9 L 3 8 L 5 7 L 8 4","-6 9 M 3 3 L 2 1 L 0 0 L -2 0 L -4 1 L -5 2 L -6 4 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 M 4 0 L 3 3 L 1 8 L -2 15 L -3 18 L -3 20 L -2 21 L 0 20 L 1 17 L 1 10 L 3 9 L 6 7 L 9 4","-5 8 M -5 4 L -3 1 L -2 -1 L -2 1 L 1 1 L 2 2 L 2 4 L 1 7 L 1 8 L 2 9 L 3 9 L 5 8 L 6 7 L 8 4","-4 7 M -4 4 L -2 1 L -1 -1 L -1 1 L 1 4 L 2 6 L 2 8 L 0 9 M -4 8 L -2 9 L 2 9 L 4 8 L 5 7 L 7 4","-3 6 M -3 4 L -1 1 L 1 -3 M 4 -12 L -2 6 L -2 8 L -1 9 L 1 9 L 3 8 L 4 7 L 6 4 M -2 -4 L 5 -4","-6 9 M -6 4 L -4 0 L -6 6 L -6 8 L -5 9 L -3 9 L -1 8 L 1 6 L 3 3 M 4 0 L 2 6 L 2 8 L 3 9 L 4 9 L 6 8 L 7 7 L 9 4","-6 9 M -6 4 L -4 0 L -5 5 L -5 8 L -4 9 L -3 9 L 0 8 L 2 6 L 3 3 L 3 0 M 3 0 L 4 4 L 5 5 L 7 5 L 9 4","-9 12 M -6 0 L -8 2 L -9 5 L -9 7 L -8 9 L -6 9 L -4 8 L -2 6 M 0 0 L -2 6 L -2 8 L -1 9 L 1 9 L 3 8 L 5 6 L 6 3 L 6 0 M 6 0 L 7 4 L 8 5 L 10 5 L 12 4","-8 8 M -8 4 L -6 1 L -4 0 L -2 0 L -1 1 L -1 8 L 0 9 L 3 9 L 6 7 L 8 4 M 5 1 L 4 0 L 2 0 L 1 1 L -3 8 L -4 9 L -6 9 L -7 8","-6 9 M -6 4 L -4 0 L -6 6 L -6 8 L -5 9 L -3 9 L -1 8 L 1 6 L 3 3 M 4 0 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 3 9 L 6 7 L 9 4","-6 8 M -6 4 L -4 1 L -2 0 L 0 0 L 2 2 L 2 4 L 1 6 L -1 8 L -4 9 L -2 10 L -1 12 L -1 15 L -2 18 L -3 20 L -5 21 L -6 20 L -6 18 L -5 15 L -2 12 L 1 10 L 5 7 L 8 4","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-7 7 M -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -4 L 1 -4 L 3 -5 L 4 -7 L 4 -9 L 3 -11 L 1 -12 L -1 -12"] -symbolic = ["-8 8","-14 14 M -14 0 L 14 0","-14 14 M -14 14 L 14 -14","0 0 M 0 -20 L 0 20","-14 14 M -14 -14 L 14 14","-14 14 M -14 0 L 14 0","-12 12 M -12 7 L 12 -7","-7 7 M -7 12 L 7 -12","0 0 M 0 -14 L 0 14","-7 7 M -7 -12 L 7 12","-12 12 M -12 -7 L 12 7","-7 7 M -7 0 L 7 0","-5 5 M -5 5 L 5 -5","0 0 M 0 -7 L 0 7","-5 5 M -5 -5 L 5 5","-11 0 M 0 -11 L -2 -11 L -5 -10 L -8 -8 L -10 -5 L -11 -2 L -11 0","-11 0 M -11 0 L -11 2 L -10 5 L -8 8 L -5 10 L -2 11 L 0 11","0 11 M 0 11 L 2 11 L 5 10 L 8 8 L 10 5 L 11 2 L 11 0","0 11 M 11 0 L 11 -2 L 10 -5 L 8 -8 L 5 -10 L 2 -11 L 0 -11","-14 14 M -14 -3 L -11 -1 L -7 1 L -2 2 L 2 2 L 7 1 L 11 -1 L 14 -3","-2 3 M 3 -14 L 1 -11 L -1 -7 L -2 -2 L -2 2 L -1 7 L 1 11 L 3 14","-3 2 M -3 -14 L -1 -11 L 1 -7 L 2 -2 L 2 2 L 1 7 L -1 11 L -3 14","-14 14 M -14 3 L -11 1 L -7 -1 L -2 -2 L 2 -2 L 7 -1 L 11 1 L 14 3","-7 7 M 0 -8 L 7 -4 L -7 4 L 0 8","-8 8 M -8 0 L -4 -7 L 4 7 L 8 0","-7 7 M -7 4 L -7 -4 L 7 4 L 7 -4","-8 8 M -6 6 L -8 -2 L 8 2 L 6 -6","-8 8 M -8 11 L -6 11 L -3 10 L -1 9 L 2 6 L 3 4 L 4 1 L 4 -3 L 3 -6 L 2 -8 L 1 -9 L -1 -9 L -2 -8 L -3 -6 L -4 -3 L -4 1 L -3 4 L -2 6 L 1 9 L 3 10 L 6 11 L 8 11","-9 11 M 11 8 L 11 6 L 10 3 L 9 1 L 6 -2 L 4 -3 L 1 -4 L -3 -4 L -6 -3 L -8 -2 L -9 -1 L -9 1 L -8 2 L -6 3 L -3 4 L 1 4 L 4 3 L 6 2 L 9 -1 L 10 -3 L 11 -6 L 11 -8","-8 8 M 8 -11 L 6 -11 L 3 -10 L 1 -9 L -2 -6 L -3 -4 L -4 -1 L -4 3 L -3 6 L -2 8 L -1 9 L 1 9 L 2 8 L 3 6 L 4 3 L 4 -1 L 3 -4 L 2 -6 L -1 -9 L -3 -10 L -6 -11 L -8 -11","-11 9 M -11 -8 L -11 -6 L -10 -3 L -9 -1 L -6 2 L -4 3 L -1 4 L 3 4 L 6 3 L 8 2 L 9 1 L 9 -1 L 8 -2 L 6 -3 L 3 -4 L -1 -4 L -4 -3 L -6 -2 L -9 1 L -10 3 L -11 6 L -11 8","-13 9 M -13 -2 L -12 0 L -10 2 L -8 3 L -5 4 L -1 4 L 3 3 L 6 1 L 8 -2 L 9 -4 L 8 -6 L 5 -6 L 1 -5 L -1 -4 L -4 -2 L -6 1 L -7 4 L -7 7 L -6 10 L -5 12","-13 7 M -13 2 L -10 4 L -7 5 L -2 5 L 1 4 L 4 2 L 6 -1 L 7 -4 L 7 -6 L 6 -7 L 4 -7 L 1 -6 L -2 -4 L -4 -1 L -5 2 L -5 7 L -4 10 L -2 13","-3 3 M -1 -3 L -3 -1 L -3 1 L -1 3 L 1 3 L 3 1 L 3 -1 L 1 -3 L -1 -3 M -1 -2 L -2 -1 L -2 1 L -1 2 L 1 2 L 2 1 L 2 -1 L 1 -2 L -1 -2 M 0 -1 L -1 0 L 0 1 L 1 0 L 0 -1","0 5 M 0 -5 L 1 -5 L 3 -4 L 4 -3 L 5 -1 L 5 1 L 4 3 L 3 4 L 1 5 L 0 5","-14 14 M -14 0 L -8 0 M -3 0 L 3 0 M 8 0 L 14 0","-14 14 M -14 3 L -14 -3 L 14 -3 L 14 3","-8 8 M 0 -14 L -8 0 M 0 -14 L 8 0","-14 14 M -14 0 L 14 0 M -8 7 L 8 7 M -2 14 L 2 14","-14 14 M -14 0 L 14 0 M -14 0 L 0 16 M 14 0 L 0 16","-7 7 M -1 -7 L -4 -6 L -6 -4 L -7 -1 L -7 1 L -6 4 L -4 6 L -1 7 L 1 7 L 4 6 L 6 4 L 7 1 L 7 -1 L 6 -4 L 4 -6 L 1 -7 L -1 -7","-6 6 M -6 -6 L -6 6 L 6 6 L 6 -6 L -6 -6","-7 7 M 0 -8 L -7 4 L 7 4 L 0 -8","-6 6 M 0 -10 L -6 0 L 0 10 L 6 0 L 0 -10","-8 8 M 0 -9 L -2 -3 L -8 -3 L -3 1 L -5 7 L 0 3 L 5 7 L 3 1 L 8 -3 L 2 -3 L 0 -9","-7 7 M 0 -7 L 0 7 M -7 0 L 7 0","-5 5 M -5 -5 L 5 5 M 5 -5 L -5 5","-5 5 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-4 4 M -1 -4 L -3 -3 L -4 -1 L -4 1 L -3 3 L -1 4 L 1 4 L 3 3 L 4 1 L 4 -1 L 3 -3 L 1 -4 L -1 -4 M -3 -1 L -3 1 M -2 -2 L -2 2 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -2 L 2 2 M 3 -1 L 3 1","-4 4 M -4 -4 L -4 4 L 4 4 L 4 -4 L -4 -4 M -3 -3 L -3 3 M -2 -3 L -2 3 M -1 -3 L -1 3 M 0 -3 L 0 3 M 1 -3 L 1 3 M 2 -3 L 2 3 M 3 -3 L 3 3","-5 5 M 0 -6 L -5 3 L 5 3 L 0 -6 M 0 -3 L -3 2 M 0 -3 L 3 2 M 0 0 L -1 2 M 0 0 L 1 2","-6 3 M -6 0 L 3 5 L 3 -5 L -6 0 M -3 0 L 2 3 M -3 0 L 2 -3 M 0 0 L 2 1 M 0 0 L 2 -1","-5 5 M 0 6 L 5 -3 L -5 -3 L 0 6 M 0 3 L 3 -2 M 0 3 L -3 -2 M 0 0 L 1 -2 M 0 0 L -1 -2","-3 6 M 6 0 L -3 -5 L -3 5 L 6 0 M 3 0 L -2 -3 M 3 0 L -2 3 M 0 0 L -2 -1 M 0 0 L -2 1","0 7 M 0 -7 L 0 7 M 0 -7 L 7 -4 L 0 -1 M 1 -5 L 4 -4 L 1 -3","-9 9 M 0 -11 L 0 4 M -5 -8 L 5 -2 M 5 -8 L -5 -2 M -9 4 L -6 10 M 9 4 L 6 10 M -9 4 L 9 4 M -6 10 L 6 10","-5 5 M 0 -6 L 0 6 M -3 -3 L 3 -3 M -5 3 L -3 5 L -1 6 L 1 6 L 3 5 L 5 3","-6 6 M 0 -6 L 0 6 M -6 -1 L -5 -3 L 5 -3 L 6 -1 M -2 5 L 2 5","-7 7 M -5 -4 L 5 6 M 5 -4 L -5 6 M -3 -6 L -6 -3 L -7 -1 M 3 -6 L 6 -3 L 7 -1","-9 9 M -4 -9 L -9 9 M 4 -9 L 9 9 M -5 -5 L 9 9 M 5 -5 L -9 9 M -4 -9 L 4 -9 M -5 -5 L 5 -5","-7 7 M -7 -12 L 7 12","-11 9 M -5 -8 L 1 4 M -7 -2 L 1 -6 M -11 10 L 9 10 L 9 0 L -11 10","-6 6 M -2 -6 L -2 -2 L -6 -2 L -6 2 L -2 2 L -2 6 L 2 6 L 2 2 L 6 2 L 6 -2 L 2 -2 L 2 -6 L -2 -6","-7 7 M 7 -2 L 6 -4 L 4 -6 L 1 -7 L -1 -7 L -4 -6 L -6 -4 L -7 -1 L -7 1 L -6 4 L -4 6 L -1 7 L 1 7 L 4 6 L 6 4 L 7 2 M 7 -2 L 5 -4 L 3 -5 L 1 -5 L -1 -4 L -2 -3 L -3 -1 L -3 1 L -2 3 L -1 4 L 1 5 L 3 5 L 5 4 L 7 2","-7 7 M 0 -8 L -7 4 L 7 4 L 0 -8 M 0 8 L 7 -4 L -7 -4 L 0 8","-11 11 M -2 -9 L -2 -11 L -1 -12 L 1 -12 L 2 -11 L 2 -9 M -11 8 L -10 6 L -8 4 L -7 2 L -6 -2 L -6 -7 L -5 -8 L -3 -9 L 3 -9 L 5 -8 L 6 -7 L 6 -2 L 7 2 L 8 4 L 10 6 L 11 8 M -11 8 L 11 8 M -1 8 L -2 9 L -1 10 L 1 10 L 2 9 L 1 8","-8 8 M 0 -5 L 0 1 M 0 1 L -1 10 M 0 1 L 1 10 M -1 10 L 1 10 M 0 -5 L -1 -8 L -2 -10 L -4 -11 M -1 -8 L -4 -11 M 0 -5 L 1 -8 L 2 -10 L 4 -11 M 1 -8 L 4 -11 M 0 -5 L -4 -7 L -6 -7 L -8 -5 M -2 -6 L -6 -6 L -8 -5 M 0 -5 L 4 -7 L 6 -7 L 8 -5 M 2 -6 L 6 -6 L 8 -5 M 0 -5 L -2 -4 L -3 -3 L -3 0 M 0 -5 L -2 -3 L -3 0 M 0 -5 L 2 -4 L 3 -3 L 3 0 M 0 -5 L 2 -3 L 3 0","-8 8 M 0 -9 L 0 -7 M 0 -4 L 0 -2 M 0 1 L 0 3 M 0 7 L -1 10 M 0 7 L 1 10 M -1 10 L 1 10 M 0 -11 L -1 -9 L -2 -8 M 0 -11 L 1 -9 L 2 -8 M -2 -8 L 0 -9 L 2 -8 M 0 -7 L -2 -4 L -4 -3 L -5 -4 M 0 -7 L 2 -4 L 4 -3 L 5 -4 M -4 -3 L -2 -3 L 0 -4 L 2 -3 L 4 -3 M 0 -2 L -2 1 L -4 2 L -6 2 L -7 0 L -7 1 L -6 2 M 0 -2 L 2 1 L 4 2 L 6 2 L 7 0 L 7 1 L 6 2 M -4 2 L -2 2 L 0 1 L 2 2 L 4 2 M 0 3 L -2 6 L -3 7 L -5 8 L -6 8 L -7 7 L -8 5 L -8 7 L -6 8 M 0 3 L 2 6 L 3 7 L 5 8 L 6 8 L 7 7 L 8 5 L 8 7 L 6 8 M -5 8 L -3 8 L 0 7 L 3 8 L 5 8","-8 8 M 0 7 L -1 10 M 0 7 L 1 10 M -1 10 L 1 10 M 0 7 L 3 8 L 6 8 L 8 6 L 8 3 L 7 2 L 5 2 L 7 0 L 8 -3 L 7 -5 L 5 -6 L 3 -5 L 4 -8 L 3 -10 L 1 -11 L -1 -11 L -3 -10 L -4 -8 L -3 -5 L -5 -6 L -7 -5 L -8 -3 L -7 0 L -5 2 L -7 2 L -8 3 L -8 6 L -6 8 L -3 8 L 0 7","-8 8 M 0 7 L -1 10 M 0 7 L 1 10 M -1 10 L 1 10 M 0 7 L 4 6 L 4 4 L 6 3 L 6 0 L 8 -1 L 8 -6 L 7 -9 L 6 -10 L 4 -10 L 2 -11 L -2 -11 L -4 -10 L -6 -10 L -7 -9 L -8 -6 L -8 -1 L -6 0 L -6 3 L -4 4 L -4 6 L 0 7","-9 9 M -9 -2 L -7 0 M -6 -7 L -4 -2 M 0 -11 L 0 -3 M 6 -7 L 4 -2 M 9 -2 L 7 0","-11 11 M -9 -9 L -8 -7 L -7 -3 L -7 3 L -8 7 L -9 9 M 9 -9 L 8 -7 L 7 -3 L 7 3 L 8 7 L 9 9 M -9 -9 L -7 -8 L -3 -7 L 3 -7 L 7 -8 L 9 -9 M -9 9 L -7 8 L -3 7 L 3 7 L 7 8 L 9 9","-12 12 M 0 0 L 0 9 L -1 10 M 0 4 L -1 10 M 0 -9 L -1 -10 L -3 -10 L -4 -9 L -4 -7 L -3 -4 L 0 0 M 0 -9 L 1 -10 L 3 -10 L 4 -9 L 4 -7 L 3 -4 L 0 0 M 0 0 L -4 -3 L -6 -4 L -8 -4 L -9 -3 L -9 -1 L -8 0 M 0 0 L 4 -3 L 6 -4 L 8 -4 L 9 -3 L 9 -1 L 8 0 M 0 0 L -4 3 L -6 4 L -8 4 L -9 3 L -9 1 L -8 0 M 0 0 L 4 3 L 6 4 L 8 4 L 9 3 L 9 1 L 8 0","-8 8 M 3 -9 L 2 -8 L 3 -7 L 4 -8 L 4 -9 L 3 -11 L 1 -12 L -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -3 L 4 0 M -3 -5 L 2 -2 L 4 0 L 5 2 L 5 4 L 4 6 L 2 8 M -2 -4 L -4 -2 L -5 0 L -5 2 L -4 4 L -2 6 L 3 9 M -4 4 L 1 7 L 3 9 L 4 11 L 4 13 L 3 15 L 1 16 L -1 16 L -3 15 L -4 13 L -4 12 L -3 11 L -2 12 L -3 13","-8 8 M 0 -12 L -1 -10 L 0 -8 L 1 -10 L 0 -12 M 0 -12 L 0 16 M 0 -1 L -1 2 L 0 16 L 1 2 L 0 -1 M -6 -5 L -4 -4 L -2 -5 L -4 -6 L -6 -5 M -6 -5 L 6 -5 M 2 -5 L 4 -4 L 6 -5 L 4 -6 L 2 -5","-8 8 M 0 -12 L -1 -10 L 0 -8 L 1 -10 L 0 -12 M 0 -12 L 0 2 M 0 -2 L -1 0 L 1 4 L 0 6 L -1 4 L 1 0 L 0 -2 M 0 2 L 0 16 M 0 12 L -1 14 L 0 16 L 1 14 L 0 12 M -6 -5 L -4 -4 L -2 -5 L -4 -6 L -6 -5 M -6 -5 L 6 -5 M 2 -5 L 4 -4 L 6 -5 L 4 -6 L 2 -5 M -6 9 L -4 10 L -2 9 L -4 8 L -6 9 M -6 9 L 6 9 M 2 9 L 4 10 L 6 9 L 4 8 L 2 9","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 7 L -10 8 L -9 9 L -8 8 L -9 7 M 9 7 L 8 8 L 9 9 L 10 8 L 9 7","-12 12 M 0 -10 L -4 -6 L -7 -2 L -8 1 L -8 3 L -7 5 L -5 6 L -3 6 L -1 5 L 0 3 M 0 -10 L 4 -6 L 7 -2 L 8 1 L 8 3 L 7 5 L 5 6 L 3 6 L 1 5 L 0 3 M 0 3 L -1 7 L -2 10 M 0 3 L 1 7 L 2 10 M -2 10 L 2 10","-12 12 M 0 -4 L -1 -7 L -2 -9 L -4 -10 L -5 -10 L -7 -9 L -8 -7 L -8 -3 L -7 0 L -6 2 L -4 5 L 0 10 M 0 -4 L 1 -7 L 2 -9 L 4 -10 L 5 -10 L 7 -9 L 8 -7 L 8 -3 L 7 0 L 6 2 L 4 5 L 0 10","-12 12 M 0 -11 L -2 -8 L -6 -3 L -9 0 M 0 -11 L 2 -8 L 6 -3 L 9 0 M -9 0 L -6 3 L -2 8 L 0 11 M 9 0 L 6 3 L 2 8 L 0 11","-12 12 M 0 2 L 2 5 L 4 6 L 6 6 L 8 5 L 9 3 L 9 1 L 8 -1 L 6 -2 L 4 -2 L 1 -1 M 1 -1 L 3 -3 L 4 -5 L 4 -7 L 3 -9 L 1 -10 L -1 -10 L -3 -9 L -4 -7 L -4 -5 L -3 -3 L -1 -1 M -1 -1 L -4 -2 L -6 -2 L -8 -1 L -9 1 L -9 3 L -8 5 L -6 6 L -4 6 L -2 5 L 0 2 M 0 2 L -1 7 L -2 10 M 0 2 L 1 7 L 2 10 M -2 10 L 2 10","-9 9 M 4 -39 L 1 -37 L -1 -35 L -2 -33 L -3 -30 L -3 -26 L -2 -22 L 2 -14 L 3 -11 L 3 -8 L 2 -5 L 0 -2 M 1 -37 L -1 -34 L -2 -30 L -2 -26 L -1 -23 L 3 -15 L 4 -11 L 4 -8 L 3 -5 L 0 -2 L -4 0 L 0 2 L 3 5 L 4 8 L 4 11 L 3 15 L -1 23 L -2 26 L -2 30 L -1 34 L 1 37 M 0 2 L 2 5 L 3 8 L 3 11 L 2 14 L -2 22 L -3 26 L -3 30 L -2 33 L -1 35 L 1 37 L 4 39","-9 9 M -4 -39 L -1 -37 L 1 -35 L 2 -33 L 3 -30 L 3 -26 L 2 -22 L -2 -14 L -3 -11 L -3 -8 L -2 -5 L 0 -2 M -1 -37 L 1 -34 L 2 -30 L 2 -26 L 1 -23 L -3 -15 L -4 -11 L -4 -8 L -3 -5 L 0 -2 L 4 0 L 0 2 L -3 5 L -4 8 L -4 11 L -3 15 L 1 23 L 2 26 L 2 30 L 1 34 L -1 37 M 0 2 L -2 5 L -3 8 L -3 11 L -2 14 L 2 22 L 3 26 L 3 30 L 2 33 L 1 35 L -1 37 L -4 39","-9 9 M 4 -36 L 1 -33 L -1 -30 L -3 -26 L -4 -21 L -4 -15 L -3 -9 L -2 -5 L 1 6 L 2 10 L 3 16 L 3 21 L 2 26 L 1 29 L -1 33 M 1 -33 L -1 -29 L -2 -26 L -3 -21 L -3 -16 L -2 -10 L -1 -6 L 2 5 L 3 9 L 4 15 L 4 21 L 3 26 L 1 30 L -1 33 L -4 36","-9 9 M -4 -36 L -1 -33 L 1 -30 L 3 -26 L 4 -21 L 4 -15 L 3 -9 L 2 -5 L -1 6 L -2 10 L -3 16 L -3 21 L -2 26 L -1 29 L 1 33 M -1 -33 L 1 -29 L 2 -26 L 3 -21 L 3 -16 L 2 -10 L 1 -6 L -2 5 L -3 9 L -4 15 L -4 21 L -3 26 L -1 30 L 1 33 L 4 36","-27 8 M -24 0 L -17 0 L 0 29 M -18 0 L -1 29 M -19 0 L 0 32 M 8 -48 L 4 -8 L 0 32","-9 9 M 2 -5 L 4 -4 L 6 -2 L 6 -3 L 5 -4 L 2 -5 L -1 -5 L -4 -4 L -5 -3 L -6 -1 L -6 1 L -5 3 L -3 5 L 1 8 M -1 -5 L -3 -4 L -4 -3 L -5 -1 L -5 1 L -4 3 L 1 8 L 2 10 L 2 12 L 1 13 L -1 13","-11 11 M -6 -5 L -7 -4 L -8 -2 L -8 0 L -7 3 L -3 7 L -2 9 M -8 0 L -7 2 L -3 6 L -2 9 L -2 11 L -3 14 L -5 16 L -6 16 L -7 15 L -8 13 L -8 10 L -7 6 L -5 2 L -3 -1 L 0 -4 L 2 -5 L 4 -5 L 7 -4 L 8 -2 L 8 2 L 7 6 L 5 8 L 3 9 L 2 9 L 1 8 L 1 6 L 2 5 L 3 6 L 2 7 M 4 -5 L 6 -4 L 7 -2 L 7 2 L 6 6 L 5 8","-13 13 M 7 -11 L 6 -10 L 7 -9 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -4 -7 L -5 -4 L -6 0 L -8 9 L -9 13 L -10 15 M 2 -12 L 0 -11 L -2 -9 L -3 -7 L -4 -4 L -6 5 L -7 9 L -8 12 L -9 14 L -10 15 L -12 16 L -14 16 L -15 15 L -15 14 L -14 13 L -13 14 L -14 15 M 13 -11 L 12 -10 L 13 -9 L 14 -10 L 14 -11 L 13 -12 L 11 -12 L 9 -11 L 8 -10 L 7 -8 L 6 -5 L 3 9 L 2 13 L 1 15 M 11 -12 L 9 -10 L 8 -8 L 7 -4 L 5 5 L 4 9 L 3 12 L 2 14 L 1 15 L -1 16 L -3 16 L -4 15 L -4 14 L -3 13 L -2 14 L -3 15 M -9 -5 L 12 -5","-12 12 M 9 -11 L 8 -10 L 9 -9 L 10 -10 L 9 -11 L 6 -12 L 3 -12 L 0 -11 L -2 -9 L -3 -7 L -4 -4 L -5 0 L -7 9 L -8 13 L -9 15 M 3 -12 L 1 -11 L -1 -9 L -2 -7 L -3 -4 L -5 5 L -6 9 L -7 12 L -8 14 L -9 15 L -11 16 L -13 16 L -14 15 L -14 14 L -13 13 L -12 14 L -13 15 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9 L 8 9 L 10 7 L 11 5 M 8 -5 L 6 2 L 5 6 L 5 8 L 6 9 M -8 -5 L 8 -5","-12 12 M 7 -11 L 6 -10 L 7 -9 L 8 -10 L 8 -11 L 6 -12 M 10 -12 L 3 -12 L 0 -11 L -2 -9 L -3 -7 L -4 -4 L -5 0 L -7 9 L -8 13 L -9 15 M 3 -12 L 1 -11 L -1 -9 L -2 -7 L -3 -4 L -5 5 L -6 9 L -7 12 L -8 14 L -9 15 L -11 16 L -13 16 L -14 15 L -14 14 L -13 13 L -12 14 L -13 15 M 9 -12 L 5 2 L 4 6 L 4 8 L 5 9 L 8 9 L 10 7 L 11 5 M 10 -12 L 6 2 L 5 6 L 5 8 L 6 9 M -8 -5 L 7 -5","-18 17 M 2 -11 L 1 -10 L 2 -9 L 3 -10 L 2 -11 L 0 -12 L -3 -12 L -6 -11 L -8 -9 L -9 -7 L -10 -4 L -11 0 L -13 9 L -14 13 L -15 15 M -3 -12 L -5 -11 L -7 -9 L -8 -7 L -9 -4 L -11 5 L -12 9 L -13 12 L -14 14 L -15 15 L -17 16 L -19 16 L -20 15 L -20 14 L -19 13 L -18 14 L -19 15 M 14 -11 L 13 -10 L 14 -9 L 15 -10 L 14 -11 L 11 -12 L 8 -12 L 5 -11 L 3 -9 L 2 -7 L 1 -4 L 0 0 L -2 9 L -3 13 L -4 15 M 8 -12 L 6 -11 L 4 -9 L 3 -7 L 2 -4 L 0 5 L -1 9 L -2 12 L -3 14 L -4 15 L -6 16 L -8 16 L -9 15 L -9 14 L -8 13 L -7 14 L -8 15 M 12 -5 L 10 2 L 9 6 L 9 8 L 10 9 L 13 9 L 15 7 L 16 5 M 13 -5 L 11 2 L 10 6 L 10 8 L 11 9 M -14 -5 L 13 -5","-18 17 M 2 -11 L 1 -10 L 2 -9 L 3 -10 L 2 -11 L 0 -12 L -3 -12 L -6 -11 L -8 -9 L -9 -7 L -10 -4 L -11 0 L -13 9 L -14 13 L -15 15 M -3 -12 L -5 -11 L -7 -9 L -8 -7 L -9 -4 L -11 5 L -12 9 L -13 12 L -14 14 L -15 15 L -17 16 L -19 16 L -20 15 L -20 14 L -19 13 L -18 14 L -19 15 M 12 -11 L 11 -10 L 12 -9 L 13 -10 L 13 -11 L 11 -12 M 15 -12 L 8 -12 L 5 -11 L 3 -9 L 2 -7 L 1 -4 L 0 0 L -2 9 L -3 13 L -4 15 M 8 -12 L 6 -11 L 4 -9 L 3 -7 L 2 -4 L 0 5 L -1 9 L -2 12 L -3 14 L -4 15 L -6 16 L -8 16 L -9 15 L -9 14 L -8 13 L -7 14 L -8 15 M 14 -12 L 10 2 L 9 6 L 9 8 L 10 9 L 13 9 L 15 7 L 16 5 M 15 -12 L 11 2 L 10 6 L 10 8 L 11 9 M -14 -5 L 12 -5","-6 7 M -5 -1 L -4 -3 L -2 -5 L 1 -5 L 2 -4 L 2 -1 L 0 5 L 0 8 L 1 9 M 0 -5 L 1 -4 L 1 -1 L -1 5 L -1 8 L 0 9 L 3 9 L 5 7 L 6 5","-6 6 M 0 -6 L -4 5 L 6 -2 L -6 -2 L 4 5 L 0 -6 M 0 0 L 0 -6 M 0 0 L -6 -2 M 0 0 L -4 5 M 0 0 L 4 5 M 0 0 L 6 -2","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3"] -timesg = ["-8 8","-5 5 M 0 -12 L -1 -10 L 0 2 L 1 -10 L 0 -12 M 0 -10 L 0 -4 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-8 8 M -4 -12 L -5 -5 M -3 -12 L -5 -5 M 4 -12 L 3 -5 M 5 -12 L 3 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 6 -9 L 5 -8 L 6 -7 L 7 -8 L 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 7 2 M -7 -7 L -5 -5 L -3 -4 L 3 -2 L 5 -1 L 6 0 L 7 2 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6 L -7 5 L -6 4 L -5 5 L -6 6","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 13 M 9 -4 L 8 -3 L 9 -2 L 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -5 9 L -8 8 L -9 6 L -9 3 L -8 1 L -2 -3 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 8 9 L 9 9 L 10 8 L 10 7 M -5 9 L -7 8 L -8 6 L -8 3 L -7 1 L -5 -1 M -5 -7 L -4 -5 L 4 6 L 6 8 L 8 9","-4 4 M 0 -12 L -1 -5 M 1 -12 L -1 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 L 4 16 M 3 -16 L 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 L -3 16 M -4 -16 L -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -4 -10 L -5 -8 L -6 -3 L -6 0 L -5 5 L -4 7 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 5 L 6 0 L 6 -3 L 5 -8 L 4 -10 L 3 -11 L 1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9 M 0 -11 L 0 9 M -4 9 L 5 9","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 3 -2 L -2 0 L -4 1 L -6 3 L -7 6 L -7 9 M 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 2 -2 L -2 0 M -7 7 L -6 6 L -4 6 L 1 8 L 4 8 L 6 7 L 7 6 M -4 6 L 1 9 L 5 9 L 6 8 L 7 6 L 7 4","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 L -1 -3 M 2 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -4 L 2 -3 M 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 5 -1 L 6 2 L 6 5 L 5 7 L 4 8 L 2 9","-10 10 M 2 -10 L 2 9 M 3 -12 L 3 9 M 3 -12 L -8 3 L 8 3 M -1 9 L 6 9","-10 10 M -5 -12 L -7 -2 M -7 -2 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -5 -12 L 5 -12 M -5 -11 L 0 -11 L 5 -12","-10 10 M 5 -9 L 4 -8 L 5 -7 L 6 -8 L 6 -9 L 5 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2 M 0 -12 L -2 -11 L -4 -9 L -5 -7 L -6 -3 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 2 L 5 -1 L 3 -3 L 1 -4","-10 10 M -7 -12 L -7 -6 M -7 -8 L -6 -10 L -4 -12 L -2 -12 L 3 -9 L 5 -9 L 6 -10 L 7 -12 M -6 -10 L -4 -11 L -2 -11 L 3 -9 M 7 -12 L 7 -9 L 6 -6 L 2 -1 L 1 1 L 0 4 L 0 9 M 6 -6 L 1 -1 L 0 1 L -1 4 L -1 9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 6 -6 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -2 -12 L -4 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -3 M 2 -3 L 4 -4 L 5 -6 L 5 -9 L 4 -11 L 2 -12 M -2 -3 L -5 -2 L -6 -1 L -7 1 L -7 5 L -6 7 L -5 8 L -2 9 L 2 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 2 -3 M -2 -3 L -4 -2 L -5 -1 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 M 2 9 L 4 8 L 5 7 L 6 5 L 6 1 L 5 -1 L 4 -2 L 2 -3","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 0 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 5 L -5 6 M -1 1 L -3 0 L -5 -2 L -6 -5 L -6 -6 L -5 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 5 -9 L 6 -6 L 6 0 L 5 4 L 4 6 L 2 8 L 0 9","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -5 -8 L -4 -7 L -5 -6 L -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 1 -12 L 3 -11 L 4 -10 L 5 -8 L 5 -6 L 4 -4 L 2 -2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 0 -12 L -7 9 M 0 -12 L 7 9 M 0 -9 L 6 9 M -5 3 L 4 3 M -9 9 L -3 9 M 3 9 L 9 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 3 -2 M -5 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 3 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9","-10 10 M -7 -12 L 6 9 M -6 -12 L 7 9 M 7 -12 L -7 9 M -9 -12 L -3 -12 M 3 -12 L 9 -12 M -9 9 L -3 9 M 3 9 L 9 9","-10 10 M 0 -12 L -8 9 M 0 -12 L 8 9 M 0 -9 L 7 9 M -7 8 L 7 8 M -8 9 L 8 9","-11 10 M -6 -12 L -6 9 M -5 -12 L -5 9 M 1 -6 L 1 2 M -9 -12 L 7 -12 L 7 -6 L 6 -12 M -5 -2 L 1 -2 M -9 9 L 7 9 L 7 3 L 6 9","-10 11 M 0 -12 L 0 9 M 1 -12 L 1 9 M -2 -7 L -5 -6 L -6 -5 L -7 -3 L -7 0 L -6 2 L -5 3 L -2 4 L 3 4 L 6 3 L 7 2 L 8 0 L 8 -3 L 7 -5 L 6 -6 L 3 -7 L -2 -7 M -2 -7 L -4 -6 L -5 -5 L -6 -3 L -6 0 L -5 2 L -4 3 L -2 4 M 3 4 L 5 3 L 6 2 L 7 0 L 7 -3 L 6 -5 L 5 -6 L 3 -7 M -3 -12 L 4 -12 M -3 9 L 4 9","-9 9 M -4 -12 L -4 9 M -3 -12 L -3 9 M -7 -12 L 8 -12 L 8 -6 L 7 -12 M -7 9 L 0 9","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M -6 -2 L 6 -2 M -10 9 L -3 9 M 3 9 L 10 9","-5 6 M 0 -12 L 0 9 M 1 -12 L 1 9 M -3 -12 L 4 -12 M -3 9 L 4 9","-2 3 M 0 -1 L 0 0 L 1 0 L 1 -1 L 0 -1","-12 10 M -7 -12 L -7 9 M -6 -12 L -6 9 M 7 -12 L -6 1 M -1 -3 L 7 9 M -2 -3 L 6 9 M -10 -12 L -3 -12 M 3 -12 L 9 -12 M -10 9 L -3 9 M 3 9 L 9 9","-10 10 M 0 -12 L -7 9 M 0 -12 L 7 9 M 0 -9 L 6 9 M -9 9 L -3 9 M 3 9 L 9 9","-12 13 M -7 -12 L -7 9 M -6 -12 L 0 6 M -7 -12 L 0 9 M 7 -12 L 0 9 M 7 -12 L 7 9 M 8 -12 L 8 9 M -10 -12 L -6 -12 M 7 -12 L 11 -12 M -10 9 L -4 9 M 4 9 L 11 9","-11 12 M -6 -12 L -6 9 M -5 -12 L 7 7 M -5 -10 L 7 9 M 7 -12 L 7 9 M -9 -12 L -5 -12 M 4 -12 L 10 -12 M -9 9 L -3 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 0 L -6 4 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 4 L 7 0 L 7 -3 L 6 -7 L 5 -9 L 3 -11 L 1 -12","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L 10 -12 M -10 9 L -3 9 M 3 9 L 10 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 0 L -6 4 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 4 L 7 0 L 7 -3 L 6 -7 L 5 -9 L 3 -11 L 1 -12 M -3 -5 L -3 2 M 3 -5 L 3 2 M -3 -2 L 3 -2 M -3 -1 L 3 -1","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -5 -1 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 3 -1 M -9 9 L -2 9","-10 11 M -7 -12 L 0 -2 L -8 9 M -8 -12 L -1 -2 M -8 -12 L 7 -12 L 8 -6 L 6 -12 M -7 8 L 6 8 M -8 9 L 7 9 L 8 3 L 6 9","-9 10 M 0 -12 L 0 9 M 1 -12 L 1 9 M -6 -12 L -7 -6 L -7 -12 L 8 -12 L 8 -6 L 7 -12 M -3 9 L 4 9","-9 10 M -7 -7 L -7 -9 L -6 -11 L -5 -12 L -3 -12 L -2 -11 L -1 -9 L 0 -5 L 0 9 M -7 -9 L -5 -11 L -3 -11 L -1 -9 M 8 -7 L 8 -9 L 7 -11 L 6 -12 L 4 -12 L 3 -11 L 2 -9 L 1 -5 L 1 9 M 8 -9 L 6 -11 L 4 -11 L 2 -9 M -3 9 L 4 9","-7 7 M -1 -12 L -3 -11 L -4 -9 L -4 -7 L -3 -5 L -1 -4 L 1 -4 L 3 -5 L 4 -7 L 4 -9 L 3 -11 L 1 -12 L -1 -12","-11 11 M -8 6 L -7 9 L -3 9 L -5 5 L -7 1 L -8 -2 L -8 -6 L -7 -9 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 7 -9 L 8 -6 L 8 -2 L 7 1 L 5 5 L 3 9 L 7 9 L 8 6 M -5 5 L -6 2 L -7 -2 L -7 -6 L -6 -9 L -4 -11 L -2 -12 M 2 -12 L 4 -11 L 6 -9 L 7 -6 L 7 -2 L 6 2 L 5 5 M -7 8 L -4 8 M 4 8 L 7 8","-11 11 M -7 -13 L -8 -8 M 8 -13 L 7 -8 M -3 -4 L -4 1 M 4 -4 L 3 1 M -7 5 L -8 10 M 8 5 L 7 10 M -7 -11 L 7 -11 M -7 -10 L 7 -10 M -3 -2 L 3 -2 M -3 -1 L 3 -1 M -7 7 L 7 7 M -7 8 L 7 8","-11 12 M 0 -12 L 0 9 M 1 -12 L 1 9 M -9 -5 L -8 -6 L -6 -5 L -5 -1 L -4 1 L -3 2 L -1 3 M -8 -6 L -7 -5 L -6 -1 L -5 1 L -4 2 L -1 3 L 2 3 L 5 2 L 6 1 L 7 -1 L 8 -5 L 9 -6 M 2 3 L 4 2 L 5 1 L 6 -1 L 7 -5 L 9 -6 L 10 -5 M -3 -12 L 4 -12 M -3 9 L 4 9","-10 10 M 6 -12 L -7 9 M 7 -12 L -6 9 M -6 -12 L -7 -6 L -7 -12 L 7 -12 M -7 9 L 7 9 L 7 3 L 6 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-11 12 M -1 -5 L -4 -4 L -6 -2 L -7 0 L -8 3 L -8 6 L -7 8 L -4 9 L -2 9 L 0 8 L 3 5 L 5 2 L 7 -2 L 8 -5 M -1 -5 L -3 -4 L -5 -2 L -6 0 L -7 3 L -7 6 L -6 8 L -4 9 M -1 -5 L 1 -5 L 3 -4 L 4 -2 L 6 6 L 7 8 L 8 9 M 1 -5 L 2 -4 L 3 -2 L 5 6 L 6 8 L 8 9 L 9 9","-11 10 M 2 -12 L -1 -11 L -3 -9 L -5 -5 L -6 -2 L -7 2 L -8 8 L -9 16 M 2 -12 L 0 -11 L -2 -9 L -4 -5 L -5 -2 L -6 2 L -7 8 L -8 16 M 2 -12 L 4 -12 L 6 -11 L 7 -10 L 7 -7 L 6 -5 L 5 -4 L 2 -3 L -2 -3 M 4 -12 L 6 -10 L 6 -7 L 5 -5 L 4 -4 L 2 -3 M -2 -3 L 2 -2 L 4 0 L 5 2 L 5 5 L 4 7 L 3 8 L 0 9 L -2 9 L -4 8 L -5 7 L -6 4 M -2 -3 L 1 -2 L 3 0 L 4 2 L 4 5 L 3 7 L 2 8 L 0 9","-9 9 M -7 -5 L -5 -5 L -3 -4 L -2 -2 L 3 13 L 4 15 L 5 16 M -5 -5 L -4 -4 L -3 -2 L 2 13 L 3 15 L 5 16 L 7 16 M 8 -5 L 7 -3 L 5 0 L -5 11 L -7 14 L -8 16","-9 10 M 4 -4 L 2 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 L 6 2 L 6 -1 L 5 -3 L 1 -8 L 0 -10 L 0 -12 L 1 -13 L 3 -13 L 5 -12 L 7 -10 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 5 L 5 2 L 5 -2 L 4 -4 L 2 -7 L 1 -9 L 1 -11 L 2 -12 L 4 -12 L 7 -10","-9 9 M 6 -2 L 4 -4 L 2 -5 L -2 -5 L -4 -4 L -4 -2 L -2 0 L 1 1 M -2 -5 L -3 -4 L -3 -2 L -1 0 L 1 1 M 1 1 L -4 2 L -6 4 L -6 6 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 M 1 1 L -3 2 L -5 4 L -5 6 L -4 8 L -2 9","-11 11 M -3 -4 L -5 -3 L -7 -1 L -8 2 L -8 5 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 5 6 L 7 3 L 8 0 L 8 -3 L 6 -5 L 4 -5 L 2 -3 L 0 1 L -2 6 L -5 16 M -8 5 L -6 7 L -4 8 L -1 8 L 2 7 L 5 5 L 7 3 M 8 -3 L 6 -4 L 4 -4 L 2 -2 L 0 1 L -2 7 L -4 16","-10 10 M -9 -2 L -7 -4 L -5 -5 L -3 -5 L -1 -4 L 0 -3 L 1 0 L 1 4 L 0 8 L -3 16 M -8 -3 L -6 -4 L -2 -4 L 0 -3 M 8 -5 L 7 -2 L 6 0 L 1 7 L -2 12 L -4 16 M 7 -5 L 6 -2 L 5 0 L 1 7","-11 11 M -10 -1 L -9 -3 L -7 -5 L -4 -5 L -3 -4 L -3 -2 L -4 2 L -6 9 M -5 -5 L -4 -4 L -4 -2 L -5 2 L -7 9 M -4 2 L -2 -2 L 0 -4 L 2 -5 L 4 -5 L 6 -4 L 7 -3 L 7 0 L 6 5 L 3 16 M 4 -5 L 6 -3 L 6 0 L 5 5 L 2 16","-6 6 M 0 -5 L -2 2 L -3 6 L -3 8 L -2 9 L 1 9 L 3 7 L 4 5 M 1 -5 L -1 2 L -2 6 L -2 8 L -1 9","-11 11 M -7 -7 L 7 7 M 7 -7 L -7 7","-10 10 M -4 -5 L -8 9 M -3 -5 L -7 9 M 6 -5 L 7 -4 L 8 -4 L 7 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 L -5 1 M -3 1 L -1 2 L 1 8 L 2 9 M -3 1 L -2 2 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5","-10 10 M -7 -12 L -5 -12 L -3 -11 L -2 -10 L -1 -8 L 5 6 L 6 8 L 7 9 M -5 -12 L -3 -10 L -2 -8 L 4 6 L 5 8 L 7 9 L 8 9 M 0 -5 L -8 9 M 0 -5 L -7 9","-12 11 M -5 -5 L -11 16 M -4 -5 L -10 16 M -5 -2 L -6 4 L -6 7 L -4 9 L -2 9 L 0 8 L 2 6 L 4 3 M 6 -5 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 7 -5 L 4 6 L 4 8 L 5 9","-10 10 M -4 -5 L -6 9 M -3 -5 L -4 1 L -5 6 L -6 9 M 7 -5 L 6 -1 L 4 3 M 8 -5 L 7 -2 L 6 0 L 4 3 L 2 5 L -1 7 L -3 8 L -6 9 M -7 -5 L -3 -5","-9 9 M 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 L 6 2 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L 0 -5 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 5 L 5 2 L 5 -2 L 4 -4","-11 11 M -2 -4 L -6 9 M -2 -4 L -5 9 M 4 -4 L 4 9 M 4 -4 L 5 9 M -9 -2 L -7 -4 L -4 -5 L 9 -5 M -9 -2 L -7 -3 L -4 -4 L 9 -4","-12 11 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -2 L -5 3 L -5 6 L -4 8 L -3 9 M -6 -5 L -5 -4 L -5 -2 L -6 3 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -5 L 7 -9 L 6 -11 L 4 -12 L 2 -12 L 0 -10 L 0 -8 L 1 -5 L 3 -2 L 5 0 L 8 2 M 1 8 L 3 5 L 4 3 L 5 0 L 6 -5 L 6 -9 L 5 -11 L 4 -12","-10 9 M -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 L 6 2 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -10 16 M 0 9 L 2 8 L 4 5 L 5 2 L 5 -2 L 4 -4 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -9 16","-10 11 M 9 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 5 L 5 2 L 5 -1 L 4 -3 L 3 -4 L 1 -5 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8 M -1 9 L 1 8 L 3 5 L 4 2 L 4 -2 L 3 -4 M 3 -4 L 9 -4","-10 10 M 1 -4 L -2 9 M 1 -4 L -1 9 M -8 -2 L -6 -4 L -3 -5 L 8 -5 M -8 -2 L -6 -3 L -3 -4 L 8 -4","-10 10 M -9 -1 L -8 -3 L -6 -5 L -3 -5 L -2 -4 L -2 -2 L -4 4 L -4 7 L -2 9 M -4 -5 L -3 -4 L -3 -2 L -5 4 L -5 7 L -4 8 L -2 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 7 -3 L 6 -5 L 5 -4 L 6 -3 L 7 0 M 6 3 L 7 -3","-13 13 M 0 -9 L -1 -8 L 0 -7 L 1 -8 L 0 -9 M -9 0 L 9 0 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-12 11 M -8 -1 L -6 -3 L -3 -4 L -4 -5 L -6 -4 L -8 -1 L -9 2 L -9 5 L -8 8 L -7 9 L -5 9 L -3 8 L -1 5 L 0 2 M -9 5 L -8 7 L -7 8 L -5 8 L -3 7 L -1 5 M -1 2 L -1 5 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 L 8 2 L 8 -1 L 7 -4 L 6 -5 L 5 -4 L 7 -3 L 8 -1 M -1 5 L 0 7 L 1 8 L 3 8 L 5 7 L 7 5","-9 8 M 2 -12 L 0 -11 L -1 -10 L -1 -9 L 0 -8 L 3 -7 L 6 -7 M 3 -7 L -1 -6 L -3 -5 L -4 -3 L -4 -1 L -2 1 L 1 2 L 4 2 M 3 -7 L 0 -6 L -2 -5 L -3 -3 L -3 -1 L -1 1 L 1 2 M 1 2 L -3 3 L -5 4 L -6 6 L -6 8 L -4 10 L 1 12 L 2 13 L 2 15 L 0 16 L -2 16 M 1 2 L -2 3 L -4 4 L -5 6 L -5 8 L -3 10 L 1 12","-12 11 M 3 -12 L -3 16 M 4 -12 L -4 16 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -2 L -5 3 L -5 6 L -3 8 L 0 8 L 2 7 L 5 4 L 7 1 M -6 -5 L -5 -4 L -5 -2 L -6 3 L -6 6 L -5 8 L -3 9 L 0 9 L 2 8 L 4 6 L 6 3 L 7 1 L 9 -5","-9 9 M 2 -12 L 0 -11 L -1 -10 L -1 -9 L 0 -8 L 3 -7 L 8 -7 L 8 -8 L 5 -7 L 1 -5 L -2 -3 L -5 0 L -6 3 L -6 5 L -5 7 L -2 9 L 1 11 L 2 13 L 2 15 L 1 16 L -1 16 L -2 15 M 3 -6 L -1 -3 L -4 0 L -5 3 L -5 5 L -4 7 L -2 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -timesi = ["-8 8","-5 6 M 3 -12 L 2 -11 L 0 1 M 3 -11 L 0 1 M 3 -12 L 4 -11 L 0 1 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-9 9 M -2 -12 L -4 -5 M -1 -12 L -4 -5 M 7 -12 L 5 -5 M 8 -12 L 5 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 11 M 2 -16 L -6 13 M 7 -16 L -1 13 M 8 -8 L 7 -7 L 8 -6 L 9 -7 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -7 L -4 -5 L -3 -4 L 4 0 L 6 2 M -5 -7 L -3 -5 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 13 M 9 -4 L 8 -3 L 9 -2 L 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -5 9 L -8 8 L -9 6 L -9 3 L -8 1 L -2 -3 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 8 9 L 9 9 L 10 8 L 10 7 M -5 9 L -7 8 L -8 6 L -8 3 L -7 1 L -5 -1 M -5 -7 L -4 -5 L 4 6 L 6 8 L 8 9","-4 5 M 3 -12 L 1 -5 M 4 -12 L 1 -5","-7 8 M 8 -16 L 4 -13 L 1 -10 L -1 -7 L -3 -3 L -4 2 L -4 6 L -3 11 L -2 14 L -1 16 M 4 -13 L 1 -9 L -1 -5 L -2 -2 L -3 3 L -3 8 L -2 13 L -1 16","-8 7 M 1 -16 L 2 -14 L 3 -11 L 4 -6 L 4 -2 L 3 3 L 1 7 L -1 10 L -4 13 L -8 16 M 1 -16 L 2 -13 L 3 -8 L 3 -3 L 2 2 L 1 5 L -1 9 L -4 13","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-5 6 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-13 13 M -9 0 L 9 0","-5 6 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-11 11 M 9 -16 L -9 16","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -3 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12","-10 11 M 2 -8 L -3 9 M 4 -12 L -2 9 M 4 -12 L 1 -9 L -2 -7 L -4 -6 M 3 -9 L -1 -7 L -4 -6","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 5 -3 L 2 -1 L -2 1 L -5 3 L -7 5 L -9 9 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 L -2 1 M -8 7 L -7 6 L -5 6 L 0 8 L 3 8 L 5 7 L 6 5 M -5 6 L 0 9 L 3 9 L 5 8 L 6 5","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 4 -3 L 1 -2 M 4 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 M -1 -2 L 1 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -2 L 3 -1 L 4 0 L 5 2 L 5 5 L 4 7 L 3 8 L 1 9","-10 11 M 6 -11 L 0 9 M 7 -12 L 1 9 M 7 -12 L -8 3 L 8 3","-10 11 M -1 -12 L -6 -2 M -1 -12 L 9 -12 M -1 -11 L 4 -11 L 9 -12 M -6 -2 L -5 -3 L -2 -4 L 1 -4 L 4 -3 L 5 -2 L 6 0 L 6 3 L 5 6 L 3 8 L 0 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 4 L -7 3 L -6 4 L -7 5 M 1 -4 L 3 -3 L 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 L 0 9","-10 11 M 7 -9 L 6 -8 L 7 -7 L 8 -8 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 5 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 L -1 -3 L -3 -2 L -5 0 L -6 2 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 6 L -5 8 M 0 9 L 2 8 L 4 6 L 5 4 L 5 0 L 4 -2","-10 11 M -4 -12 L -6 -6 M 9 -12 L 8 -9 L 6 -6 L 1 0 L -1 3 L -2 5 L -3 9 M 6 -6 L 0 0 L -2 3 L -3 5 L -4 9 M -5 -9 L -2 -12 L 0 -12 L 5 -9 M -4 -10 L -2 -11 L 0 -11 L 5 -9 L 7 -9 L 8 -10 L 9 -12","-10 11 M 1 -12 L -2 -11 L -3 -10 L -4 -8 L -4 -5 L -3 -3 L -1 -2 L 2 -2 L 6 -3 L 7 -4 L 8 -6 L 8 -9 L 7 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -2 -10 L -3 -8 L -3 -5 L -2 -3 L -1 -2 M 2 -2 L 5 -3 L 6 -4 L 7 -6 L 7 -9 L 6 -11 L 4 -12 M -1 -2 L -5 -1 L -7 1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 4 8 L 5 7 L 6 5 L 6 2 L 5 0 L 4 -1 L 2 -2 M -1 -2 L -4 -1 L -6 1 L -7 3 L -7 6 L -6 8 L -4 9 M 0 9 L 3 8 L 4 7 L 5 5 L 5 1 L 4 -1","-10 11 M 7 -5 L 6 -3 L 4 -1 L 2 0 L -1 0 L -3 -1 L -4 -2 L -5 -4 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 4 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -4 L 7 0 L 6 3 L 4 6 L 2 8 L -1 9 L -4 9 L -6 8 L -7 6 L -7 5 L -6 4 L -5 5 L -6 6 M -3 -1 L -4 -3 L -4 -7 L -3 -9 L -1 -11 L 1 -12 M 6 -11 L 7 -9 L 7 -4 L 6 0 L 5 3 L 3 6 L 1 8 L -1 9","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 7 L -3 8 L -2 9 L -1 8","-5 6 M 1 -5 L 0 -4 L 1 -3 L 2 -4 L 1 -5 M -2 9 L -3 8 L -2 7 L -1 8 L -1 9 L -2 11 L -4 13","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-10 11 M -3 -8 L -2 -7 L -3 -6 L -4 -7 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 1 -2 L -1 -1 L -1 1 L 0 2 L 2 2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 M -2 7 L -3 8 L -2 9 L -1 8 L -2 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 3 -12 L -10 9 M 3 -12 L 4 9 M 2 -10 L 3 9 M -6 3 L 3 3 M -12 9 L -6 9 M 0 9 L 6 9","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 L 4 -2 M -5 -2 L 4 -2 L 6 -1 L 7 1 L 7 3 L 6 6 L 4 8 L 0 9 L -12 9 M 4 -2 L 5 -1 L 6 1 L 6 3 L 5 6 L 3 8 L 0 9","-10 11 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 L 6 4 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -7 L 8 -3 L 7 1 L 5 5 L 3 7 L 1 8 L -3 9 L -12 9 M 3 -12 L 5 -11 L 6 -10 L 7 -7 L 7 -3 L 6 1 L 4 5 L 2 7 L 0 8 L -3 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M 2 -6 L 0 2 M -6 -12 L 9 -12 L 8 -6 L 8 -12 M -5 -2 L 1 -2 M -12 9 L 3 9 L 5 4 L 2 9","-12 10 M -3 -12 L -9 9 M -2 -12 L -8 9 M 2 -6 L 0 2 M -6 -12 L 9 -12 L 8 -6 L 8 -12 M -5 -2 L 1 -2 M -12 9 L -5 9","-10 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 0 9 L 3 8 L 5 6 L 7 2 M 2 -12 L 0 -11 L -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 4 L -5 7 L -4 8 L -2 9 M 0 9 L 2 8 L 4 6 L 6 2 M 3 2 L 10 2","-13 13 M -4 -12 L -10 9 M -3 -12 L -9 9 M 9 -12 L 3 9 M 10 -12 L 4 9 M -7 -12 L 0 -12 M 6 -12 L 13 -12 M -6 -2 L 6 -2 M -13 9 L -6 9 M 0 9 L 7 9","-6 7 M 3 -12 L -3 9 M 4 -12 L -2 9 M 0 -12 L 7 -12 M -6 9 L 1 9","-9 9 M 6 -12 L 1 5 L 0 7 L -1 8 L -3 9 L -5 9 L -7 8 L -8 6 L -8 4 L -7 3 L -6 4 L -7 5 M 5 -12 L 0 5 L -1 7 L -3 9 M 2 -12 L 9 -12","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M 11 -12 L -6 1 M 1 -3 L 5 9 M 0 -3 L 4 9 M -6 -12 L 1 -12 M 7 -12 L 13 -12 M -12 9 L -5 9 M 1 9 L 7 9","-10 10 M -1 -12 L -7 9 M 0 -12 L -6 9 M -4 -12 L 3 -12 M -10 9 L 5 9 L 7 3 L 4 9","-13 14 M -4 -12 L -10 9 M -4 -12 L -3 9 M -3 -12 L -2 7 M 10 -12 L -3 9 M 10 -12 L 4 9 M 11 -12 L 5 9 M -7 -12 L -3 -12 M 10 -12 L 14 -12 M -13 9 L -7 9 M 1 9 L 8 9","-12 13 M -3 -12 L -9 9 M -3 -12 L 4 6 M -3 -9 L 4 9 M 10 -12 L 4 9 M -6 -12 L -3 -12 M 7 -12 L 13 -12 M -12 9 L -6 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -4 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 6 -12 L 9 -11 L 10 -9 L 10 -7 L 9 -4 L 7 -2 L 3 -1 L -5 -1 M 6 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 6 -2 L 3 -1 M -12 9 L -5 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M 1 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -4 9 M -1 9 L 1 8 L 3 6 L 5 3 L 6 0 L 7 -4 L 7 -7 L 6 -10 L 4 -12 M -6 7 L -6 6 L -5 4 L -3 3 L -2 3 L 0 4 L 1 6 L 1 13 L 2 14 L 4 14 L 5 12 L 5 11 M 1 6 L 2 12 L 3 13 L 4 13 L 5 12","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 L -5 -2 M 5 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 L 4 -2 M 0 -2 L 2 -1 L 3 0 L 4 8 L 5 9 L 7 9 L 8 7 L 8 6 M 3 0 L 5 7 L 6 8 L 7 8 L 8 7 M -12 9 L -5 9","-11 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -7 L -4 -5 L -3 -4 L 4 0 L 6 2 M -5 -7 L -3 -5 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -9 9 L -8 7 L -7 7","-10 11 M 3 -12 L -3 9 M 4 -12 L -2 9 M -3 -12 L -6 -6 L -4 -12 L 11 -12 L 10 -6 L 10 -12 M -6 9 L 1 9","-12 13 M -4 -12 L -7 -1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 3 8 L 5 6 L 6 3 L 10 -12 M -3 -12 L -6 -1 L -7 3 L -7 6 L -6 8 L -4 9 M -7 -12 L 0 -12 M 7 -12 L 13 -12","-10 10 M -4 -12 L -3 9 M -3 -12 L -2 7 M 10 -12 L -3 9 M -6 -12 L 0 -12 M 6 -12 L 12 -12","-13 13 M -5 -12 L -7 9 M -4 -12 L -6 7 M 3 -12 L -7 9 M 3 -12 L 1 9 M 4 -12 L 2 7 M 11 -12 L 1 9 M -8 -12 L -1 -12 M 8 -12 L 14 -12","-11 11 M -4 -12 L 3 9 M -3 -12 L 4 9 M 10 -12 L -10 9 M -6 -12 L 0 -12 M 6 -12 L 12 -12 M -12 9 L -6 9 M 0 9 L 6 9","-10 11 M -4 -12 L 0 -2 L -3 9 M -3 -12 L 1 -2 L -2 9 M 11 -12 L 1 -2 M -6 -12 L 0 -12 M 7 -12 L 13 -12 M -6 9 L 1 9","-11 11 M 9 -12 L -10 9 M 10 -12 L -9 9 M -3 -12 L -6 -6 L -4 -12 L 10 -12 M -10 9 L 4 9 L 6 3 L 3 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-10 11 M 6 -5 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8","-10 9 M -2 -12 L -6 1 L -6 4 L -5 7 L -4 8 M -1 -12 L -5 1 M -5 1 L -4 -2 L -2 -4 L 0 -5 L 2 -5 L 4 -4 L 5 -3 L 6 -1 L 6 2 L 5 5 L 3 8 L 0 9 L -2 9 L -4 8 L -5 5 L -5 1 M 4 -4 L 5 -2 L 5 2 L 4 5 L 2 8 L 0 9 M -5 -12 L -1 -12","-9 9 M 5 -2 L 5 -1 L 6 -1 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8","-10 11 M 8 -12 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 9 -12 L 5 2 L 4 6 L 4 8 L 5 9 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8 M 5 -12 L 9 -12","-9 9 M -5 4 L -1 3 L 2 2 L 5 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8","-7 8 M 8 -11 L 7 -10 L 8 -9 L 9 -10 L 9 -11 L 8 -12 L 6 -12 L 4 -11 L 3 -10 L 2 -8 L 1 -5 L -2 9 L -3 13 L -4 15 M 6 -12 L 4 -10 L 3 -8 L 2 -4 L 0 5 L -1 9 L -2 12 L -3 14 L -4 15 L -6 16 L -8 16 L -9 15 L -9 14 L -8 13 L -7 14 L -8 15 M -3 -5 L 7 -5","-10 10 M 7 -5 L 3 9 L 2 12 L 0 15 L -3 16 L -6 16 L -8 15 L -9 14 L -9 13 L -8 12 L -7 13 L -8 14 M 6 -5 L 2 9 L 1 12 L -1 15 L -3 16 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8","-10 11 M -2 -12 L -8 9 M -1 -12 L -7 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 6 -1 L 4 5 L 4 8 L 5 9 M 3 -5 L 5 -3 L 5 -1 L 3 5 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M -5 -12 L -1 -12","-6 7 M 3 -12 L 2 -11 L 3 -10 L 4 -11 L 3 -12 M -5 -1 L -4 -3 L -2 -5 L 1 -5 L 2 -4 L 2 -1 L 0 5 L 0 8 L 1 9 M 0 -5 L 1 -4 L 1 -1 L -1 5 L -1 8 L 0 9 L 3 9 L 5 7 L 6 5","-6 7 M 4 -12 L 3 -11 L 4 -10 L 5 -11 L 4 -12 M -4 -1 L -3 -3 L -1 -5 L 2 -5 L 3 -4 L 3 -1 L 0 9 L -1 12 L -2 14 L -3 15 L -5 16 L -7 16 L -8 15 L -8 14 L -7 13 L -6 14 L -7 15 M 1 -5 L 2 -4 L 2 -1 L -1 9 L -2 12 L -3 14 L -5 16","-10 10 M -2 -12 L -8 9 M -1 -12 L -7 9 M 6 -4 L 5 -3 L 6 -2 L 7 -3 L 7 -4 L 6 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 L -5 1 M -3 1 L -1 2 L 1 8 L 2 9 M -3 1 L -2 2 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 M -5 -12 L -1 -12","-5 7 M 3 -12 L -1 2 L -2 6 L -2 8 L -1 9 L 2 9 L 4 7 L 5 5 M 4 -12 L 0 2 L -1 6 L -1 8 L 0 9 M 0 -12 L 4 -12","-17 16 M -16 -1 L -15 -3 L -13 -5 L -10 -5 L -9 -4 L -9 -2 L -10 2 L -12 9 M -11 -5 L -10 -4 L -10 -2 L -11 2 L -13 9 M -10 2 L -8 -2 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -3 L 1 -1 L -2 9 M -2 -5 L 0 -3 L 0 -1 L -3 9 M 0 2 L 2 -2 L 4 -4 L 6 -5 L 8 -5 L 10 -4 L 11 -3 L 11 -1 L 9 5 L 9 8 L 10 9 M 8 -5 L 10 -3 L 10 -1 L 8 5 L 8 8 L 9 9 L 12 9 L 14 7 L 15 5","-12 11 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -2 L -5 2 L -7 9 M -6 -5 L -5 -4 L -5 -2 L -6 2 L -8 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 6 -1 L 4 5 L 4 8 L 5 9 M 3 -5 L 5 -3 L 5 -1 L 3 5 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5","-9 9 M 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 5 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 L 6 2 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L 0 -5 M 0 -5 L -2 -4 L -4 -1 L -5 2 L -5 6 L -4 8 M 0 9 L 2 8 L 4 5 L 5 2 L 5 -2 L 4 -4","-11 10 M -10 -1 L -9 -3 L -7 -5 L -4 -5 L -3 -4 L -3 -2 L -4 2 L -8 16 M -5 -5 L -4 -4 L -4 -2 L -5 2 L -9 16 M -4 2 L -3 -1 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -3 L 7 -1 L 7 2 L 6 5 L 4 8 L 1 9 L -1 9 L -3 8 L -4 5 L -4 2 M 5 -4 L 6 -2 L 6 2 L 5 5 L 3 8 L 1 9 M -12 16 L -5 16","-10 10 M 6 -5 L 0 16 M 7 -5 L 1 16 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 5 L 4 2 M -1 -5 L -3 -4 L -5 -1 L -6 2 L -6 6 L -5 8 M -3 16 L 4 16","-9 8 M -8 -1 L -7 -3 L -5 -5 L -2 -5 L -1 -4 L -1 -2 L -2 2 L -4 9 M -3 -5 L -2 -4 L -2 -2 L -3 2 L -5 9 M -2 2 L 0 -2 L 2 -4 L 4 -5 L 6 -5 L 7 -4 L 7 -3 L 6 -2 L 5 -3 L 6 -4","-8 9 M 6 -3 L 6 -2 L 7 -2 L 7 -3 L 6 -4 L 3 -5 L 0 -5 L -3 -4 L -4 -3 L -4 -1 L -3 0 L 4 4 L 5 5 M -4 -2 L -3 -1 L 4 3 L 5 4 L 5 7 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -6 6 L -5 6 L -5 7","-7 7 M 2 -12 L -2 2 L -3 6 L -3 8 L -2 9 L 1 9 L 3 7 L 4 5 M 3 -12 L -1 2 L -2 6 L -2 8 L -1 9 M -4 -5 L 5 -5","-12 11 M -11 -1 L -10 -3 L -8 -5 L -5 -5 L -4 -4 L -4 -1 L -6 5 L -6 7 L -4 9 M -6 -5 L -5 -4 L -5 -1 L -7 5 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 2 M 6 -5 L 4 2 L 3 6 L 3 8 L 4 9 L 7 9 L 9 7 L 10 5 M 7 -5 L 5 2 L 4 6 L 4 8 L 5 9","-10 10 M -9 -1 L -8 -3 L -6 -5 L -3 -5 L -2 -4 L -2 -1 L -4 5 L -4 7 L -2 9 M -4 -5 L -3 -4 L -3 -1 L -5 5 L -5 7 L -4 8 L -2 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 -1 L 7 -5 L 6 -5 L 7 -3","-15 14 M -14 -1 L -13 -3 L -11 -5 L -8 -5 L -7 -4 L -7 -1 L -9 5 L -9 7 L -7 9 M -9 -5 L -8 -4 L -8 -1 L -10 5 L -10 7 L -9 8 L -7 9 L -5 9 L -3 8 L -1 6 L 0 4 M 2 -5 L 0 4 L 0 7 L 1 8 L 3 9 L 5 9 L 7 8 L 9 6 L 10 4 L 11 0 L 11 -5 L 10 -5 L 11 -3 M 3 -5 L 1 4 L 1 7 L 3 9","-10 10 M -7 -1 L -5 -4 L -3 -5 L 0 -5 L 1 -3 L 1 0 M -1 -5 L 0 -3 L 0 0 L -1 4 L -2 6 L -4 8 L -6 9 L -7 9 L -8 8 L -8 7 L -7 6 L -6 7 L -7 8 M -1 4 L -1 7 L 0 9 L 3 9 L 5 8 L 7 5 M 7 -4 L 6 -3 L 7 -2 L 8 -3 L 8 -4 L 7 -5 L 6 -5 L 4 -4 L 2 -2 L 1 0 L 0 4 L 0 7 L 1 9","-11 10 M -10 -1 L -9 -3 L -7 -5 L -4 -5 L -3 -4 L -3 -1 L -5 5 L -5 7 L -3 9 M -5 -5 L -4 -4 L -4 -1 L -6 5 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 3 6 L 5 2 M 8 -5 L 4 9 L 3 12 L 1 15 L -2 16 L -5 16 L -7 15 L -8 14 L -8 13 L -7 12 L -6 13 L -7 14 M 7 -5 L 3 9 L 2 12 L 0 15 L -2 16","-10 10 M 7 -5 L 6 -3 L 4 -1 L -4 5 L -6 7 L -7 9 M -6 -1 L -5 -3 L -3 -5 L 0 -5 L 4 -3 M -5 -3 L -3 -4 L 0 -4 L 4 -3 L 6 -3 M -6 7 L -4 7 L 0 8 L 3 8 L 5 7 M -4 7 L 0 9 L 3 9 L 5 7 L 6 5","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -timesib = ["-8 8","-5 6 M 4 -12 L 3 -12 L 2 -11 L 0 2 M 4 -11 L 3 -11 L 0 2 M 4 -11 L 4 -10 L 0 2 M 4 -12 L 5 -11 L 5 -10 L 0 2 M -2 6 L -3 7 L -3 8 L -2 9 L -1 9 L 0 8 L 0 7 L -1 6 L -2 6 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7","-9 9 M -2 -12 L -4 -5 M -1 -12 L -4 -5 M 7 -12 L 5 -5 M 8 -12 L 5 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 11 M 2 -16 L -6 13 M 7 -16 L -1 13 M 8 -7 L 8 -8 L 7 -8 L 7 -6 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -2 L 4 1 L 5 3 L 5 6 L 4 8 M -4 -6 L -3 -4 L 4 0 L 5 2 M -3 -11 L -4 -9 L -4 -7 L -3 -5 L 3 -2 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -6 3 L -6 5 L -7 5 L -7 4","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 10 -3 L 10 -4 L 9 -4 L 9 -2 L 11 -2 L 11 -4 L 10 -5 L 9 -5 L 7 -4 L 5 -2 L 0 6 L -2 8 L -4 9 L -7 9 L -10 8 L -11 6 L -11 4 L -10 2 L -9 1 L -7 0 L -2 -2 L 0 -3 L 2 -5 L 3 -7 L 3 -9 L 2 -11 L 0 -12 L -2 -11 L -3 -9 L -3 -6 L -2 0 L -1 3 L 0 5 L 2 8 L 4 9 L 6 9 L 7 7 L 7 6 M -6 9 L -10 8 M -9 8 L -10 6 L -10 4 L -9 2 L -8 1 L -6 0 M -2 -2 L -1 1 L 2 7 L 4 8 M -7 9 L -8 8 L -9 6 L -9 4 L -8 2 L -7 1 L -5 0 L 0 -3 M -3 -6 L -2 -3 L -1 0 L 1 4 L 3 7 L 5 8 L 6 8 L 7 7","-4 5 M 3 -12 L 1 -5 M 4 -12 L 1 -5","-8 8 M 8 -16 L 6 -15 L 3 -13 L 0 -10 L -2 -7 L -4 -3 L -5 1 L -5 6 L -4 10 L -3 13 L -1 16 M 1 -10 L -1 -7 L -3 -3 L -4 2 L -4 10 M 8 -16 L 5 -14 L 2 -11 L 0 -8 L -1 -6 L -2 -3 L -3 1 L -4 10 M -4 2 L -3 11 L -2 14 L -1 16","-8 8 M 1 -16 L 3 -13 L 4 -10 L 5 -6 L 5 -1 L 4 3 L 2 7 L 0 10 L -3 13 L -6 15 L -8 16 M 4 -10 L 4 -2 L 3 3 L 1 7 L -1 10 M 1 -16 L 2 -14 L 3 -11 L 4 -2 M 4 -10 L 3 -1 L 2 3 L 1 6 L 0 8 L -2 11 L -5 14 L -8 16","-8 9 M 2 -12 L 1 -11 L 3 -1 L 2 0 M 2 -12 L 2 0 M 2 -12 L 3 -11 L 1 -1 L 2 0 M -3 -9 L -2 -9 L 6 -3 L 7 -3 M -3 -9 L 7 -3 M -3 -9 L -3 -8 L 7 -4 L 7 -3 M 7 -9 L 6 -9 L -2 -3 L -3 -3 M 7 -9 L -3 -3 M 7 -9 L 7 -8 L -3 -4 L -3 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-5 6 M -1 9 L -2 9 L -3 8 L -3 7 L -2 6 L -1 6 L 0 7 L 0 9 L -1 11 L -2 12 L -4 13 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7 M -1 9 L -1 10 L -2 12","-13 13 M -9 0 L 9 0","-5 6 M -2 6 L -3 7 L -3 8 L -2 9 L -1 9 L 0 8 L 0 7 L -1 6 L -2 6 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 11 M 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 2 -12 M -1 -10 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 2 7 L 4 5 L 5 3 L 6 0 L 7 -4 L 7 -8 L 6 -10 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -3 9 M -1 9 L 1 8 L 3 5 L 4 3 L 5 0 L 6 -4 L 6 -9 L 5 -11 L 4 -12","-10 11 M 2 -8 L -3 9 L -1 9 M 5 -12 L 3 -8 L -2 9 M 5 -12 L -1 9 M 5 -12 L 2 -9 L -1 -7 L -3 -6 M 2 -8 L 0 -7 L -3 -6","-10 11 M -3 -7 L -3 -8 L -2 -8 L -2 -6 L -4 -6 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 5 -3 L -5 3 L -7 5 L -9 9 M 6 -11 L 7 -9 L 7 -7 L 6 -5 L 4 -3 L 1 -1 M 4 -12 L 5 -11 L 6 -9 L 6 -7 L 5 -5 L 3 -3 L -5 3 M -8 7 L -7 6 L -5 6 L 0 7 L 5 7 L 6 6 M -5 6 L 0 8 L 5 8 M -5 6 L 0 9 L 3 9 L 5 8 L 6 6 L 6 5","-10 11 M -3 -7 L -3 -8 L -2 -8 L -2 -6 L -4 -6 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 4 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 L 1 -2 M 6 -11 L 7 -9 L 7 -7 L 6 -5 L 5 -4 M 4 -12 L 5 -11 L 6 -9 L 6 -7 L 5 -5 L 3 -3 L 1 -2 M -1 -2 L 1 -2 L 4 -1 L 5 0 L 6 2 L 6 5 L 5 7 L 3 8 L 0 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -6 3 L -6 5 L -7 5 L -7 4 M 4 0 L 5 2 L 5 5 L 4 7 M 1 -2 L 3 -1 L 4 1 L 4 5 L 3 7 L 2 8 L 0 9","-10 11 M 5 -8 L 0 9 L 2 9 M 8 -12 L 6 -8 L 1 9 M 8 -12 L 2 9 M 8 -12 L -8 3 L 8 3","-10 11 M -1 -12 L -6 -2 M -1 -12 L 9 -12 M -1 -11 L 7 -11 M -2 -10 L 3 -10 L 7 -11 L 9 -12 M -6 -2 L -5 -3 L -2 -4 L 1 -4 L 4 -3 L 5 -2 L 6 0 L 6 3 L 5 6 L 3 8 L -1 9 L -4 9 L -6 8 L -7 7 L -8 5 L -8 3 L -6 3 L -6 5 L -7 5 L -7 4 M 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 M 1 -4 L 3 -3 L 4 -1 L 4 3 L 3 6 L 1 8 L -1 9","-10 11 M 7 -8 L 7 -9 L 6 -9 L 6 -7 L 8 -7 L 8 -9 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -3 9 L 0 9 L 3 8 L 5 6 L 6 4 L 6 1 L 5 -1 L 4 -2 L 2 -3 L -1 -3 L -3 -2 L -4 -1 L -5 1 M -2 -9 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 4 6 L 5 4 L 5 1 L 4 -1 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -3 9 M 0 9 L 2 8 L 3 7 L 4 4 L 4 0 L 3 -2 L 2 -3","-10 11 M -4 -12 L -6 -6 M 9 -12 L 8 -9 L 6 -6 L 2 -1 L 0 2 L -1 5 L -2 9 M 0 1 L -2 5 L -3 9 M 6 -6 L 0 0 L -2 3 L -3 5 L -4 9 L -2 9 M -5 -9 L -2 -12 L 0 -12 L 5 -9 M -3 -11 L 0 -11 L 5 -9 M -5 -9 L -3 -10 L 0 -10 L 5 -9 L 7 -9 L 8 -10 L 9 -12","-10 11 M 1 -12 L -2 -11 L -3 -10 L -4 -8 L -4 -5 L -3 -3 L -1 -2 L 2 -2 L 5 -3 L 7 -4 L 8 -6 L 8 -9 L 7 -11 L 5 -12 L 1 -12 M 3 -12 L -2 -11 M -2 -10 L -3 -8 L -3 -4 L -2 -3 M -3 -3 L 0 -2 M 1 -2 L 5 -3 M 6 -4 L 7 -6 L 7 -9 L 6 -11 M 7 -11 L 3 -12 M 1 -12 L -1 -10 L -2 -8 L -2 -4 L -1 -2 M 2 -2 L 4 -3 L 5 -4 L 6 -6 L 6 -10 L 5 -12 M -1 -2 L -5 -1 L -7 1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 4 8 L 5 7 L 6 5 L 6 2 L 5 0 L 4 -1 L 2 -2 M 0 -2 L -5 -1 M -4 -1 L -6 1 L -7 3 L -7 6 L -6 8 M -7 8 L -2 9 L 4 8 M 4 7 L 5 5 L 5 2 L 4 0 M 4 -1 L 1 -2 M -1 -2 L -3 -1 L -5 1 L -6 3 L -6 6 L -5 8 L -4 9 M 0 9 L 2 8 L 3 7 L 4 5 L 4 1 L 3 -1 L 2 -2","-10 11 M 6 -4 L 5 -2 L 4 -1 L 2 0 L -1 0 L -3 -1 L -4 -2 L -5 -4 L -5 -7 L -4 -9 L -2 -11 L 1 -12 L 4 -12 L 6 -11 L 7 -10 L 8 -7 L 8 -4 L 7 0 L 6 3 L 4 6 L 2 8 L -1 9 L -4 9 L -6 8 L -7 6 L -7 4 L -5 4 L -5 6 L -6 6 L -6 5 M -3 -2 L -4 -4 L -4 -7 L -3 -9 M 6 -10 L 7 -8 L 7 -4 L 6 0 L 5 3 L 3 6 M -1 0 L -2 -1 L -3 -3 L -3 -7 L -2 -10 L -1 -11 L 1 -12 M 4 -12 L 5 -11 L 6 -9 L 6 -4 L 5 0 L 4 3 L 3 5 L 1 8 L -1 9","-5 6 M 1 -5 L 0 -4 L 0 -3 L 1 -2 L 2 -2 L 3 -3 L 3 -4 L 2 -5 L 1 -5 M 1 -4 L 1 -3 L 2 -3 L 2 -4 L 1 -4 M -2 6 L -3 7 L -3 8 L -2 9 L -1 9 L 0 8 L 0 7 L -1 6 L -2 6 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7","-5 6 M 1 -5 L 0 -4 L 0 -3 L 1 -2 L 2 -2 L 3 -3 L 3 -4 L 2 -5 L 1 -5 M 1 -4 L 1 -3 L 2 -3 L 2 -4 L 1 -4 M -1 9 L -2 9 L -3 8 L -3 7 L -2 6 L -1 6 L 0 7 L 0 9 L -1 11 L -2 12 L -4 13 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7 M -1 9 L -1 10 L -2 12","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-10 11 M -3 -7 L -3 -8 L -2 -8 L -2 -6 L -4 -6 L -4 -8 L -3 -10 L -2 -11 L 1 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -5 L 7 -4 L 5 -3 L 1 -2 L -1 -1 L -1 1 L 1 2 L 2 2 M 3 -12 L 8 -11 M 7 -11 L 8 -9 L 8 -7 L 7 -5 L 6 -4 L 4 -3 M 5 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -5 L 5 -4 L 1 -2 L 0 -1 L 0 1 L 1 2 M -2 6 L -3 7 L -3 8 L -2 9 L -1 9 L 0 8 L 0 7 L -1 6 L -2 6 M -2 7 L -2 8 L -1 8 L -1 7 L -2 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 3 -12 L -9 8 M 1 -8 L 2 9 M 2 -10 L 3 8 M 3 -12 L 3 -10 L 4 7 L 4 9 M -6 3 L 2 3 M -12 9 L -6 9 M -1 9 L 6 9 M -9 8 L -11 9 M -9 8 L -7 9 M 2 8 L 0 9 M 2 7 L 1 9 M 4 7 L 5 9","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 M 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 M 5 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -4 L 4 -2 M -4 -2 L 4 -2 L 6 -1 L 7 1 L 7 3 L 6 6 L 4 8 L 0 9 L -12 9 M 5 -1 L 6 1 L 6 3 L 5 6 L 3 8 M 4 -2 L 5 0 L 5 3 L 4 6 L 2 8 L 0 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9","-10 11 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 L 6 4 M -1 -10 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -2 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M -6 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -7 L 8 -3 L 7 1 L 5 5 L 3 7 L 1 8 L -3 9 L -12 9 M 5 -11 L 6 -10 L 7 -7 L 7 -3 L 6 1 L 4 5 L 2 7 M 3 -12 L 5 -10 L 6 -7 L 6 -3 L 5 1 L 3 5 L 0 8 L -3 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M 3 -6 L 1 2 M -6 -12 L 9 -12 L 8 -6 M -4 -2 L 2 -2 M -12 9 L 3 9 L 5 4 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M 5 -12 L 8 -11 M 6 -12 L 8 -10 M 7 -12 L 8 -9 M 8 -12 L 8 -6 M 3 -6 L 1 -2 L 1 2 M 2 -4 L 0 -2 L 1 0 M 2 -3 L -1 -2 L 1 -1 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9 M -2 9 L 3 8 M 0 9 L 3 7 M 3 7 L 5 4","-12 10 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M 3 -6 L 1 2 M -6 -12 L 9 -12 L 8 -6 M -4 -2 L 2 -2 M -12 9 L -4 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M 5 -12 L 8 -11 M 6 -12 L 8 -10 M 7 -12 L 8 -9 M 8 -12 L 8 -6 M 3 -6 L 1 -2 L 1 2 M 2 -4 L 0 -2 L 1 0 M 2 -3 L -1 -2 L 1 -1 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9","-10 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 5 -12 L 2 -12 L -1 -11 L -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 4 L -6 7 L -5 8 L -2 9 L 0 9 L 3 8 L 5 6 L 7 2 M -1 -10 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 5 L -5 7 M 4 6 L 5 5 L 6 2 M 2 -12 L 0 -11 L -2 -8 L -3 -6 L -4 -3 L -5 1 L -5 6 L -4 8 L -2 9 M 0 9 L 2 8 L 4 5 L 5 2 M 2 2 L 10 2 M 3 2 L 5 3 M 4 2 L 5 5 M 8 2 L 6 4 M 9 2 L 6 3","-13 13 M -4 -12 L -10 9 M -3 -12 L -9 9 M -2 -12 L -8 9 M 8 -12 L 2 9 M 9 -12 L 3 9 M 10 -12 L 4 9 M -7 -12 L 1 -12 M 5 -12 L 13 -12 M -6 -2 L 6 -2 M -13 9 L -5 9 M -1 9 L 7 9 M -6 -12 L -3 -11 M -5 -12 L -4 -10 M -1 -12 L -3 -10 M 0 -12 L -3 -11 M 6 -12 L 9 -11 M 7 -12 L 8 -10 M 11 -12 L 9 -10 M 12 -12 L 9 -11 M -9 8 L -12 9 M -9 7 L -11 9 M -8 7 L -7 9 M -9 8 L -6 9 M 3 8 L 0 9 M 3 7 L 1 9 M 4 7 L 5 9 M 3 8 L 6 9","-7 7 M 2 -12 L -4 9 M 3 -12 L -3 9 M 4 -12 L -2 9 M -1 -12 L 7 -12 M -7 9 L 1 9 M 0 -12 L 3 -11 M 1 -12 L 2 -10 M 5 -12 L 3 -10 M 6 -12 L 3 -11 M -3 8 L -6 9 M -3 7 L -5 9 M -2 7 L -1 9 M -3 8 L 0 9","-9 10 M 5 -12 L 0 5 L -1 7 L -3 9 M 6 -12 L 2 1 L 1 4 L 0 6 M 7 -12 L 3 1 L 1 6 L -1 8 L -3 9 L -5 9 L -7 8 L -8 6 L -8 4 L -7 3 L -6 3 L -5 4 L -5 5 L -6 6 L -7 6 M -7 4 L -7 5 L -6 5 L -6 4 L -7 4 M 2 -12 L 10 -12 M 3 -12 L 6 -11 M 4 -12 L 5 -10 M 8 -12 L 6 -10 M 9 -12 L 6 -11","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M 10 -11 L -5 0 M -1 -3 L 3 9 M 0 -3 L 4 9 M 1 -4 L 5 8 M -6 -12 L 2 -12 M 7 -12 L 13 -12 M -12 9 L -4 9 M 0 9 L 7 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M 8 -12 L 10 -11 M 12 -12 L 10 -11 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9 M 3 8 L 1 9 M 3 7 L 2 9 M 4 7 L 6 9","-10 10 M -1 -12 L -7 9 M 0 -12 L -6 9 M 1 -12 L -5 9 M -4 -12 L 4 -12 M -10 9 L 5 9 L 7 3 M -3 -12 L 0 -11 M -2 -12 L -1 -10 M 2 -12 L 0 -10 M 3 -12 L 0 -11 M -6 8 L -9 9 M -6 7 L -8 9 M -5 7 L -4 9 M -6 8 L -3 9 M 0 9 L 5 8 M 2 9 L 6 6 M 4 9 L 7 3","-14 14 M -5 -12 L -11 8 M -5 -11 L -4 7 L -4 9 M -4 -12 L -3 7 M -3 -12 L -2 6 M 9 -12 L -2 6 L -4 9 M 9 -12 L 3 9 M 10 -12 L 4 9 M 11 -12 L 5 9 M -8 -12 L -3 -12 M 9 -12 L 14 -12 M -14 9 L -8 9 M 0 9 L 8 9 M -7 -12 L -5 -11 M -6 -12 L -5 -10 M 12 -12 L 10 -10 M 13 -12 L 10 -11 M -11 8 L -13 9 M -11 8 L -9 9 M 4 8 L 1 9 M 4 7 L 2 9 M 5 7 L 6 9 M 4 8 L 7 9","-12 13 M -3 -12 L -9 8 M -3 -12 L 4 9 M -2 -12 L 4 6 M -1 -12 L 5 6 M 10 -11 L 5 6 L 4 9 M -6 -12 L -1 -12 M 7 -12 L 13 -12 M -12 9 L -6 9 M -5 -12 L -2 -11 M -4 -12 L -2 -10 M 8 -12 L 10 -11 M 12 -12 L 10 -11 M -9 8 L -11 9 M -9 8 L -7 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 5 L -6 7 M 3 6 L 5 3 L 6 0 L 7 -4 L 7 -8 L 6 -10 M 1 -12 L -1 -11 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 6 L -5 8 L -4 9 M -1 9 L 1 8 L 3 5 L 4 3 L 5 0 L 6 -4 L 6 -9 L 5 -11 L 4 -12","-12 11 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M -6 -12 L 6 -12 L 9 -11 L 10 -9 L 10 -7 L 9 -4 L 7 -2 L 3 -1 L -5 -1 M 8 -11 L 9 -9 L 9 -7 L 8 -4 L 6 -2 M 6 -12 L 7 -11 L 8 -9 L 8 -7 L 7 -4 L 5 -2 L 3 -1 M -12 9 L -4 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9","-11 11 M 1 -12 L -2 -11 L -4 -9 L -6 -6 L -7 -3 L -8 1 L -8 4 L -7 7 L -6 8 L -4 9 L -1 9 L 2 8 L 4 6 L 6 3 L 7 0 L 8 -4 L 8 -7 L 7 -10 L 6 -11 L 4 -12 L 1 -12 M -3 -9 L -5 -6 L -6 -3 L -7 1 L -7 5 L -6 7 M 3 6 L 5 3 L 6 0 L 7 -4 L 7 -8 L 6 -10 M 1 -12 L -1 -11 L -3 -8 L -4 -6 L -5 -3 L -6 1 L -6 6 L -5 8 L -4 9 M -1 9 L 1 8 L 3 5 L 4 3 L 5 0 L 6 -4 L 6 -9 L 5 -11 L 4 -12 M -6 6 L -5 4 L -3 3 L -2 3 L 0 4 L 1 6 L 2 11 L 3 12 L 4 12 L 5 11 M 2 12 L 3 13 L 4 13 M 1 6 L 1 13 L 2 14 L 4 14 L 5 11 L 5 10","-12 12 M -3 -12 L -9 9 M -2 -12 L -8 9 M -1 -12 L -7 9 M -6 -12 L 5 -12 L 8 -11 L 9 -9 L 9 -7 L 8 -4 L 7 -3 L 4 -2 L -4 -2 M 7 -11 L 8 -9 L 8 -7 L 7 -4 L 6 -3 M 5 -12 L 6 -11 L 7 -9 L 7 -7 L 6 -4 L 4 -2 M 0 -2 L 2 -1 L 3 0 L 5 6 L 6 7 L 7 7 L 8 6 M 5 7 L 6 8 L 7 8 M 3 0 L 4 8 L 5 9 L 7 9 L 8 6 L 8 5 M -12 9 L -4 9 M -5 -12 L -2 -11 M -4 -12 L -3 -10 M 0 -12 L -2 -10 M 1 -12 L -2 -11 M -8 8 L -11 9 M -8 7 L -10 9 M -7 7 L -6 9 M -8 8 L -5 9","-11 12 M 8 -10 L 9 -10 L 10 -12 L 9 -6 L 9 -8 L 8 -10 L 7 -11 L 4 -12 L 0 -12 L -3 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -2 L 4 1 L 5 3 L 5 6 L 4 8 M -4 -6 L -3 -4 L 4 0 L 5 2 M -3 -11 L -4 -9 L -4 -7 L -3 -5 L 3 -2 L 5 0 L 6 2 L 6 5 L 5 7 L 4 8 L 1 9 L -3 9 L -6 8 L -7 7 L -8 5 L -8 3 L -9 9 L -8 7 L -7 7","-11 11 M 2 -12 L -4 9 M 3 -12 L -3 9 M 4 -12 L -2 9 M -5 -12 L -7 -6 M 11 -12 L 10 -6 M -5 -12 L 11 -12 M -7 9 L 1 9 M -4 -12 L -7 -6 M -2 -12 L -6 -9 M 0 -12 L -5 -11 M 7 -12 L 10 -11 M 8 -12 L 10 -10 M 9 -12 L 10 -9 M 10 -12 L 10 -6 M -3 8 L -6 9 M -3 7 L -5 9 M -2 7 L -1 9 M -3 8 L 0 9","-12 13 M -4 -12 L -7 -1 L -8 3 L -8 6 L -7 8 L -4 9 L 0 9 L 3 8 L 5 6 L 6 3 L 10 -11 M -3 -12 L -6 -1 L -7 3 L -7 7 L -6 8 M -2 -12 L -5 -1 L -6 3 L -6 7 L -4 9 M -7 -12 L 1 -12 M 7 -12 L 13 -12 M -6 -12 L -3 -11 M -5 -12 L -4 -10 M -1 -12 L -3 -10 M 0 -12 L -3 -11 M 8 -12 L 10 -11 M 12 -12 L 10 -11","-10 10 M -4 -12 L -4 -10 L -3 7 L -3 9 M -3 -11 L -2 6 M -2 -12 L -1 5 M 9 -11 L -3 9 M -6 -12 L 1 -12 M 6 -12 L 12 -12 M -5 -12 L -4 -10 M -1 -12 L -2 -10 M 0 -12 L -3 -11 M 7 -12 L 9 -11 M 11 -12 L 9 -11","-13 13 M -5 -12 L -5 -10 L -7 7 L -7 9 M -4 -11 L -6 6 M -3 -12 L -5 5 M 3 -12 L -5 5 L -7 9 M 3 -12 L 3 -10 L 1 7 L 1 9 M 4 -11 L 2 6 M 5 -12 L 3 5 M 11 -11 L 3 5 L 1 9 M -8 -12 L 0 -12 M 3 -12 L 5 -12 M 8 -12 L 14 -12 M -7 -12 L -4 -11 M -6 -12 L -5 -10 M -2 -12 L -4 -9 M -1 -12 L -4 -11 M 9 -12 L 11 -11 M 13 -12 L 11 -11","-11 11 M -4 -12 L 2 9 M -3 -12 L 3 9 M -2 -12 L 4 9 M 9 -11 L -9 8 M -6 -12 L 1 -12 M 6 -12 L 12 -12 M -12 9 L -6 9 M -1 9 L 6 9 M -5 -12 L -3 -10 M -1 -12 L -2 -10 M 0 -12 L -2 -11 M 7 -12 L 9 -11 M 11 -12 L 9 -11 M -9 8 L -11 9 M -9 8 L -7 9 M 2 8 L 0 9 M 2 7 L 1 9 M 3 7 L 5 9","-11 11 M -5 -12 L -1 -2 L -4 9 M -4 -12 L 0 -2 L -3 9 M -3 -12 L 1 -2 L -2 9 M 10 -11 L 1 -2 M -7 -12 L 0 -12 M 7 -12 L 13 -12 M -7 9 L 1 9 M -6 -12 L -4 -11 M -2 -12 L -3 -10 M -1 -12 L -4 -11 M 8 -12 L 10 -11 M 12 -12 L 10 -11 M -3 8 L -6 9 M -3 7 L -5 9 M -2 7 L -1 9 M -3 8 L 0 9","-11 11 M 8 -12 L -10 9 M 9 -12 L -9 9 M 10 -12 L -8 9 M 10 -12 L -4 -12 L -6 -6 M -10 9 L 4 9 L 6 3 M -3 -12 L -6 -6 M -2 -12 L -5 -9 M 0 -12 L -4 -11 M 0 9 L 4 8 M 2 9 L 5 6 M 3 9 L 6 3","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-11 11 M 5 -5 L 3 2 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M 6 -5 L 4 2 L 4 8 M 5 -5 L 7 -5 L 5 2 L 4 6 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -4 -4 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9","-9 10 M -2 -12 L -4 -5 L -5 1 L -5 5 L -4 7 L -3 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 2 L 7 0 L 6 -3 L 5 -4 L 3 -5 L 1 -5 L -1 -4 L -2 -3 L -3 -1 L -4 2 M -1 -12 L -3 -5 L -4 -1 L -4 5 L -3 8 M 4 7 L 5 5 L 6 2 L 6 -1 L 5 -3 M -5 -12 L 0 -12 L -2 -5 L -4 2 M 1 9 L 3 7 L 4 5 L 5 2 L 5 -1 L 4 -4 L 3 -5 M -4 -12 L -1 -11 M -3 -12 L -2 -10","-9 9 M 5 -1 L 5 -2 L 4 -2 L 4 0 L 6 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 5 M -3 -3 L -4 -1 L -5 2 L -5 5 L -4 7 M 0 -5 L -2 -3 L -3 -1 L -4 2 L -4 5 L -3 8 L -2 9","-11 11 M 7 -12 L 4 -1 L 3 3 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M 8 -12 L 5 -1 L 4 3 L 4 8 M 4 -12 L 9 -12 L 5 2 L 4 6 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -5 -3 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9 M 5 -12 L 8 -11 M 6 -12 L 7 -10","-9 9 M -5 4 L -1 3 L 2 2 L 5 0 L 6 -2 L 5 -4 L 3 -5 L 0 -5 L -3 -4 L -5 -1 L -6 2 L -6 4 L -5 7 L -4 8 L -2 9 L 0 9 L 3 8 L 5 6 M -3 -3 L -4 -1 L -5 2 L -5 5 L -4 7 M 0 -5 L -2 -3 L -3 -1 L -4 2 L -4 5 L -3 8 L -2 9","-8 8 M 8 -10 L 8 -11 L 7 -11 L 7 -9 L 9 -9 L 9 -11 L 8 -12 L 6 -12 L 4 -11 L 2 -9 L 1 -7 L 0 -4 L -1 0 L -3 9 L -4 12 L -5 14 L -7 16 M 2 -8 L 1 -5 L 0 0 L -2 9 L -3 12 M 6 -12 L 4 -10 L 3 -8 L 2 -5 L 1 0 L -1 8 L -2 11 L -3 13 L -5 15 L -7 16 L -9 16 L -10 15 L -10 13 L -8 13 L -8 15 L -9 15 L -9 14 M -4 -5 L 7 -5","-10 11 M 6 -5 L 2 9 L 1 12 L -1 15 L -3 16 M 7 -5 L 3 9 L 1 13 M 6 -5 L 8 -5 L 4 9 L 2 13 L 0 15 L -3 16 L -6 16 L -8 15 L -9 14 L -9 12 L -7 12 L -7 14 L -8 14 L -8 13 M 4 2 L 4 -1 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 4 L -6 7 L -5 8 L -3 9 L -1 9 L 1 8 L 2 7 L 3 5 L 4 2 M -4 -3 L -5 -1 L -6 2 L -6 5 L -5 7 M -1 -5 L -3 -3 L -4 -1 L -5 2 L -5 5 L -4 8 L -3 9","-11 11 M -3 -12 L -9 9 L -7 9 M -2 -12 L -8 9 M -6 -12 L -1 -12 L -7 9 M -5 2 L -3 -2 L -1 -4 L 1 -5 L 3 -5 L 5 -4 L 6 -2 L 6 1 L 4 6 M 5 -4 L 5 0 L 4 4 L 4 8 M 5 -2 L 3 3 L 3 6 L 4 8 L 5 9 L 7 9 L 9 7 L 10 5 M -5 -12 L -2 -11 M -4 -12 L -3 -10","-7 6 M 1 -12 L 1 -10 L 3 -10 L 3 -12 L 1 -12 M 2 -12 L 2 -10 M 1 -11 L 3 -11 M -6 -1 L -5 -3 L -3 -5 L -1 -5 L 0 -4 L 1 -2 L 1 1 L -1 6 M 0 -4 L 0 0 L -1 4 L -1 8 M 0 -2 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5","-7 6 M 3 -12 L 3 -10 L 5 -10 L 5 -12 L 3 -12 M 4 -12 L 4 -10 M 3 -11 L 5 -11 M -5 -1 L -4 -3 L -2 -5 L 0 -5 L 1 -4 L 2 -2 L 2 1 L 0 8 L -1 11 L -2 13 L -4 15 L -6 16 L -8 16 L -9 15 L -9 13 L -7 13 L -7 15 L -8 15 L -8 14 M 1 -4 L 1 1 L -1 8 L -2 11 L -3 13 M 1 -2 L 0 2 L -2 9 L -3 12 L -4 14 L -6 16","-11 11 M -3 -12 L -9 9 L -7 9 M -2 -12 L -8 9 M -6 -12 L -1 -12 L -7 9 M 7 -3 L 7 -4 L 6 -4 L 6 -2 L 8 -2 L 8 -4 L 7 -5 L 5 -5 L 3 -4 L -1 0 L -3 1 M -5 1 L -3 1 L -1 2 L 0 3 L 2 7 L 3 8 L 5 8 M -1 3 L 1 7 L 2 8 M -3 1 L -2 2 L 0 8 L 1 9 L 3 9 L 5 8 L 7 5 M -5 -12 L -2 -11 M -4 -12 L -3 -10","-6 6 M 2 -12 L -1 -1 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5 M 3 -12 L 0 -1 L -1 3 L -1 8 M -1 -12 L 4 -12 L 0 2 L -1 6 M 0 -12 L 3 -11 M 1 -12 L 2 -10","-18 17 M -17 -1 L -16 -3 L -14 -5 L -12 -5 L -11 -4 L -10 -2 L -10 1 L -12 9 M -11 -4 L -11 1 L -13 9 M -11 -2 L -12 2 L -14 9 L -12 9 M -10 1 L -8 -2 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -2 L 1 1 L -1 9 M 0 -4 L 0 1 L -2 9 M 0 -2 L -1 2 L -3 9 L -1 9 M 1 1 L 3 -2 L 5 -4 L 7 -5 L 9 -5 L 11 -4 L 12 -2 L 12 1 L 10 6 M 11 -4 L 11 0 L 10 4 L 10 8 M 11 -2 L 9 3 L 9 6 L 10 8 L 11 9 L 13 9 L 15 7 L 16 5","-12 12 M -11 -1 L -10 -3 L -8 -5 L -6 -5 L -5 -4 L -4 -2 L -4 1 L -6 9 M -5 -4 L -5 1 L -7 9 M -5 -2 L -6 2 L -8 9 L -6 9 M -4 1 L -2 -2 L 0 -4 L 2 -5 L 4 -5 L 6 -4 L 7 -2 L 7 1 L 5 6 M 6 -4 L 6 0 L 5 4 L 5 8 M 6 -2 L 4 3 L 4 6 L 5 8 L 6 9 L 8 9 L 10 7 L 11 5","-10 10 M -1 -5 L -4 -4 L -6 -1 L -7 2 L -7 4 L -6 7 L -5 8 L -2 9 L 1 9 L 4 8 L 6 5 L 7 2 L 7 0 L 6 -3 L 5 -4 L 2 -5 L -1 -5 M -4 -3 L -5 -1 L -6 2 L -6 5 L -5 7 M 4 7 L 5 5 L 6 2 L 6 -1 L 5 -3 M -1 -5 L -3 -3 L -4 -1 L -5 2 L -5 5 L -4 8 L -2 9 M 1 9 L 3 7 L 4 5 L 5 2 L 5 -1 L 4 -4 L 2 -5","-11 11 M -10 -1 L -9 -3 L -7 -5 L -5 -5 L -4 -4 L -3 -2 L -3 1 L -4 5 L -7 16 M -4 -4 L -4 1 L -5 5 L -8 16 M -4 -2 L -5 2 L -9 16 M -3 2 L -2 -1 L -1 -3 L 0 -4 L 2 -5 L 4 -5 L 6 -4 L 7 -3 L 8 0 L 8 2 L 7 5 L 5 8 L 2 9 L 0 9 L -2 8 L -3 5 L -3 2 M 6 -3 L 7 -1 L 7 2 L 6 5 L 5 7 M 4 -5 L 5 -4 L 6 -1 L 6 2 L 5 5 L 4 7 L 2 9 M -12 16 L -4 16 M -8 15 L -11 16 M -8 14 L -10 16 M -7 14 L -6 16 M -8 15 L -5 16","-11 10 M 5 -5 L -1 16 M 6 -5 L 0 16 M 5 -5 L 7 -5 L 1 16 M 3 2 L 3 -1 L 2 -4 L 0 -5 L -2 -5 L -5 -4 L -7 -1 L -8 2 L -8 4 L -7 7 L -6 8 L -4 9 L -2 9 L 0 8 L 1 7 L 2 5 L 3 2 M -5 -3 L -6 -1 L -7 2 L -7 5 L -6 7 M -2 -5 L -4 -3 L -5 -1 L -6 2 L -6 5 L -5 8 L -4 9 M -4 16 L 4 16 M 0 15 L -3 16 M 0 14 L -2 16 M 1 14 L 2 16 M 0 15 L 3 16","-9 9 M -8 -1 L -7 -3 L -5 -5 L -3 -5 L -2 -4 L -1 -2 L -1 2 L -3 9 M -2 -4 L -2 2 L -4 9 M -2 -2 L -3 2 L -5 9 L -3 9 M 7 -3 L 7 -4 L 6 -4 L 6 -2 L 8 -2 L 8 -4 L 7 -5 L 5 -5 L 3 -4 L 1 -2 L -1 2","-8 9 M 6 -2 L 6 -3 L 5 -3 L 5 -1 L 7 -1 L 7 -3 L 6 -4 L 3 -5 L 0 -5 L -3 -4 L -4 -3 L -4 -1 L -3 1 L -1 2 L 2 3 L 4 4 L 5 6 M -3 -4 L -4 -1 M -3 0 L -1 1 L 2 2 L 4 3 M 5 4 L 4 8 M -4 -3 L -3 -1 L -1 0 L 2 1 L 4 2 L 5 4 L 5 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -6 5 L -4 5 L -4 7 L -5 7 L -5 6","-7 7 M 2 -12 L -1 -1 L -2 3 L -2 6 L -1 8 L 0 9 L 2 9 L 4 7 L 5 5 M 3 -12 L 0 -1 L -1 3 L -1 8 M 2 -12 L 4 -12 L 0 2 L -1 6 M -4 -5 L 6 -5","-12 12 M -11 -1 L -10 -3 L -8 -5 L -6 -5 L -5 -4 L -4 -2 L -4 1 L -6 6 M -5 -4 L -5 0 L -6 4 L -6 8 M -5 -2 L -7 3 L -7 6 L -6 8 L -4 9 L -2 9 L 0 8 L 2 6 L 4 3 M 6 -5 L 4 3 L 4 6 L 5 8 L 6 9 L 8 9 L 10 7 L 11 5 M 7 -5 L 5 3 L 5 8 M 6 -5 L 8 -5 L 6 2 L 5 6","-10 10 M -9 -1 L -8 -3 L -6 -5 L -4 -5 L -3 -4 L -2 -2 L -2 1 L -4 6 M -3 -4 L -3 0 L -4 4 L -4 8 M -3 -2 L -5 3 L -5 6 L -4 8 L -2 9 L 0 9 L 2 8 L 4 6 L 6 3 L 7 -1 L 7 -5 L 6 -5 L 6 -4 L 7 -2","-15 15 M -14 -1 L -13 -3 L -11 -5 L -9 -5 L -8 -4 L -7 -2 L -7 1 L -9 6 M -8 -4 L -8 0 L -9 4 L -9 8 M -8 -2 L -10 3 L -10 6 L -9 8 L -7 9 L -5 9 L -3 8 L -1 6 L 0 3 M 2 -5 L 0 3 L 0 6 L 1 8 L 3 9 L 5 9 L 7 8 L 9 6 L 11 3 L 12 -1 L 12 -5 L 11 -5 L 11 -4 L 12 -2 M 3 -5 L 1 3 L 1 8 M 2 -5 L 4 -5 L 2 2 L 1 6","-11 11 M -8 -1 L -6 -4 L -4 -5 L -2 -5 L 0 -4 L 1 -2 L 1 0 M -2 -5 L -1 -4 L -1 0 L -2 4 L -3 6 L -5 8 L -7 9 L -9 9 L -10 8 L -10 6 L -8 6 L -8 8 L -9 8 L -9 7 M 0 -3 L 0 0 L -1 4 L -1 7 M 8 -3 L 8 -4 L 7 -4 L 7 -2 L 9 -2 L 9 -4 L 8 -5 L 6 -5 L 4 -4 L 2 -2 L 1 0 L 0 4 L 0 8 L 1 9 M -2 4 L -2 6 L -1 8 L 1 9 L 3 9 L 5 8 L 7 5","-11 11 M -10 -1 L -9 -3 L -7 -5 L -5 -5 L -4 -4 L -3 -2 L -3 1 L -5 6 M -4 -4 L -4 0 L -5 4 L -5 8 M -4 -2 L -6 3 L -6 6 L -5 8 L -3 9 L -1 9 L 1 8 L 3 6 L 5 2 M 7 -5 L 3 9 L 2 12 L 0 15 L -2 16 M 8 -5 L 4 9 L 2 13 M 7 -5 L 9 -5 L 5 9 L 3 13 L 1 15 L -2 16 L -5 16 L -7 15 L -8 14 L -8 12 L -6 12 L -6 14 L -7 14 L -7 13","-10 10 M 7 -5 L 6 -3 L 4 -1 L -4 5 L -6 7 L -7 9 M 6 -3 L -3 -3 L -5 -2 L -6 0 M 4 -3 L 0 -4 L -3 -4 L -4 -3 M 4 -3 L 0 -5 L -3 -5 L -5 -3 L -6 0 M -6 7 L 3 7 L 5 6 L 6 4 M -4 7 L 0 8 L 3 8 L 4 7 M -4 7 L 0 9 L 3 9 L 5 7 L 6 4","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -timesr = ["-8 8","-5 5 M 0 -12 L -1 -10 L 0 2 L 1 -10 L 0 -12 M 0 -10 L 0 -4 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 6 -9 L 5 -8 L 6 -7 L 7 -8 L 7 -9 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 7 2 M -7 -7 L -5 -5 L -3 -4 L 3 -2 L 5 -1 L 6 0 L 7 2 L 7 6 L 5 8 L 2 9 L -2 9 L -5 8 L -7 6 L -7 5 L -6 4 L -5 5 L -6 6","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-12 13 M 9 -4 L 8 -3 L 9 -2 L 10 -3 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -5 9 L -8 8 L -9 6 L -9 3 L -8 1 L -2 -3 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -7 L -4 -4 L -2 -1 L 3 6 L 5 8 L 8 9 L 9 9 L 10 8 L 10 7 M -5 9 L -7 8 L -8 6 L -8 3 L -7 1 L -5 -1 M -5 -7 L -4 -5 L 4 6 L 6 8 L 8 9","-4 4 M 0 -12 L -1 -5 M 1 -12 L -1 -5","-7 7 M 4 -16 L 2 -14 L 0 -11 L -2 -7 L -3 -2 L -3 2 L -2 7 L 0 11 L 2 14 L 4 16 M 2 -14 L 0 -10 L -1 -7 L -2 -2 L -2 2 L -1 7 L 0 10 L 2 14","-7 7 M -4 -16 L -2 -14 L 0 -11 L 2 -7 L 3 -2 L 3 2 L 2 7 L 0 11 L -2 14 L -4 16 M -2 -14 L 0 -10 L 1 -7 L 2 -2 L 2 2 L 1 7 L 0 10 L -2 14","-8 8 M 0 -6 L 0 6 M -5 -3 L 5 3 M 5 -3 L -5 3","-13 13 M 0 -9 L 0 9 M -9 0 L 9 0","-4 4 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-13 13 M -9 0 L 9 0","-4 4 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-11 11 M 9 -16 L -9 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -4 -10 L -5 -8 L -6 -3 L -6 0 L -5 5 L -4 7 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 5 L 6 0 L 6 -3 L 5 -8 L 4 -10 L 3 -11 L 1 -12","-10 10 M -4 -8 L -2 -9 L 1 -12 L 1 9 M 0 -11 L 0 9 M -4 9 L 5 9","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 3 -2 L -2 0 L -4 1 L -6 3 L -7 6 L -7 9 M 2 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 2 -2 L -2 0 M -7 7 L -6 6 L -4 6 L 1 8 L 4 8 L 6 7 L 7 6 M -4 6 L 1 9 L 5 9 L 6 8 L 7 6 L 7 4","-10 10 M -6 -8 L -5 -7 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 L -1 -3 M 2 -12 L 4 -11 L 5 -9 L 5 -6 L 4 -4 L 2 -3 M 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 5 -1 L 6 2 L 6 5 L 5 7 L 4 8 L 2 9","-10 10 M 2 -10 L 2 9 M 3 -12 L 3 9 M 3 -12 L -8 3 L 8 3 M -1 9 L 6 9","-10 10 M -5 -12 L -7 -2 M -7 -2 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 4 L -6 5 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -5 -12 L 5 -12 M -5 -11 L 0 -11 L 5 -12","-10 10 M 5 -9 L 4 -8 L 5 -7 L 6 -8 L 6 -9 L 5 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L 0 -4 L -3 -3 L -5 -1 L -6 2 M 0 -12 L -2 -11 L -4 -9 L -5 -7 L -6 -3 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 2 L 5 -1 L 3 -3 L 1 -4","-10 10 M -7 -12 L -7 -6 M -7 -8 L -6 -10 L -4 -12 L -2 -12 L 3 -9 L 5 -9 L 6 -10 L 7 -12 M -6 -10 L -4 -11 L -2 -11 L 3 -9 M 7 -12 L 7 -9 L 6 -6 L 2 -1 L 1 1 L 0 4 L 0 9 M 6 -6 L 1 -1 L 0 1 L -1 4 L -1 9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 6 -6 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -2 -12 L -4 -11 L -5 -9 L -5 -6 L -4 -4 L -2 -3 M 2 -3 L 4 -4 L 5 -6 L 5 -9 L 4 -11 L 2 -12 M -2 -3 L -5 -2 L -6 -1 L -7 1 L -7 5 L -6 7 L -5 8 L -2 9 L 2 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 2 -3 M -2 -3 L -4 -2 L -5 -1 L -6 1 L -6 5 L -5 7 L -4 8 L -2 9 M 2 9 L 4 8 L 5 7 L 6 5 L 6 1 L 5 -1 L 4 -2 L 2 -3","-10 10 M 6 -5 L 5 -2 L 3 0 L 0 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 0 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 5 L -5 6 M -1 1 L -3 0 L -5 -2 L -6 -5 L -6 -6 L -5 -9 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 5 -9 L 6 -6 L 6 0 L 5 4 L 4 6 L 2 8 L 0 9","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 0 4 L -1 5 L 0 6 L 1 5 L 0 4","-4 4 M 0 -3 L -1 -2 L 0 -1 L 1 -2 L 0 -3 M 1 5 L 0 6 L -1 5 L 0 4 L 1 5 L 1 7 L -1 9","-12 12 M 8 -9 L -8 0 L 8 9","-13 13 M -9 -3 L 9 -3 M -9 3 L 9 3","-12 12 M -8 -9 L 8 0 L -8 9","-9 9 M -5 -8 L -4 -7 L -5 -6 L -6 -7 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 1 -12 L 4 -11 L 5 -10 L 6 -8 L 6 -6 L 5 -4 L 4 -3 L 0 -1 L 0 2 M 1 -12 L 3 -11 L 4 -10 L 5 -8 L 5 -6 L 4 -4 L 2 -2 M 0 7 L -1 8 L 0 9 L 1 8 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 0 -12 L -7 9 M 0 -12 L 7 9 M 0 -9 L 6 9 M -5 3 L 4 3 M -9 9 L -3 9 M 3 9 L 9 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 3 -2 M -5 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 3 -2 L 5 -1 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 3 9","-11 10 M 6 -9 L 7 -6 L 7 -12 L 6 -9 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -9 9 M 1 -12 L 3 -11 L 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 L 3 8 L 1 9","-11 10 M -6 -12 L -6 9 M -5 -12 L -5 9 M 1 -6 L 1 2 M -9 -12 L 7 -12 L 7 -6 L 6 -12 M -5 -2 L 1 -2 M -9 9 L 7 9 L 7 3 L 6 9","-11 9 M -6 -12 L -6 9 M -5 -12 L -5 9 M 1 -6 L 1 2 M -9 -12 L 7 -12 L 7 -6 L 6 -12 M -5 -2 L 1 -2 M -9 9 L -2 9","-11 12 M 6 -9 L 7 -6 L 7 -12 L 6 -9 L 4 -11 L 1 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 L -3 8 L -1 9 M 6 1 L 6 9 M 7 1 L 7 9 M 3 1 L 10 1","-12 12 M -7 -12 L -7 9 M -6 -12 L -6 9 M 6 -12 L 6 9 M 7 -12 L 7 9 M -10 -12 L -3 -12 M 3 -12 L 10 -12 M -6 -2 L 6 -2 M -10 9 L -3 9 M 3 9 L 10 9","-5 6 M 0 -12 L 0 9 M 1 -12 L 1 9 M -3 -12 L 4 -12 M -3 9 L 4 9","-7 8 M 3 -12 L 3 5 L 2 8 L 0 9 L -2 9 L -4 8 L -5 6 L -5 4 L -4 3 L -3 4 L -4 5 M 2 -12 L 2 5 L 1 8 L 0 9 M -1 -12 L 6 -12","-12 10 M -7 -12 L -7 9 M -6 -12 L -6 9 M 7 -12 L -6 1 M -1 -3 L 7 9 M -2 -3 L 6 9 M -10 -12 L -3 -12 M 3 -12 L 9 -12 M -10 9 L -3 9 M 3 9 L 9 9","-9 9 M -4 -12 L -4 9 M -3 -12 L -3 9 M -7 -12 L 0 -12 M -7 9 L 8 9 L 8 3 L 7 9","-12 13 M -7 -12 L -7 9 M -6 -12 L 0 6 M -7 -12 L 0 9 M 7 -12 L 0 9 M 7 -12 L 7 9 M 8 -12 L 8 9 M -10 -12 L -6 -12 M 7 -12 L 11 -12 M -10 9 L -4 9 M 4 9 L 11 9","-11 12 M -6 -12 L -6 9 M -5 -12 L 7 7 M -5 -10 L 7 9 M 7 -12 L 7 9 M -9 -12 L -5 -12 M 4 -12 L 10 -12 M -9 9 L -3 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 0 L -6 4 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 4 L 7 0 L 7 -3 L 6 -7 L 5 -9 L 3 -11 L 1 -12","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -5 -1 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -5 L 6 -3 L 5 -2 L 3 -1 M -9 9 L -2 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -1 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 0 L -6 4 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 4 L 7 0 L 7 -3 L 6 -7 L 5 -9 L 3 -11 L 1 -12 M -4 7 L -4 6 L -3 4 L -1 3 L 0 3 L 2 4 L 3 6 L 4 13 L 5 14 L 7 14 L 8 12 L 8 11 M 3 6 L 4 10 L 5 12 L 6 13 L 7 13 L 8 12","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 L -5 -2 M 3 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 3 -2 M -9 9 L -2 9 M 0 -2 L 2 -1 L 3 0 L 6 7 L 7 8 L 8 8 L 9 7 M 2 -1 L 3 1 L 5 8 L 6 9 L 8 9 L 9 7 L 9 6","-10 10 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 1 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -7 L -6 -5 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 7 2 M -7 -7 L -5 -5 L -3 -4 L 3 -2 L 5 -1 L 6 0 L 7 2 L 7 6 L 5 8 L 2 9 L -1 9 L -4 8 L -6 6 L -7 3 L -7 9 L -6 6","-9 10 M 0 -12 L 0 9 M 1 -12 L 1 9 M -6 -12 L -7 -6 L -7 -12 L 8 -12 L 8 -6 L 7 -12 M -3 9 L 4 9","-12 12 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -12 M -6 -12 L -6 3 L -5 6 L -3 8 L -1 9 M -10 -12 L -3 -12 M 4 -12 L 10 -12","-10 10 M -7 -12 L 0 9 M -6 -12 L 0 6 M 7 -12 L 0 9 M -9 -12 L -3 -12 M 3 -12 L 9 -12","-12 12 M -8 -12 L -4 9 M -7 -12 L -4 4 M 0 -12 L -4 9 M 0 -12 L 4 9 M 1 -12 L 4 4 M 8 -12 L 4 9 M -11 -12 L -4 -12 M 5 -12 L 11 -12","-10 10 M -7 -12 L 6 9 M -6 -12 L 7 9 M 7 -12 L -7 9 M -9 -12 L -3 -12 M 3 -12 L 9 -12 M -9 9 L -3 9 M 3 9 L 9 9","-10 11 M -7 -12 L 0 -1 L 0 9 M -6 -12 L 1 -1 L 1 9 M 8 -12 L 1 -1 M -9 -12 L -3 -12 M 4 -12 L 10 -12 M -3 9 L 4 9","-10 10 M 6 -12 L -7 9 M 7 -12 L -6 9 M -6 -12 L -7 -6 L -7 -12 L 7 -12 M -7 9 L 7 9 L 7 3 L 6 9","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-9 11 M -4 -3 L -4 -2 L -5 -2 L -5 -3 L -4 -4 L -2 -5 L 2 -5 L 4 -4 L 5 -3 L 6 -1 L 6 6 L 7 8 L 8 9 M 5 -3 L 5 6 L 6 8 L 8 9 L 9 9 M 5 -1 L 4 0 L -2 1 L -5 2 L -6 4 L -6 6 L -5 8 L -2 9 L 1 9 L 3 8 L 5 6 M -2 1 L -4 2 L -5 4 L -5 6 L -4 8 L -2 9","-11 10 M -6 -12 L -6 9 M -5 -12 L -5 9 M -5 -2 L -3 -4 L -1 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -1 9 L -3 8 L -5 6 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -9 -12 L -5 -12","-10 9 M 5 -2 L 4 -1 L 5 0 L 6 -1 L 6 -2 L 4 -4 L 2 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9","-10 11 M 5 -12 L 5 9 M 6 -12 L 6 9 M 5 -2 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 3 8 L 5 6 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 M 2 -12 L 6 -12 M 5 9 L 9 9","-10 9 M -6 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M 5 1 L 5 -2 L 4 -4 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9","-7 6 M 3 -11 L 2 -10 L 3 -9 L 4 -10 L 4 -11 L 3 -12 L 1 -12 L -1 -11 L -2 -9 L -2 9 M 1 -12 L 0 -11 L -1 -9 L -1 9 M -5 -5 L 3 -5 M -5 9 L 2 9","-9 10 M -1 -5 L -3 -4 L -4 -3 L -5 -1 L -5 1 L -4 3 L -3 4 L -1 5 L 1 5 L 3 4 L 4 3 L 5 1 L 5 -1 L 4 -3 L 3 -4 L 1 -5 L -1 -5 M -3 -4 L -4 -2 L -4 2 L -3 4 M 3 4 L 4 2 L 4 -2 L 3 -4 M 4 -3 L 5 -4 L 7 -5 L 7 -4 L 5 -4 M -4 3 L -5 4 L -6 6 L -6 7 L -5 9 L -2 10 L 3 10 L 6 11 L 7 12 M -6 7 L -5 8 L -2 9 L 3 9 L 6 10 L 7 12 L 7 13 L 6 15 L 3 16 L -3 16 L -6 15 L -7 13 L -7 12 L -6 10 L -3 9","-11 11 M -6 -12 L -6 9 M -5 -12 L -5 9 M -5 -2 L -3 -4 L 0 -5 L 2 -5 L 5 -4 L 6 -2 L 6 9 M 2 -5 L 4 -4 L 5 -2 L 5 9 M -9 -12 L -5 -12 M -9 9 L -2 9 M 2 9 L 9 9","-5 6 M 0 -12 L -1 -11 L 0 -10 L 1 -11 L 0 -12 M 0 -5 L 0 9 M 1 -5 L 1 9 M -3 -5 L 1 -5 M -3 9 L 4 9","-5 6 M 1 -12 L 0 -11 L 1 -10 L 2 -11 L 1 -12 M 2 -5 L 2 13 L 1 15 L -1 16 L -3 16 L -4 15 L -4 14 L -3 13 L -2 14 L -3 15 M 1 -5 L 1 13 L 0 15 L -1 16 M -2 -5 L 2 -5","-11 10 M -6 -12 L -6 9 M -5 -12 L -5 9 M 5 -5 L -5 5 M 0 1 L 6 9 M -1 1 L 5 9 M -9 -12 L -5 -12 M 2 -5 L 8 -5 M -9 9 L -2 9 M 2 9 L 8 9","-5 6 M 0 -12 L 0 9 M 1 -12 L 1 9 M -3 -12 L 1 -12 M -3 9 L 4 9","-16 17 M -11 -5 L -11 9 M -10 -5 L -10 9 M -10 -2 L -8 -4 L -5 -5 L -3 -5 L 0 -4 L 1 -2 L 1 9 M -3 -5 L -1 -4 L 0 -2 L 0 9 M 1 -2 L 3 -4 L 6 -5 L 8 -5 L 11 -4 L 12 -2 L 12 9 M 8 -5 L 10 -4 L 11 -2 L 11 9 M -14 -5 L -10 -5 M -14 9 L -7 9 M -3 9 L 4 9 M 8 9 L 15 9","-11 11 M -6 -5 L -6 9 M -5 -5 L -5 9 M -5 -2 L -3 -4 L 0 -5 L 2 -5 L 5 -4 L 6 -2 L 6 9 M 2 -5 L 4 -4 L 5 -2 L 5 9 M -9 -5 L -5 -5 M -9 9 L -2 9 M 2 9 L 9 9","-10 10 M -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 1 -5 L -1 -5 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 M 1 9 L 3 8 L 5 6 L 6 3 L 6 1 L 5 -2 L 3 -4 L 1 -5","-11 10 M -6 -5 L -6 16 M -5 -5 L -5 16 M -5 -2 L -3 -4 L -1 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -1 9 L -3 8 L -5 6 M 1 -5 L 3 -4 L 5 -2 L 6 1 L 6 3 L 5 6 L 3 8 L 1 9 M -9 -5 L -5 -5 M -9 16 L -2 16","-10 10 M 5 -5 L 5 16 M 6 -5 L 6 16 M 5 -2 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 3 8 L 5 6 M -1 -5 L -3 -4 L -5 -2 L -6 1 L -6 3 L -5 6 L -3 8 L -1 9 M 2 16 L 9 16","-9 8 M -4 -5 L -4 9 M -3 -5 L -3 9 M -3 1 L -2 -2 L 0 -4 L 2 -5 L 5 -5 L 6 -4 L 6 -3 L 5 -2 L 4 -3 L 5 -4 M -7 -5 L -3 -5 M -7 9 L 0 9","-8 9 M 5 -3 L 6 -5 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -2 -5 L -4 -4 L -5 -3 L -5 -1 L -4 0 L -2 1 L 3 3 L 5 4 L 6 5 M -5 -2 L -4 -1 L -2 0 L 3 2 L 5 3 L 6 4 L 6 7 L 5 8 L 3 9 L -1 9 L -3 8 L -4 7 L -5 5 L -5 9 L -4 7","-7 8 M -2 -12 L -2 5 L -1 8 L 1 9 L 3 9 L 5 8 L 6 6 M -1 -12 L -1 5 L 0 8 L 1 9 M -5 -5 L 3 -5","-11 11 M -6 -5 L -6 6 L -5 8 L -2 9 L 0 9 L 3 8 L 5 6 M -5 -5 L -5 6 L -4 8 L -2 9 M 5 -5 L 5 9 M 6 -5 L 6 9 M -9 -5 L -5 -5 M 2 -5 L 6 -5 M 5 9 L 9 9","-9 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M 6 -5 L 0 9 M -8 -5 L -2 -5 M 2 -5 L 8 -5","-12 12 M -8 -5 L -4 9 M -7 -5 L -4 6 M 0 -5 L -4 9 M 0 -5 L 4 9 M 1 -5 L 4 6 M 8 -5 L 4 9 M -11 -5 L -4 -5 M 5 -5 L 11 -5","-10 10 M -6 -5 L 5 9 M -5 -5 L 6 9 M 6 -5 L -6 9 M -8 -5 L -2 -5 M 2 -5 L 8 -5 M -8 9 L -2 9 M 2 9 L 8 9","-10 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M 6 -5 L 0 9 L -2 13 L -4 15 L -6 16 L -7 16 L -8 15 L -7 14 L -6 15 M -8 -5 L -2 -5 M 2 -5 L 8 -5","-9 9 M 5 -5 L -6 9 M 6 -5 L -5 9 M -5 -5 L -6 -1 L -6 -5 L 6 -5 M -6 9 L 6 9 L 6 5 L 5 9","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"] -timesrb = ["-8 8","-5 6 M 0 -12 L -1 -11 L -1 -9 L 0 -1 M 0 -12 L 0 2 L 1 2 M 0 -12 L 1 -12 L 1 2 M 1 -12 L 2 -11 L 2 -9 L 1 -1 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-9 9 M -4 -12 L -5 -11 L -5 -5 M -4 -11 L -5 -5 M -4 -12 L -3 -11 L -5 -5 M 5 -12 L 4 -11 L 4 -5 M 5 -11 L 4 -5 M 5 -12 L 6 -11 L 4 -5","-10 11 M 1 -16 L -6 16 M 7 -16 L 0 16 M -6 -3 L 8 -3 M -7 3 L 7 3","-10 10 M -2 -16 L -2 13 M 2 -16 L 2 13 M 6 -7 L 6 -8 L 5 -8 L 5 -6 L 7 -6 L 7 -8 L 6 -10 L 5 -11 L 2 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 3 L -5 3 L -5 5 L -6 5 L -6 4","-12 12 M 9 -12 L -9 9 M -4 -12 L -2 -10 L -2 -8 L -3 -6 L -5 -5 L -7 -5 L -9 -7 L -9 -9 L -8 -11 L -6 -12 L -4 -12 L -2 -11 L 1 -10 L 4 -10 L 7 -11 L 9 -12 M 5 2 L 3 3 L 2 5 L 2 7 L 4 9 L 6 9 L 8 8 L 9 6 L 9 4 L 7 2 L 5 2","-13 13 M 9 -3 L 9 -4 L 8 -4 L 8 -2 L 10 -2 L 10 -4 L 9 -5 L 8 -5 L 7 -4 L 6 -2 L 4 3 L 2 6 L 0 8 L -2 9 L -6 9 L -8 8 L -9 6 L -9 3 L -8 1 L -2 -3 L 0 -5 L 1 -7 L 1 -9 L 0 -11 L -2 -12 L -4 -11 L -5 -9 L -5 -6 L -4 -3 L -2 0 L 2 5 L 5 8 L 7 9 L 9 9 L 10 7 L 10 6 M -7 8 L -8 6 L -8 3 L -7 1 L -6 0 M 0 -5 L 1 -9 M 1 -7 L 0 -11 M -4 -11 L -5 -7 M -4 -4 L -2 -1 L 2 4 L 5 7 L 7 8 M -4 9 L -6 8 L -7 6 L -7 3 L -6 1 L -2 -3 M -5 -9 L -4 -5 L -1 -1 L 3 4 L 6 7 L 8 8 L 9 8 L 10 7","-4 5 M 1 -12 L 0 -11 L 0 -5 M 1 -11 L 0 -5 M 1 -12 L 2 -11 L 0 -5","-7 7 M 3 -16 L 1 -14 L -1 -11 L -3 -7 L -4 -2 L -4 2 L -3 7 L -1 11 L 1 14 L 3 16 M -1 -10 L -2 -7 L -3 -3 L -3 3 L -2 7 L -1 10 M 1 -14 L 0 -12 L -1 -9 L -2 -3 L -2 3 L -1 9 L 0 12 L 1 14","-7 7 M -3 -16 L -1 -14 L 1 -11 L 3 -7 L 4 -2 L 4 2 L 3 7 L 1 11 L -1 14 L -3 16 M 1 -10 L 2 -7 L 3 -3 L 3 3 L 2 7 L 1 10 M -1 -14 L 0 -12 L 1 -9 L 2 -3 L 2 3 L 1 9 L 0 12 L -1 14","-8 8 M 0 -12 L -1 -11 L 1 -1 L 0 0 M 0 -12 L 0 0 M 0 -12 L 1 -11 L -1 -1 L 0 0 M -5 -9 L -4 -9 L 4 -3 L 5 -3 M -5 -9 L 5 -3 M -5 -9 L -5 -8 L 5 -4 L 5 -3 M 5 -9 L 4 -9 L -4 -3 L -5 -3 M 5 -9 L -5 -3 M 5 -9 L 5 -8 L -5 -4 L -5 -3","-12 13 M 0 -9 L 0 8 L 1 8 M 0 -9 L 1 -9 L 1 8 M -8 -1 L 9 -1 L 9 0 M -8 -1 L -8 0 L 9 0","-5 6 M 2 8 L 1 9 L 0 9 L -1 8 L -1 7 L 0 6 L 1 6 L 2 7 L 2 10 L 1 12 L -1 13 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7 M 1 9 L 2 10 M 2 8 L 1 12","-13 13 M -9 0 L 9 0","-5 6 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-11 12 M 9 -16 L -9 16 L -8 16 M 9 -16 L 10 -16 L -8 16","-10 10 M -1 -12 L -4 -11 L -6 -8 L -7 -3 L -7 0 L -6 5 L -4 8 L -1 9 L 1 9 L 4 8 L 6 5 L 7 0 L 7 -3 L 6 -8 L 4 -11 L 1 -12 L -1 -12 M -4 -10 L -5 -8 L -6 -4 L -6 1 L -5 5 L -4 7 M 4 7 L 5 5 L 6 1 L 6 -4 L 5 -8 L 4 -10 M -1 -12 L -3 -11 L -4 -9 L -5 -4 L -5 1 L -4 6 L -3 8 L -1 9 M 1 9 L 3 8 L 4 6 L 5 1 L 5 -4 L 4 -9 L 3 -11 L 1 -12","-10 10 M -1 -10 L -1 9 M 0 -10 L 0 8 M 1 -12 L 1 9 M 1 -12 L -2 -9 L -4 -8 M -5 9 L 5 9 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-10 10 M -6 -8 L -6 -7 L -5 -7 L -5 -8 L -6 -8 M -6 -9 L -5 -9 L -4 -8 L -4 -7 L -5 -6 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 3 -2 L -2 0 L -4 1 L -6 3 L -7 6 L -7 9 M 5 -10 L 6 -8 L 6 -6 L 5 -4 M 2 -12 L 4 -11 L 5 -8 L 5 -6 L 4 -4 L 2 -2 L -2 0 M -7 7 L -6 6 L -4 6 L 1 7 L 5 7 L 7 6 M -4 6 L 1 8 L 5 8 L 6 7 M -4 6 L 1 9 L 5 9 L 6 8 L 7 6 L 7 4","-10 10 M -6 -8 L -6 -7 L -5 -7 L -5 -8 L -6 -8 M -6 -9 L -5 -9 L -4 -8 L -4 -7 L -5 -6 L -6 -6 L -7 -7 L -7 -8 L -6 -10 L -5 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -9 L 6 -6 L 5 -4 L 2 -3 M 4 -11 L 5 -9 L 5 -6 L 4 -4 M 1 -12 L 3 -11 L 4 -9 L 4 -6 L 3 -4 L 1 -3 M -1 -3 L 2 -3 L 4 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 3 L -4 4 L -4 5 L -5 6 L -6 6 M 5 0 L 6 2 L 6 5 L 5 7 M 1 -3 L 3 -2 L 4 -1 L 5 2 L 5 5 L 4 8 L 2 9 M -6 4 L -6 5 L -5 5 L -5 4 L -6 4","-10 10 M 1 -9 L 1 9 M 2 -10 L 2 8 M 3 -12 L 3 9 M 3 -12 L -8 3 L 8 3 M -2 9 L 6 9 M 1 8 L -1 9 M 1 7 L 0 9 M 3 7 L 4 9 M 3 8 L 5 9","-10 10 M -5 -12 L -7 -2 L -5 -4 L -2 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -2 9 L -5 8 L -6 7 L -7 5 L -7 4 L -6 3 L -5 3 L -4 4 L -4 5 L -5 6 L -6 6 M 5 -2 L 6 0 L 6 4 L 5 6 M 1 -5 L 3 -4 L 4 -3 L 5 0 L 5 4 L 4 7 L 3 8 L 1 9 M -6 4 L -6 5 L -5 5 L -5 4 L -6 4 M -5 -12 L 5 -12 M -5 -11 L 3 -11 M -5 -10 L -1 -10 L 3 -11 L 5 -12","-10 10 M 4 -9 L 4 -8 L 5 -8 L 5 -9 L 4 -9 M 5 -10 L 4 -10 L 3 -9 L 3 -8 L 4 -7 L 5 -7 L 6 -8 L 6 -9 L 5 -11 L 3 -12 L 0 -12 L -3 -11 L -5 -9 L -6 -7 L -7 -3 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 2 L 6 -1 L 4 -3 L 1 -4 L -1 -4 L -3 -3 L -4 -2 L -5 0 M -4 -9 L -5 -7 L -6 -3 L -6 3 L -5 6 L -4 7 M 5 6 L 6 4 L 6 1 L 5 -1 M 0 -12 L -2 -11 L -3 -10 L -4 -8 L -5 -4 L -5 3 L -4 6 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 4 L 5 1 L 4 -2 L 3 -3 L 1 -4","-10 10 M -7 -12 L -7 -6 M 7 -12 L 7 -9 L 6 -6 L 2 -1 L 1 1 L 0 5 L 0 9 M 1 0 L 0 2 L -1 5 L -1 9 M 6 -6 L 1 -1 L -1 2 L -2 5 L -2 9 L 0 9 M -7 -8 L -6 -10 L -4 -12 L -2 -12 L 3 -9 L 5 -9 L 6 -10 L 7 -12 M -5 -10 L -4 -11 L -2 -11 L 0 -10 M -7 -8 L -6 -9 L -4 -10 L -2 -10 L 3 -9","-10 10 M -2 -12 L -5 -11 L -6 -9 L -6 -6 L -5 -4 L -2 -3 L 2 -3 L 5 -4 L 6 -6 L 6 -9 L 5 -11 L 2 -12 L -2 -12 M -4 -11 L -5 -9 L -5 -6 L -4 -4 M 4 -4 L 5 -6 L 5 -9 L 4 -11 M -2 -12 L -3 -11 L -4 -9 L -4 -6 L -3 -4 L -2 -3 M 2 -3 L 3 -4 L 4 -6 L 4 -9 L 3 -11 L 2 -12 M -2 -3 L -5 -2 L -6 -1 L -7 1 L -7 5 L -6 7 L -5 8 L -2 9 L 2 9 L 5 8 L 6 7 L 7 5 L 7 1 L 6 -1 L 5 -2 L 2 -3 M -5 -1 L -6 1 L -6 5 L -5 7 M 5 7 L 6 5 L 6 1 L 5 -1 M -2 -3 L -4 -2 L -5 1 L -5 5 L -4 8 L -2 9 M 2 9 L 4 8 L 5 5 L 5 1 L 4 -2 L 2 -3","-10 10 M -5 5 L -5 6 L -4 6 L -4 5 L -5 5 M 5 -3 L 4 -1 L 3 0 L 1 1 L -1 1 L -4 0 L -6 -2 L -7 -5 L -7 -6 L -6 -9 L -4 -11 L -1 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -6 L 7 0 L 6 4 L 5 6 L 3 8 L 0 9 L -3 9 L -5 8 L -6 6 L -6 5 L -5 4 L -4 4 L -3 5 L -3 6 L -4 7 L -5 7 M -5 -2 L -6 -4 L -6 -7 L -5 -9 M 4 -10 L 5 -9 L 6 -6 L 6 0 L 5 4 L 4 6 M -1 1 L -3 0 L -4 -1 L -5 -4 L -5 -7 L -4 -10 L -3 -11 L -1 -12 M 1 -12 L 3 -11 L 4 -9 L 5 -6 L 5 1 L 4 5 L 3 7 L 2 8 L 0 9","-5 6 M 0 -5 L -1 -4 L -1 -3 L 0 -2 L 1 -2 L 2 -3 L 2 -4 L 1 -5 L 0 -5 M 0 -4 L 0 -3 L 1 -3 L 1 -4 L 0 -4 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-5 6 M 0 -5 L -1 -4 L -1 -3 L 0 -2 L 1 -2 L 2 -3 L 2 -4 L 1 -5 L 0 -5 M 0 -4 L 0 -3 L 1 -3 L 1 -4 L 0 -4 M 2 8 L 1 9 L 0 9 L -1 8 L -1 7 L 0 6 L 1 6 L 2 7 L 2 10 L 1 12 L -1 13 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7 M 1 9 L 2 10 M 2 8 L 1 12","-12 12 M 8 -9 L -8 0 L 8 9","-12 13 M -8 -5 L 9 -5 L 9 -4 M -8 -5 L -8 -4 L 9 -4 M -8 3 L 9 3 L 9 4 M -8 3 L -8 4 L 9 4","-12 12 M -8 -9 L 8 0 L -8 9","-9 10 M -5 -7 L -5 -8 L -4 -8 L -4 -6 L -6 -6 L -6 -8 L -5 -10 L -4 -11 L -2 -12 L 2 -12 L 5 -11 L 6 -10 L 7 -8 L 7 -6 L 6 -4 L 5 -3 L 1 -1 M 5 -10 L 6 -9 L 6 -5 L 5 -4 M 2 -12 L 4 -11 L 5 -9 L 5 -5 L 4 -3 L 3 -2 M 0 -1 L 0 2 L 1 2 L 1 -1 L 0 -1 M 0 6 L -1 7 L -1 8 L 0 9 L 1 9 L 2 8 L 2 7 L 1 6 L 0 6 M 0 7 L 0 8 L 1 8 L 1 7 L 0 7","-13 14 M 5 -4 L 4 -6 L 2 -7 L -1 -7 L -3 -6 L -4 -5 L -5 -2 L -5 1 L -4 3 L -2 4 L 1 4 L 3 3 L 4 1 M -1 -7 L -3 -5 L -4 -2 L -4 1 L -3 3 L -2 4 M 5 -7 L 4 1 L 4 3 L 6 4 L 8 4 L 10 2 L 11 -1 L 11 -3 L 10 -6 L 9 -8 L 7 -10 L 5 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -10 L -8 -8 L -9 -6 L -10 -3 L -10 0 L -9 3 L -8 5 L -6 7 L -4 8 L -1 9 L 2 9 L 5 8 L 7 7 L 8 6 M 6 -7 L 5 1 L 5 3 L 6 4","-10 10 M 0 -12 L -7 8 M -1 -9 L 5 9 M 0 -9 L 6 9 M 0 -12 L 7 9 M -5 3 L 4 3 M -9 9 L -3 9 M 2 9 L 9 9 M -7 8 L -8 9 M -7 8 L -5 9 M 5 8 L 3 9 M 5 7 L 4 9 M 6 7 L 8 9","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 M 6 -10 L 7 -8 L 7 -6 L 6 -4 M 3 -12 L 5 -11 L 6 -9 L 6 -5 L 5 -3 L 3 -2 M -4 -2 L 3 -2 L 6 -1 L 7 0 L 8 2 L 8 5 L 7 7 L 6 8 L 3 9 L -9 9 M 6 0 L 7 2 L 7 5 L 6 7 M 3 -2 L 5 -1 L 6 1 L 6 6 L 5 8 L 3 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 10 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 2 9 L 4 8 L 6 6 L 7 4 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 1 -12 L 4 -11 L 6 -9 L 7 -7 L 8 -4 L 8 1 L 7 4 L 6 6 L 4 8 L 1 9 L -9 9 M 5 -9 L 6 -7 L 7 -4 L 7 1 L 6 4 L 5 6 M 1 -12 L 3 -11 L 5 -8 L 6 -4 L 6 1 L 5 5 L 3 8 L 1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 10 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 7 -12 L 7 -6 M -4 -2 L 2 -2 M 2 -6 L 2 2 M -9 9 L 7 9 L 7 3 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M 2 -12 L 7 -11 M 4 -12 L 7 -10 M 5 -12 L 7 -9 M 6 -12 L 7 -6 M 2 -6 L 1 -2 L 2 2 M 2 -4 L 0 -2 L 2 0 M 2 -3 L -2 -2 L 2 -1 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9 M 2 9 L 7 8 M 4 9 L 7 7 M 5 9 L 7 6 M 6 9 L 7 3","-11 9 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 7 -12 L 7 -6 M -4 -2 L 2 -2 M 2 -6 L 2 2 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M 2 -12 L 7 -11 M 4 -12 L 7 -10 M 5 -12 L 7 -9 M 6 -12 L 7 -6 M 2 -6 L 1 -2 L 2 2 M 2 -4 L 0 -2 L 2 0 M 2 -3 L -2 -2 L 2 -1 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 12 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 2 -12 L -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -4 L -8 1 L -7 4 L -6 6 L -4 8 L -1 9 L 2 9 L 4 8 L 6 8 L 7 9 L 7 1 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 6 2 L 6 7 M 5 1 L 5 7 L 4 8 M 2 1 L 10 1 M 3 1 L 5 2 M 4 1 L 5 3 M 8 1 L 7 3 M 9 1 L 7 2","-12 12 M -7 -12 L -7 9 M -6 -11 L -6 8 M -5 -12 L -5 9 M 5 -12 L 5 9 M 6 -11 L 6 8 M 7 -12 L 7 9 M -10 -12 L -2 -12 M 2 -12 L 10 -12 M -5 -2 L 5 -2 M -10 9 L -2 9 M 2 9 L 10 9 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 3 -12 L 5 -11 M 4 -12 L 5 -10 M 8 -12 L 7 -10 M 9 -12 L 7 -11 M -7 8 L -9 9 M -7 7 L -8 9 M -5 7 L -4 9 M -5 8 L -3 9 M 5 8 L 3 9 M 5 7 L 4 9 M 7 7 L 8 9 M 7 8 L 9 9","-6 6 M -1 -12 L -1 9 M 0 -11 L 0 8 M 1 -12 L 1 9 M -4 -12 L 4 -12 M -4 9 L 4 9 M -3 -12 L -1 -11 M -2 -12 L -1 -10 M 2 -12 L 1 -10 M 3 -12 L 1 -11 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-8 8 M 1 -12 L 1 5 L 0 8 L -1 9 M 2 -11 L 2 5 L 1 8 M 3 -12 L 3 5 L 2 8 L -1 9 L -3 9 L -5 8 L -6 6 L -6 4 L -5 3 L -4 3 L -3 4 L -3 5 L -4 6 L -5 6 M -5 4 L -5 5 L -4 5 L -4 4 L -5 4 M -2 -12 L 6 -12 M -1 -12 L 1 -11 M 0 -12 L 1 -10 M 4 -12 L 3 -10 M 5 -12 L 3 -11","-12 10 M -7 -12 L -7 9 M -6 -11 L -6 8 M -5 -12 L -5 9 M 6 -11 L -5 0 M -2 -2 L 5 9 M -1 -2 L 6 9 M -1 -4 L 7 9 M -10 -12 L -2 -12 M 3 -12 L 9 -12 M -10 9 L -2 9 M 2 9 L 9 9 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 6 -11 M 8 -12 L 6 -11 M -7 8 L -9 9 M -7 7 L -8 9 M -5 7 L -4 9 M -5 8 L -3 9 M 5 7 L 3 9 M 5 7 L 8 9","-9 9 M -4 -12 L -4 9 M -3 -11 L -3 8 M -2 -12 L -2 9 M -7 -12 L 1 -12 M -7 9 L 8 9 L 8 3 M -6 -12 L -4 -11 M -5 -12 L -4 -10 M -1 -12 L -2 -10 M 0 -12 L -2 -11 M -4 8 L -6 9 M -4 7 L -5 9 M -2 7 L -1 9 M -2 8 L 0 9 M 3 9 L 8 8 M 5 9 L 8 7 M 6 9 L 8 6 M 7 9 L 8 3","-13 13 M -8 -12 L -8 8 M -8 -12 L -1 9 M -7 -12 L -1 6 M -6 -12 L 0 6 M 6 -12 L -1 9 M 6 -12 L 6 9 M 7 -11 L 7 8 M 8 -12 L 8 9 M -11 -12 L -6 -12 M 6 -12 L 11 -12 M -11 9 L -5 9 M 3 9 L 11 9 M -10 -12 L -8 -11 M 9 -12 L 8 -10 M 10 -12 L 8 -11 M -8 8 L -10 9 M -8 8 L -6 9 M 6 8 L 4 9 M 6 7 L 5 9 M 8 7 L 9 9 M 8 8 L 10 9","-12 12 M -7 -12 L -7 8 M -7 -12 L 7 9 M -6 -12 L 6 6 M -5 -12 L 7 6 M 7 -11 L 7 9 M -10 -12 L -5 -12 M 4 -12 L 10 -12 M -10 9 L -4 9 M -9 -12 L -7 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11 M -7 8 L -9 9 M -7 8 L -5 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M 5 6 L 6 4 L 7 1 L 7 -4 L 6 -7 L 5 -9 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 1 9 L 3 8 L 5 5 L 6 1 L 6 -4 L 5 -8 L 3 -11 L 1 -12","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -5 L 7 -3 L 6 -2 L 3 -1 L -4 -1 M 6 -10 L 7 -8 L 7 -5 L 6 -3 M 3 -12 L 5 -11 L 6 -9 L 6 -4 L 5 -2 L 3 -1 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-11 11 M -1 -12 L -4 -11 L -6 -9 L -7 -7 L -8 -3 L -8 0 L -7 4 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 4 L 8 0 L 8 -3 L 7 -7 L 6 -9 L 4 -11 L 1 -12 L -1 -12 M -5 -9 L -6 -7 L -7 -4 L -7 1 L -6 4 L -5 6 M 5 6 L 6 4 L 7 1 L 7 -4 L 6 -7 L 5 -9 M -1 -12 L -3 -11 L -5 -8 L -6 -4 L -6 1 L -5 5 L -3 8 L -1 9 M 1 9 L 3 8 L 5 5 L 6 1 L 6 -4 L 5 -8 L 3 -11 L 1 -12 M -4 6 L -3 4 L -1 3 L 0 3 L 2 4 L 3 6 L 4 12 L 5 14 L 7 14 L 8 12 L 8 10 M 4 10 L 5 12 L 6 13 L 7 13 M 3 6 L 5 11 L 6 12 L 7 12 L 8 11","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -4 -12 L -4 9 M -9 -12 L 3 -12 L 6 -11 L 7 -10 L 8 -8 L 8 -6 L 7 -4 L 6 -3 L 3 -2 L -4 -2 M 6 -10 L 7 -8 L 7 -6 L 6 -4 M 3 -12 L 5 -11 L 6 -9 L 6 -5 L 5 -3 L 3 -2 M 0 -2 L 2 -1 L 3 1 L 5 7 L 6 9 L 8 9 L 9 7 L 9 5 M 5 5 L 6 7 L 7 8 L 8 8 M 2 -1 L 3 0 L 6 6 L 7 7 L 8 7 L 9 6 M -9 9 L -1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -3 -12 L -4 -10 M -2 -12 L -4 -11 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9","-10 10 M 6 -9 L 7 -12 L 7 -6 L 6 -9 L 4 -11 L 1 -12 L -2 -12 L -5 -11 L -7 -9 L -7 -6 L -6 -4 L -3 -2 L 3 0 L 5 1 L 6 3 L 6 6 L 5 8 M -6 -6 L -5 -4 L -3 -3 L 3 -1 L 5 0 L 6 2 M -5 -11 L -6 -9 L -6 -7 L -5 -5 L -3 -4 L 3 -2 L 6 0 L 7 2 L 7 5 L 6 7 L 5 8 L 2 9 L -1 9 L -4 8 L -6 6 L -7 3 L -7 9 L -6 6","-10 10 M -8 -12 L -8 -6 M -1 -12 L -1 9 M 0 -11 L 0 8 M 1 -12 L 1 9 M 8 -12 L 8 -6 M -8 -12 L 8 -12 M -4 9 L 4 9 M -7 -12 L -8 -6 M -6 -12 L -8 -9 M -5 -12 L -8 -10 M -3 -12 L -8 -11 M 3 -12 L 8 -11 M 5 -12 L 8 -10 M 6 -12 L 8 -9 M 7 -12 L 8 -6 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-12 12 M -7 -12 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 -11 M -6 -11 L -6 4 L -5 6 M -5 -12 L -5 4 L -4 7 L -3 8 L -1 9 M -10 -12 L -2 -12 M 4 -12 L 10 -12 M -9 -12 L -7 -11 M -8 -12 L -7 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11","-10 10 M -7 -12 L 0 9 M -6 -12 L 0 6 L 0 9 M -5 -12 L 1 6 M 7 -11 L 0 9 M -9 -12 L -2 -12 M 3 -12 L 9 -12 M -8 -12 L -6 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 5 -12 L 7 -11 M 8 -12 L 7 -11","-12 12 M -8 -12 L -4 9 M -7 -12 L -4 4 L -4 9 M -6 -12 L -3 4 M 0 -12 L -3 4 L -4 9 M 0 -12 L 4 9 M 1 -12 L 4 4 L 4 9 M 2 -12 L 5 4 M 8 -11 L 5 4 L 4 9 M -11 -12 L -3 -12 M 0 -12 L 2 -12 M 5 -12 L 11 -12 M -10 -12 L -7 -11 M -9 -12 L -7 -10 M -5 -12 L -6 -10 M -4 -12 L -6 -11 M 6 -12 L 8 -11 M 10 -12 L 8 -11","-10 10 M -7 -12 L 5 9 M -6 -12 L 6 9 M -5 -12 L 7 9 M 6 -11 L -6 8 M -9 -12 L -2 -12 M 3 -12 L 9 -12 M -9 9 L -3 9 M 2 9 L 9 9 M -8 -12 L -5 -10 M -4 -12 L -5 -10 M -3 -12 L -5 -11 M 4 -12 L 6 -11 M 8 -12 L 6 -11 M -6 8 L -8 9 M -6 8 L -4 9 M 5 8 L 3 9 M 5 7 L 4 9 M 5 7 L 8 9","-11 11 M -8 -12 L -1 -1 L -1 9 M -7 -12 L 0 -1 L 0 8 M -6 -12 L 1 -1 L 1 9 M 7 -11 L 1 -1 M -10 -12 L -3 -12 M 4 -12 L 10 -12 M -4 9 L 4 9 M -9 -12 L -7 -11 M -4 -12 L -6 -11 M 5 -12 L 7 -11 M 9 -12 L 7 -11 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-10 10 M 7 -12 L -7 -12 L -7 -6 M 5 -12 L -7 9 M 6 -12 L -6 9 M 7 -12 L -5 9 M -7 9 L 7 9 L 7 3 M -6 -12 L -7 -6 M -5 -12 L -7 -9 M -4 -12 L -7 -10 M -2 -12 L -7 -11 M 2 9 L 7 8 M 4 9 L 7 7 M 5 9 L 7 6 M 6 9 L 7 3","-7 7 M -3 -16 L -3 16 M -2 -16 L -2 16 M -3 -16 L 4 -16 M -3 16 L 4 16","-7 7 M -7 -12 L 7 12","-7 7 M 2 -16 L 2 16 M 3 -16 L 3 16 M -4 -16 L 3 -16 M -4 16 L 3 16","-11 11 M -8 2 L 0 -3 L 8 2 M -8 2 L 0 -2 L 8 2","-10 10 M -10 16 L 10 16","-6 6 M -2 -12 L 3 -6 M -2 -12 L -3 -11 L 3 -6","-9 11 M -4 -2 L -4 -3 L -3 -3 L -3 -1 L -5 -1 L -5 -3 L -4 -4 L -2 -5 L 2 -5 L 4 -4 L 5 -3 L 6 -1 L 6 6 L 7 8 L 8 9 M 4 -3 L 5 -1 L 5 6 L 6 8 M 2 -5 L 3 -4 L 4 -2 L 4 6 L 5 8 L 8 9 L 9 9 M 4 0 L 3 1 L -2 2 L -5 3 L -6 5 L -6 6 L -5 8 L -2 9 L 1 9 L 3 8 L 4 6 M -4 3 L -5 5 L -5 6 L -4 8 M 3 1 L -1 2 L -3 3 L -4 5 L -4 6 L -3 8 L -2 9","-11 10 M -6 -12 L -6 9 L -5 8 L -3 8 M -5 -11 L -5 7 M -9 -12 L -4 -12 L -4 8 M -4 -2 L -3 -4 L -1 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -1 9 L -3 8 L -4 6 M 5 -2 L 6 0 L 6 4 L 5 6 M 1 -5 L 3 -4 L 4 -3 L 5 0 L 5 4 L 4 7 L 3 8 L 1 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10","-10 9 M 5 -1 L 5 -2 L 4 -2 L 4 0 L 6 0 L 6 -2 L 4 -4 L 2 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M -5 -2 L -6 0 L -6 4 L -5 6 M -1 -5 L -3 -4 L -4 -3 L -5 0 L -5 4 L -4 7 L -3 8 L -1 9","-10 11 M 4 -12 L 4 9 L 9 9 M 5 -11 L 5 8 M 1 -12 L 6 -12 L 6 9 M 4 -2 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 3 8 L 4 6 M -5 -2 L -6 0 L -6 4 L -5 6 M -1 -5 L -3 -4 L -4 -3 L -5 0 L -5 4 L -4 7 L -3 8 L -1 9 M 2 -12 L 4 -11 M 3 -12 L 4 -10 M 6 7 L 7 9 M 6 8 L 8 9","-10 9 M -5 1 L 6 1 L 6 -1 L 5 -3 L 4 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 M 5 0 L 5 -1 L 4 -3 M -5 -2 L -6 0 L -6 4 L -5 6 M 4 1 L 4 -2 L 3 -4 L 1 -5 M -1 -5 L -3 -4 L -4 -3 L -5 0 L -5 4 L -4 7 L -3 8 L -1 9","-7 7 M 5 -10 L 5 -11 L 4 -11 L 4 -9 L 6 -9 L 6 -11 L 5 -12 L 2 -12 L 0 -11 L -1 -10 L -2 -7 L -2 9 M 0 -10 L -1 -7 L -1 8 M 2 -12 L 1 -11 L 0 -9 L 0 9 M -5 -5 L 4 -5 M -5 9 L 3 9 M -2 8 L -4 9 M -2 7 L -3 9 M 0 7 L 1 9 M 0 8 L 2 9","-9 10 M 6 -4 L 7 -3 L 8 -4 L 7 -5 L 6 -5 L 4 -4 L 3 -3 M -1 -5 L -3 -4 L -4 -3 L -5 -1 L -5 1 L -4 3 L -3 4 L -1 5 L 1 5 L 3 4 L 4 3 L 5 1 L 5 -1 L 4 -3 L 3 -4 L 1 -5 L -1 -5 M -3 -3 L -4 -1 L -4 1 L -3 3 M 3 3 L 4 1 L 4 -1 L 3 -3 M -1 -5 L -2 -4 L -3 -2 L -3 2 L -2 4 L -1 5 M 1 5 L 2 4 L 3 2 L 3 -2 L 2 -4 L 1 -5 M -4 3 L -5 4 L -6 6 L -6 7 L -5 9 L -4 10 L -1 11 L 3 11 L 6 12 L 7 13 M -4 9 L -1 10 L 3 10 L 6 11 M -6 7 L -5 8 L -2 9 L 3 9 L 6 10 L 7 12 L 7 13 L 6 15 L 3 16 L -3 16 L -6 15 L -7 13 L -7 12 L -6 10 L -3 9 M -3 16 L -5 15 L -6 13 L -6 12 L -5 10 L -3 9","-11 12 M -6 -12 L -6 9 M -5 -11 L -5 8 M -9 -12 L -4 -12 L -4 9 M -4 -1 L -3 -3 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -3 L 7 0 L 7 9 M 5 -3 L 6 0 L 6 8 M 3 -5 L 4 -4 L 5 -1 L 5 9 M -9 9 L -1 9 M 2 9 L 10 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9 M 5 8 L 3 9 M 5 7 L 4 9 M 7 7 L 8 9 M 7 8 L 9 9","-6 6 M -1 -12 L -1 -10 L 1 -10 L 1 -12 L -1 -12 M 0 -12 L 0 -10 M -1 -11 L 1 -11 M -1 -5 L -1 9 M 0 -4 L 0 8 M -4 -5 L 1 -5 L 1 9 M -4 9 L 4 9 M -3 -5 L -1 -4 M -2 -5 L -1 -3 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-7 6 M 0 -12 L 0 -10 L 2 -10 L 2 -12 L 0 -12 M 1 -12 L 1 -10 M 0 -11 L 2 -11 M 0 -5 L 0 12 L -1 15 L -2 16 M 1 -4 L 1 11 L 0 14 M -3 -5 L 2 -5 L 2 11 L 1 14 L 0 15 L -2 16 L -5 16 L -6 15 L -6 13 L -4 13 L -4 15 L -5 15 L -5 14 M -2 -5 L 0 -4 M -1 -5 L 0 -3","-11 11 M -6 -12 L -6 9 M -5 -11 L -5 8 M -9 -12 L -4 -12 L -4 9 M 5 -4 L -4 5 M 0 1 L 7 9 M 0 2 L 6 9 M -1 2 L 5 9 M 2 -5 L 9 -5 M -9 9 L -1 9 M 2 9 L 9 9 M -8 -12 L -6 -11 M -7 -12 L -6 -10 M 3 -5 L 5 -4 M 8 -5 L 5 -4 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9 M 5 7 L 3 9 M 4 7 L 8 9","-6 6 M -1 -12 L -1 9 M 0 -11 L 0 8 M -4 -12 L 1 -12 L 1 9 M -4 9 L 4 9 M -3 -12 L -1 -11 M -2 -12 L -1 -10 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9","-17 17 M -12 -5 L -12 9 M -11 -4 L -11 8 M -15 -5 L -10 -5 L -10 9 M -10 -1 L -9 -3 L -8 -4 L -6 -5 L -3 -5 L -1 -4 L 0 -3 L 1 0 L 1 9 M -1 -3 L 0 0 L 0 8 M -3 -5 L -2 -4 L -1 -1 L -1 9 M 1 -1 L 2 -3 L 3 -4 L 5 -5 L 8 -5 L 10 -4 L 11 -3 L 12 0 L 12 9 M 10 -3 L 11 0 L 11 8 M 8 -5 L 9 -4 L 10 -1 L 10 9 M -15 9 L -7 9 M -4 9 L 4 9 M 7 9 L 15 9 M -14 -5 L -12 -4 M -13 -5 L -12 -3 M -12 8 L -14 9 M -12 7 L -13 9 M -10 7 L -9 9 M -10 8 L -8 9 M -1 8 L -3 9 M -1 7 L -2 9 M 1 7 L 2 9 M 1 8 L 3 9 M 10 8 L 8 9 M 10 7 L 9 9 M 12 7 L 13 9 M 12 8 L 14 9","-11 12 M -6 -5 L -6 9 M -5 -4 L -5 8 M -9 -5 L -4 -5 L -4 9 M -4 -1 L -3 -3 L -2 -4 L 0 -5 L 3 -5 L 5 -4 L 6 -3 L 7 0 L 7 9 M 5 -3 L 6 0 L 6 8 M 3 -5 L 4 -4 L 5 -1 L 5 9 M -9 9 L -1 9 M 2 9 L 10 9 M -8 -5 L -6 -4 M -7 -5 L -6 -3 M -6 8 L -8 9 M -6 7 L -7 9 M -4 7 L -3 9 M -4 8 L -2 9 M 5 8 L 3 9 M 5 7 L 4 9 M 7 7 L 8 9 M 7 8 L 9 9","-10 10 M -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 4 8 L 6 6 L 7 3 L 7 1 L 6 -2 L 4 -4 L 1 -5 L -1 -5 M -5 -2 L -6 0 L -6 4 L -5 6 M 5 6 L 6 4 L 6 0 L 5 -2 M -1 -5 L -3 -4 L -4 -3 L -5 0 L -5 4 L -4 7 L -3 8 L -1 9 M 1 9 L 3 8 L 4 7 L 5 4 L 5 0 L 4 -3 L 3 -4 L 1 -5","-11 10 M -6 -5 L -6 16 M -5 -4 L -5 15 M -9 -5 L -4 -5 L -4 16 M -4 -2 L -3 -4 L -1 -5 L 1 -5 L 4 -4 L 6 -2 L 7 1 L 7 3 L 6 6 L 4 8 L 1 9 L -1 9 L -3 8 L -4 6 M 5 -2 L 6 0 L 6 4 L 5 6 M 1 -5 L 3 -4 L 4 -3 L 5 0 L 5 4 L 4 7 L 3 8 L 1 9 M -9 16 L -1 16 M -8 -5 L -6 -4 M -7 -5 L -6 -3 M -6 15 L -8 16 M -6 14 L -7 16 M -4 14 L -3 16 M -4 15 L -2 16","-10 10 M 4 -4 L 4 16 M 5 -3 L 5 15 M 3 -4 L 5 -4 L 6 -5 L 6 16 M 4 -2 L 3 -4 L 1 -5 L -1 -5 L -4 -4 L -6 -2 L -7 1 L -7 3 L -6 6 L -4 8 L -1 9 L 1 9 L 3 8 L 4 6 M -5 -2 L -6 0 L -6 4 L -5 6 M -1 -5 L -3 -4 L -4 -3 L -5 0 L -5 4 L -4 7 L -3 8 L -1 9 M 1 16 L 9 16 M 4 15 L 2 16 M 4 14 L 3 16 M 6 14 L 7 16 M 6 15 L 8 16","-9 8 M -4 -5 L -4 9 M -3 -4 L -3 8 M -7 -5 L -2 -5 L -2 9 M 5 -3 L 5 -4 L 4 -4 L 4 -2 L 6 -2 L 6 -4 L 5 -5 L 3 -5 L 1 -4 L -1 -2 L -2 1 M -7 9 L 1 9 M -6 -5 L -4 -4 M -5 -5 L -4 -3 M -4 8 L -6 9 M -4 7 L -5 9 M -2 7 L -1 9 M -2 8 L 0 9","-8 9 M 5 -3 L 6 -5 L 6 -1 L 5 -3 L 4 -4 L 2 -5 L -2 -5 L -4 -4 L -5 -3 L -5 -1 L -4 1 L -2 2 L 3 3 L 5 4 L 6 7 M -4 -4 L -5 -1 M -4 0 L -2 1 L 3 2 L 5 3 M 6 4 L 5 8 M -5 -3 L -4 -1 L -2 0 L 3 1 L 5 2 L 6 4 L 6 7 L 5 8 L 3 9 L -1 9 L -3 8 L -4 7 L -5 5 L -5 9 L -4 7","-7 8 M -2 -10 L -2 4 L -1 7 L 0 8 L 2 9 L 4 9 L 6 8 L 7 6 M -1 -10 L -1 5 L 0 7 M -2 -10 L 0 -12 L 0 5 L 1 8 L 2 9 M -5 -5 L 4 -5","-11 12 M -6 -5 L -6 4 L -5 7 L -4 8 L -2 9 L 1 9 L 3 8 L 4 7 L 5 5 M -5 -4 L -5 5 L -4 7 M -9 -5 L -4 -5 L -4 5 L -3 8 L -2 9 M 5 -5 L 5 9 L 10 9 M 6 -4 L 6 8 M 2 -5 L 7 -5 L 7 9 M -8 -5 L -6 -4 M -7 -5 L -6 -3 M 7 7 L 8 9 M 7 8 L 9 9","-9 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M -4 -5 L 1 7 M 6 -4 L 1 7 L 0 9 M -8 -5 L -1 -5 M 2 -5 L 8 -5 M -7 -5 L -4 -3 M -2 -5 L -4 -4 M 4 -5 L 6 -4 M 7 -5 L 6 -4","-12 12 M -8 -5 L -4 9 M -7 -5 L -4 6 M -6 -5 L -3 6 M 0 -5 L -3 6 L -4 9 M 0 -5 L 4 9 M 1 -5 L 4 6 M 0 -5 L 2 -5 L 5 6 M 8 -4 L 5 6 L 4 9 M -11 -5 L -3 -5 M 5 -5 L 11 -5 M -10 -5 L -7 -4 M -4 -5 L -6 -4 M 6 -5 L 8 -4 M 10 -5 L 8 -4","-10 10 M -6 -5 L 4 9 M -5 -5 L 5 9 M -4 -5 L 6 9 M 5 -4 L -5 8 M -8 -5 L -1 -5 M 2 -5 L 8 -5 M -8 9 L -2 9 M 1 9 L 8 9 M -7 -5 L -5 -4 M -2 -5 L -4 -4 M 3 -5 L 5 -4 M 7 -5 L 5 -4 M -5 8 L -7 9 M -5 8 L -3 9 M 4 8 L 2 9 M 5 8 L 7 9","-10 9 M -6 -5 L 0 9 M -5 -5 L 0 7 M -4 -5 L 1 7 M 6 -4 L 1 7 L -2 13 L -4 15 L -6 16 L -8 16 L -9 15 L -9 13 L -7 13 L -7 15 L -8 15 L -8 14 M -8 -5 L -1 -5 M 2 -5 L 8 -5 M -7 -5 L -4 -3 M -2 -5 L -4 -4 M 4 -5 L 6 -4 M 7 -5 L 6 -4","-9 9 M 4 -5 L -6 9 M 5 -5 L -5 9 M 6 -5 L -4 9 M 6 -5 L -6 -5 L -6 -1 M -6 9 L 6 9 L 6 5 M -5 -5 L -6 -1 M -4 -5 L -6 -2 M -3 -5 L -6 -3 M -1 -5 L -6 -4 M 1 9 L 6 8 M 3 9 L 6 7 M 4 9 L 6 6 M 5 9 L 6 5","-7 7 M 2 -16 L 0 -15 L -1 -14 L -2 -12 L -2 -10 L -1 -8 L 0 -7 L 1 -5 L 1 -3 L -1 -1 M 0 -15 L -1 -13 L -1 -11 L 0 -9 L 1 -8 L 2 -6 L 2 -4 L 1 -2 L -3 0 L 1 2 L 2 4 L 2 6 L 1 8 L 0 9 L -1 11 L -1 13 L 0 15 M -1 1 L 1 3 L 1 5 L 0 7 L -1 8 L -2 10 L -2 12 L -1 14 L 0 15 L 2 16","-4 4 M 0 -16 L 0 16","-7 7 M -2 -16 L 0 -15 L 1 -14 L 2 -12 L 2 -10 L 1 -8 L 0 -7 L -1 -5 L -1 -3 L 1 -1 M 0 -15 L 1 -13 L 1 -11 L 0 -9 L -1 -8 L -2 -6 L -2 -4 L -1 -2 L 3 0 L -1 2 L -2 4 L -2 6 L -1 8 L 0 9 L 1 11 L 1 13 L 0 15 M 1 1 L -1 3 L -1 5 L 0 7 L 1 8 L 2 10 L 2 12 L 1 14 L 0 15 L -2 16","-12 12 M -9 3 L -9 1 L -8 -2 L -6 -3 L -4 -3 L -2 -2 L 2 1 L 4 2 L 6 2 L 8 1 L 9 -1 M -9 1 L -8 -1 L -6 -2 L -4 -2 L -2 -1 L 2 2 L 4 3 L 6 3 L 8 2 L 9 -1 L 9 -3","-8 8 M -8 -12 L -8 9 L -7 9 L -7 -12 L -6 -12 L -6 9 L -5 9 L -5 -12 L -4 -12 L -4 9 L -3 9 L -3 -12 L -2 -12 L -2 9 L -1 9 L -1 -12 L 0 -12 L 0 9 L 1 9 L 1 -12 L 2 -12 L 2 9 L 3 9 L 3 -12 L 4 -12 L 4 9 L 5 9 L 5 -12 L 6 -12 L 6 9 L 7 9 L 7 -12 L 8 -12 L 8 9"]
\ No newline at end of file diff --git a/share/extensions/hpgl_decoder.py b/share/extensions/hpgl_decoder.py deleted file mode 100644 index 8f3c18e42..000000000 --- a/share/extensions/hpgl_decoder.py +++ /dev/null @@ -1,102 +0,0 @@ -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard libraries -import math -from StringIO import StringIO -# local library -import inkex - - -class hpglDecoder: - - def __init__(self, hpglString, options): - ''' options: - "resolutionX":float - "resolutionY":float - "showMovements":bool - "docWidth":float - "docHeight":float - ''' - self.hpglString = hpglString - self.options = options - self.scaleX = options.resolutionX / 25.4 # dots/inch to dots/mm - self.scaleY = options.resolutionY / 25.4 # dots/inch to dots/mm - self.warning = '' - self.textMovements = _("Movements") - self.textPenNumber = _("Pen ") - self.layers = {} - self.oldCoordinates = (0.0, self.options.docHeight) - - def getSvg(self): - actualLayer = 0 - # prepare document - self.doc = inkex.etree.parse(StringIO('<svg xmlns:sodipodi="' + inkex.NSS['sodipodi'] + '" xmlns:inkscape="' + inkex.NSS['inkscape'] + '" width="%smm" height="%smm" viewBox="0 0 %s %s"></svg>' % - (self.options.docWidth, self.options.docHeight, self.options.docWidth, self.options.docHeight))) - inkex.etree.SubElement(self.doc.getroot(), inkex.addNS('namedview', 'sodipodi'), {inkex.addNS('document-units', 'inkscape'): 'mm'}) - if self.options.showMovements: - self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): self.textMovements, 'id': self.textMovements}) - # cut stream into commands - hpglData = self.hpglString.split(';') - # if number of commands is under needed minimum, no data was found - if len(hpglData) < 3: - raise Exception('NO_HPGL_DATA') - # decode commands into svg data - for i, command in enumerate(hpglData): - if command.strip() != '': - if command[:2] == 'IN' or command[:2] == 'FS' or command[:2] == 'VS': - # if Initialize, force or speed command ignore it - pass - elif command[:2] == 'SP': - # if Select Pen command - actualLayer = int(command[2:]) - elif command[:2] == 'PU': - # if Pen Up command - self.parametersToPath(command[2:], 0, True) - elif command[:2] == 'PD': - # if Pen Down command - self.parametersToPath(command[2:], actualLayer + 1, False) - else: - self.warning = 'UNKNOWN_COMMANDS' - return (self.doc, self.warning) - - def parametersToPath(self, parameters, layerNum, isPU): - # split params and sanity check them - parameters = parameters.strip().split(',') - if len(parameters) > 0 and len(parameters) % 2 == 0: - for i, param in enumerate(parameters): - # convert params to document units - if i % 2 == 0: - parameters[i] = str(float(param) / self.scaleX) - else: - parameters[i] = str(self.options.docHeight - (float(param) / self.scaleY)) - # create path and add it to the corresponding layer - if not isPU or (self.options.showMovements and isPU): - # create layer if it does not exist - try: - self.layers[layerNum] - except KeyError: - self.layers[layerNum] = inkex.etree.SubElement(self.doc.getroot(), 'g', - {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): self.textPenNumber + str(layerNum - 1), 'id': self.textPenNumber + str(layerNum - 1)}) - path = 'M %f,%f L %s' % (self.oldCoordinates[0], self.oldCoordinates[1], ','.join(parameters)) - inkex.etree.SubElement(self.layers[layerNum], 'path', {'d': path, 'style': 'stroke:#' + ('ff0000' if isPU else '000000') + '; stroke-width:0.2; fill:none;'}) - self.oldCoordinates = (float(parameters[-2]), float(parameters[-1])) - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hpgl_encoder.py b/share/extensions/hpgl_encoder.py deleted file mode 100644 index d9a15ef36..000000000 --- a/share/extensions/hpgl_encoder.py +++ /dev/null @@ -1,407 +0,0 @@ -# coding=utf-8 -''' -Copyright (C) 2008 Aaron Spike, aaron@ekips.org -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard libraries -import math -import re -import string -from distutils.spawn import find_executable -from subprocess import Popen, PIPE -from shutil import copy2 -# local libraries -import bezmisc -import cspsubdiv -import cubicsuperpath -import inkex -import simplestyle -import simpletransform - - -class hpglEncoder: - PI = math.pi - TWO_PI = PI * 2 - - def __init__(self, effect): - ''' options: - "resolutionX":float - "resolutionY":float - "pen":int - "force:int - "speed:int - "orientation":string // "0", "90", "-90", "180" - "mirrorX":bool - "mirrorY":bool - "center":bool - "flat":float - "overcut":float - "toolOffset":float - "precut":bool - "autoAlign":bool - "debug":bool - "convertObjects":bool - ''' - self.options = effect.options - if self.options.convertObjects: - self.doc = self.convertObjectsToPaths(effect.args[-1], effect.document) - else: - self.doc = effect.document.getroot() - self.docWidth = effect.unittouu(self.doc.get('width')) - self.docHeight = effect.unittouu(self.doc.get('height')) - self.hpgl = '' - self.divergenceX = 'False' - self.divergenceY = 'False' - self.sizeX = 'False' - self.sizeY = 'False' - self.dryRun = True - self.lastPoint = [0, 0, 0] - self.lastPen = -1 - self.offsetX = 0 - self.offsetY = 0 - self.scaleX = self.options.resolutionX / effect.unittouu("1.0in") # dots per inch to dots per user unit - self.scaleY = self.options.resolutionY / effect.unittouu("1.0in") # dots per inch to dots per user unit - scaleXY = (self.scaleX + self.scaleY) / 2 - self.overcut = effect.unittouu(str(self.options.overcut) + "mm") * scaleXY # mm to dots (plotter coordinate system) - self.toolOffset = effect.unittouu(str(self.options.toolOffset) + "mm") * scaleXY # mm to dots - self.flat = self.options.flat / (1016 / ((self.options.resolutionX + self.options.resolutionY) / 2)) # scale flatness to resolution - if self.toolOffset > 0.0: - self.toolOffsetFlat = self.flat / self.toolOffset * 4.5 # scale flatness to offset - else: - self.toolOffsetFlat = 0.0 - self.mirrorX = 1.0 - if self.options.mirrorX: - self.mirrorX = -1.0 - self.mirrorY = -1.0 - if self.options.mirrorY: - self.mirrorY = 1.0 - if self.options.debug: - self.debugValues = {} - self.debugValues['docWidth'] = self.docWidth - self.debugValues['docHeight'] = self.docHeight - # process viewBox attribute to correct page scaling - self.viewBoxTransformX = 1 - self.viewBoxTransformY = 1 - if self.options.debug: - self.debugValues['viewBoxWidth'] = "-" - self.debugValues['viewBoxHeight'] = "-" - viewBox = self.doc.get('viewBox') - if viewBox: - viewBox2 = string.split(viewBox, ',') - if len(viewBox2) < 4: - viewBox2 = string.split(viewBox, ' ') - if self.options.debug: - self.debugValues['viewBoxWidth'] = viewBox2[2] - self.debugValues['viewBoxHeight'] = viewBox2[3] - self.viewBoxTransformX = self.docWidth / effect.unittouu(effect.addDocumentUnit(viewBox2[2])) - self.viewBoxTransformY = self.docHeight / effect.unittouu(effect.addDocumentUnit(viewBox2[3])) - - def convertObjectsToPaths(self, file, document): - tempfile = inkex.os.path.splitext(file)[0] + "-prepare.svg" - # tempfile is needed here only because we want to force the extension to be .svg - # so that we can open and close it silently - copy2(file, tempfile) - - command = 'inkscape --verb=EditSelectAllInAllLayers --verb=EditUnlinkClone --verb=ObjectToPath --verb=FileSave --verb=FileQuit ' + tempfile - - if find_executable('xvfb-run'): - command = 'xvfb-run ' + command - - # Unfortunately this briefly pops up the GUI and cannot be done with -z, see https://bugs.launchpad.net/inkscape/+bug/843260 - p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) - (out, err) = p.communicate() - - if p.returncode != 0: - inkex.errormsg(_("Failed to convert objects to paths. Continued without converting.")) - inkex.errormsg(out) - inkex.errormsg(err) - return document.getroot() - else: - return inkex.etree.parse(tempfile).getroot() - - def getHpgl(self): - # dryRun to find edges - groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]] - groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) - self.vData = [['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0]] - self.processGroups(self.doc, groupmat) - if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False': - raise Exception('NO_PATHS') - # live run - self.dryRun = False - if self.options.debug: - self.debugValues['drawingWidth'] = self.sizeX - self.divergenceX - self.debugValues['drawingHeight'] = self.sizeY - self.divergenceY - self.debugValues['drawingWidthUU'] = self.debugValues['drawingWidth'] / self.scaleX - self.debugValues['drawingHeightUU'] = self.debugValues['drawingHeight'] / self.scaleY - # move drawing according to various modifiers - if self.options.autoAlign: - if self.options.center: - self.offsetX -= (self.sizeX - self.divergenceX) / 2 - self.offsetY -= (self.sizeY - self.divergenceY) / 2 - else: - self.divergenceX = 0.0 - self.divergenceY = 0.0 - if self.options.center: - if self.options.orientation == '0': - self.offsetX -= (self.docWidth * self.scaleX) / 2 - self.offsetY += (self.docHeight * self.scaleY) / 2 - if self.options.orientation == '90': - self.offsetY += (self.docWidth * self.scaleX) / 2 - self.offsetX += (self.docHeight * self.scaleY) / 2 - if self.options.orientation == '180': - self.offsetX += (self.docWidth * self.scaleX) / 2 - self.offsetY -= (self.docHeight * self.scaleY) / 2 - if self.options.orientation == '270': - self.offsetY -= (self.docWidth * self.scaleX) / 2 - self.offsetX -= (self.docHeight * self.scaleY) / 2 - else: - if self.options.orientation == '0': - self.offsetY += self.docHeight * self.scaleY - if self.options.orientation == '90': - self.offsetY += self.docWidth * self.scaleX - self.offsetX += self.docHeight * self.scaleY - if self.options.orientation == '180': - self.offsetX += self.docWidth * self.scaleX - if not self.options.center and self.toolOffset > 0.0: - self.offsetX += self.toolOffset - self.offsetY += self.toolOffset - # initialize transformation matrix and cache - groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, -self.divergenceX + self.offsetX], - [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, -self.divergenceY + self.offsetY]] - groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')')) - self.vData = [['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0]] - # add move to zero point and precut - if self.toolOffset > 0.0 and self.options.precut: - if self.options.center: - # position precut outside of drawing plus one time the tooloffset - if self.offsetX >= 0.0: - precutX = self.offsetX + self.toolOffset - else: - precutX = self.offsetX - self.toolOffset - if self.offsetY >= 0.0: - precutY = self.offsetY + self.toolOffset - else: - precutY = self.offsetY - self.toolOffset - self.processOffset('PU', precutX, precutY, self.options.pen) - self.processOffset('PD', precutX, precutY + self.toolOffset * 8, self.options.pen) - else: - self.processOffset('PU', 0, 0, self.options.pen) - self.processOffset('PD', 0, self.toolOffset * 8, self.options.pen) - # start conversion - self.processGroups(self.doc, groupmat) - # shift an empty node in in order to process last node in cache - if self.toolOffset > 0.0 and not self.dryRun: - self.processOffset('PU', 0, 0, 0) - if self.options.debug: - return self.hpgl, self - else: - return self.hpgl, "" - - def processGroups(self, doc, groupmat): - # flatten layers and groups to avoid recursion - paths = [] - for node in doc: - if (node.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(node)) or node.tag == inkex.addNS('path', 'svg'): - paths.append([node.tag, node, self.mergeTransform(node, groupmat), self.getPenNumber(node)]) - doc = '' - hasGroups = True - while hasGroups: - hasGroups = False - for i, elm in enumerate(paths): - if paths[i][0] == inkex.addNS('g', 'svg') and self.isGroupVisible(paths[i][1]): - hasGroups = True - for path in paths[i][1]: - if (path.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(path)) or path.tag == inkex.addNS('path', 'svg'): - paths.insert(i + 1, [path.tag, path, self.mergeTransform(path, paths[i][2]), paths[i][3]]) - paths[i][0] = '' - for node in paths: - if node[0] == inkex.addNS('path', 'svg'): - self.processPath(node[1], node[2], node[3]) - - def getPenNumber(self, doc): - penNum = str(doc.get('{' + inkex.NSS['inkscape'] + '}label')).lower().strip(' \t\n\r') - if re.search(r'( |\A)pen *\d+( |\Z)', penNum): - penNum = re.sub(r'(.* |\A)pen *(\d+)( .*|\Z)', r'\2', penNum, 1) - return int(penNum) - else: - return self.options.pen - - def mergeTransform(self, doc, matrix): - # get and merge two matrixes into one - trans = doc.get('transform') - if trans: - return simpletransform.composeTransform(matrix, simpletransform.parseTransform(trans)) - else: - return matrix - - def isGroupVisible(self, group): - style = group.get('style') - if style: - style = simplestyle.parseStyle(style) - if 'display' in style and style['display'] == 'none': - return False - return True - - def processPath(self, node, mat, pen): - # process path - path = node.get('d') - if path: - # parse and transform path - path = cubicsuperpath.parsePath(path) - simpletransform.applyTransformToPath(mat, path) - cspsubdiv.cspsubdiv(path, self.flat) - # path to HPGL commands - oldPosX = 0.0 - oldPosY = 0.0 - for singlePath in path: - cmd = 'PU' - for singlePathPoint in singlePath: - posX, posY = singlePathPoint[1] - # check if point is repeating, if so, ignore - if int(round(posX)) != int(round(oldPosX)) or int(round(posY)) != int(round(oldPosY)): - self.processOffset(cmd, posX, posY, pen) - cmd = 'PD' - oldPosX = posX - oldPosY = posY - # perform overcut - if self.overcut > 0.0 and not self.dryRun: - # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed - if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])): - overcutLength = 0 - for singlePathPoint in singlePath: - posX, posY = singlePathPoint[1] - # check if point is repeating, if so, ignore - if int(round(posX)) != int(round(oldPosX)) or int(round(posY)) != int(round(oldPosY)): - overcutLength += self.getLength(oldPosX, oldPosY, posX, posY) - if overcutLength >= self.overcut: - newLength = self.changeLength(oldPosX, oldPosY, posX, posY, - (overcutLength - self.overcut)) - self.processOffset(cmd, newLength[0], newLength[1], pen) - break - else: - self.processOffset(cmd, posX, posY, pen) - oldPosX = posX - oldPosY = posY - - def getLength(self, x1, y1, x2, y2, absolute=True): - # calc absolute or relative length between two points - length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0) - if absolute: - length = math.fabs(length) - return length - - def changeLength(self, x1, y1, x2, y2, offset): - # change length of line - if offset < 0: - offset = max( - self.getLength(x1, y1, x2, y2), offset) - x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset - y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset - return [x, y] - - def processOffset(self, cmd, posX, posY, pen): - # calculate offset correction (or don't) - if self.toolOffset == 0.0 or self.dryRun: - self.storePoint(cmd, posX, posY, pen) - else: - # insert data into cache - self.vData.pop(0) - self.vData.insert(3, [cmd, posX, posY, pen]) - # decide if enough data is available - if self.vData[2][1] != 'False': - if self.vData[1][1] == 'False': - self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2], self.vData[2][3]) - else: - # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper) - if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset - pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.toolOffset) - self.storePoint('PD', pointThree[0], pointThree[1], self.vData[2][3]) - elif self.vData[0][1] != 'False': - # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift - # the 3rd entry by the current tool offset position according to the 2nd command - pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.toolOffset) - pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0]) - pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1]) - self.storePoint('PU', pointThree[0], pointThree[1], self.vData[2][3]) - else: - # Else just write the 3rd entry - pointThree = [self.vData[2][1], self.vData[2][2]] - self.storePoint('PU', pointThree[0], pointThree[1], self.vData[2][3]) - if self.vData[3][0] == 'PD': - # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry - if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.toolOffset: - pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.toolOffset) - else: - pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2], - (self.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]))) - # get angle start and angle vector - angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1]) - angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart - # switch direction when arc is bigger than 180° - if angleVector > self.PI: - angleVector -= self.TWO_PI - elif angleVector < - self.PI: - angleVector += self.TWO_PI - # draw arc - if angleVector >= 0: - angle = angleStart + self.toolOffsetFlat - while angle < angleStart + angleVector: - self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset, self.vData[2][3]) - angle += self.toolOffsetFlat - else: - angle = angleStart - self.toolOffsetFlat - while angle > angleStart + angleVector: - self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset, self.vData[2][3]) - angle -= self.toolOffsetFlat - self.storePoint('PD', pointFour[0], pointFour[1], self.vData[3][3]) - - def storePoint(self, command, x, y, pen): - x = int(round(x)) - y = int(round(y)) - # skip when no change in movement - if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y: - return - if self.dryRun: - # find edges - if self.divergenceX == 'False' or x < self.divergenceX: - self.divergenceX = x - if self.divergenceY == 'False' or y < self.divergenceY: - self.divergenceY = y - if self.sizeX == 'False' or x > self.sizeX: - self.sizeX = x - if self.sizeY == 'False' or y > self.sizeY: - self.sizeY = y - else: - # store point - if not self.options.center: - # only positive values are allowed (usually) - if x < 0: - x = 0 - if y < 0: - y = 0 - # select correct pen - if self.lastPen != pen: - self.hpgl += ';SP%d' % pen - # do not repeat command - if command == 'PD' and self.lastPoint[0] == 'PD' and self.lastPen == pen: - self.hpgl += ',%d,%d' % (x, y) - else: - self.hpgl += ';%s%d,%d' % (command, x, y) - self.lastPen = pen - self.lastPoint = [command, x, y] - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hpgl_input.inx b/share/extensions/hpgl_input.inx deleted file mode 100644 index 4cbbba812..000000000 --- a/share/extensions/hpgl_input.inx +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>HPGL Input</_name> - <id>org.inkscape.input.hpgl</id> - <dependency type="executable" location="extensions">hpgl_input.py</dependency> - <dependency type="executable" location="extensions">hpgl_decoder.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="introduction" type="description">Please note that you can only open HPGL files written by Inkscape, to open other HPGL files please change their file extension to .plt, make sure you have UniConverter installed and open them again.</_param> - <param name="space" type="description"> </param> - <param name="resolutionX" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution X (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the X axis (Default: 1016.0)">1016.0</param> - <param name="resolutionY" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution Y (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the Y axis (Default: 1016.0)">1016.0</param> - <param name="showMovements" type="boolean" _gui-text="Show movements between paths" _gui-description="Check this to show movements between paths (Default: Unchecked)">false</param> - <input> - <extension>.hpgl</extension> - <mimetype>image/hpgl</mimetype> - <_filetypename>HP Graphics Language file (*.hpgl)</_filetypename> - <_filetypetooltip>Import an HP Graphics Language file</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">hpgl_input.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/hpgl_input.py b/share/extensions/hpgl_input.py deleted file mode 100755 index 13d6d00ec..000000000 --- a/share/extensions/hpgl_input.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard libraries -import sys -from StringIO import StringIO -# local libraries -import hpgl_decoder -import inkex -import sys - -inkex.localize() - -# parse options -parser = inkex.optparse.OptionParser(usage='usage: %prog [options] HPGLfile', option_class=inkex.InkOption) -parser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') -parser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') -parser.add_option('--showMovements', action='store', type='inkbool', dest='showMovements', default='FALSE', help='Show Movements between paths') -(options, args) = parser.parse_args(inkex.sys.argv[1:]) - -# needed to initialize the document -options.docWidth = 210.0 # 210mm (DIN A4) -options.docHeight = 297.0 # 297mm (DIN A4) - -# read file -fobj = open(args[0], 'r') -hpglString = [] -for line in fobj: - hpglString.append(line.strip()) -fobj.close() -# combine all lines -hpglString = ';'.join(hpglString) - -# interpret HPGL data -myHpglDecoder = hpgl_decoder.hpglDecoder(hpglString, options) -try: - doc, warnings = myHpglDecoder.getSvg() -except Exception as inst: - if inst.args[0] == 'NO_HPGL_DATA': - # issue error if no hpgl data found - inkex.errormsg(_("No HPGL data found.")) - exit(1) - else: - type, value, traceback = sys.exc_info() - raise ValueError, ("", type, value), traceback - -# issue warning if unknown commands where found -if 'UNKNOWN_COMMANDS' in warnings: - inkex.errormsg(_("The HPGL data contained unknown (unsupported) commands, there is a possibility that the drawing is missing some content.")) - -# deliver document to inkscape -doc.write(inkex.sys.stdout) - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/hpgl_output.inx b/share/extensions/hpgl_output.inx deleted file mode 100644 index 609fc03d4..000000000 --- a/share/extensions/hpgl_output.inx +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>HPGL Output</_name> - <id>org.ekips.output.hpgl</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">hpgl_output.py</dependency> - <dependency type="executable" location="extensions">hpgl_encoder.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="introduction" type="description">Please make sure that all objects you want to save are converted to paths. Please use the plotter extension (Extensions menu) to plot directly over a serial connection.</_param> - <param name="tab" type="notebook"> - <page name="plotter" _gui-text="Plotter Settings "> - <param name="resolutionX" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution X (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the X axis (Default: 1016.0)">1016.0</param> - <param name="resolutionY" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution Y (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the Y axis (Default: 1016.0)">1016.0</param> - <param name="pen" type="int" min="0" max="99" _gui-text="Pen number:" _gui-description="The number of the pen (tool) to use (Standard: '1')">1</param> - <param name="force" type="int" min="0" max="1000" _gui-text="Pen force (g):" _gui-description="The amount of force pushing down the pen in grams, set to 0 to omit command; most plotters ignore this command (Default: 0)">0</param> - <param name="speed" type="int" min="0" max="10000" _gui-text="Pen speed (cm/s or mm/s):" _gui-description="The speed the pen will move with in centimeters or millimeters per second (depending on your plotter model), set to 0 to omit command; most plotters ignore this command (Default: 0)">0</param> - <param name="orientation" type="enum" _gui-text="Rotation (°, Clockwise):" _gui-description="Rotation of the drawing (Default: 0°)"> - <item value="0">0</item> - <item value="90">90</item> - <item value="180">180</item> - <item value="270">270</item> - </param> - <param name="mirrorX" type="boolean" _gui-text="Mirror X axis" _gui-description="Check this to mirror the X axis (Default: Unchecked)">false</param> - <param name="mirrorY" type="boolean" _gui-text="Mirror Y axis" _gui-description="Check this to mirror the Y axis (Default: Unchecked)">false</param> - <param name="center" type="boolean" _gui-text="Center zero point" _gui-description="Check this if your plotter uses a centered zero point (Default: Unchecked)">false</param> - <param name="space" type="description"> </param> - <_param name="multiplePensHelp" type="description">If you want to use multiple pens on your pen plotter create one layer for each pen, name the layers "Pen 1", "Pen 2", etc., and put your drawings in the corresponding layers. This overrules the pen number option above.</_param> - </page> - <page name="overcutToolOffset" _gui-text="Plot Features "> - <param name="overcut" type="float" min="0.0" max="100.0" precision="2" _gui-text="Overcut (mm):" _gui-description="The distance in mm that will be cut over the starting point of the path to prevent open paths, set to 0.0 to omit command (Default: 1.00)">1.00</param> - <param name="toolOffset" type="float" min="0.0" max="20.0" precision="2" _gui-text="Tool (Knife) offset correction (mm):" _gui-description="The offset from the tool tip to the tool axis in mm, set to 0.0 to omit command (Default: 0.25)">0.25</param> - <param name="precut" type="boolean" _gui-text="Precut" _gui-description="Check this to cut a small line before the real drawing starts to correctly align the tool orientation. (Default: Checked)">true</param> - <param name="flat" type="float" min="0.1" max="10.0" precision="1" _gui-text="Curve flatness:" _gui-description="Curves are divided into lines, this number controls how fine the curves will be reproduced, the smaller the finer (Default: '1.2')">1.2</param> - <param name="autoAlign" type="boolean" _gui-text="Auto align" _gui-description="Check this to auto align the drawing to the zero point (Plus the tool offset if used). If unchecked you have to make sure that all parts of your drawing are within the document border! (Default: Checked)">true</param> - <param name="convertObjects" type="boolean" _gui-text="Convert objects to paths" _gui-description="Check this to automatically (nondestructively) convert all objects to paths before plotting (Default: Checked)">true</param> - </page> - </param> - <_param name="settingsHelp" type="description">All these settings depend on the plotter you use, for more information please consult the manual or homepage for your plotter.</_param> - <output> - <extension>.hpgl</extension> - <mimetype>image/hpgl</mimetype> - <_filetypename>HP Graphics Language file (*.hpgl)</_filetypename> - <_filetypetooltip>Export an HP Graphics Language file</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">hpgl_output.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/hpgl_output.py b/share/extensions/hpgl_output.py deleted file mode 100755 index fc212b449..000000000 --- a/share/extensions/hpgl_output.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard library -import sys -# local libraries -import hpgl_encoder -import inkex - - -class HpglOutput(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') - self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') - self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') - self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') - self.OptionParser.add_option('--force', action='store', type='int', dest='force', default=24, help='Pen force (g)') - self.OptionParser.add_option('--speed', action='store', type='int', dest='speed', default=20, help='Pen speed (cm/s)') - self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='Rotation (Clockwise)') - self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X axis') - self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y axis') - self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') - self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') - self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool (Knife) offset correction (mm)') - self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') - self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') - self.OptionParser.add_option('--autoAlign', action='store', type='inkbool', dest='autoAlign', default='TRUE', help='Auto align') - self.OptionParser.add_option('--convertObjects',action='store', type='inkbool', dest='convertObjects',default='TRUE', help='Convert objects to paths') - - def effect(self): - self.options.debug = False - # get hpgl data - myHpglEncoder = hpgl_encoder.hpglEncoder(self) - try: - self.hpgl, debugObject = myHpglEncoder.getHpgl() - except Exception as inst: - if inst.args[0] == 'NO_PATHS': - # issue error if no paths found - inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths.")) - self.hpgl = '' - return - else: - type, value, traceback = sys.exc_info() - raise ValueError, ("", type, value), traceback - # convert raw HPGL to HPGL - hpglInit = 'IN' - if self.options.force > 0: - hpglInit += ';FS%d' % self.options.force - if self.options.speed > 0: - hpglInit += ';VS%d' % self.options.speed - self.hpgl = hpglInit + self.hpgl + ';PU0,0;SP0;IN; ' - - def output(self): - # print to file - if self.hpgl != '': - print self.hpgl - -if __name__ == '__main__': - # start extension - e = HpglOutput() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/image_attributes.inx b/share/extensions/image_attributes.inx deleted file mode 100644 index d9ae9cefb..000000000 --- a/share/extensions/image_attributes.inx +++ /dev/null @@ -1,82 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - - <_name>Set Image Attributes</_name> - <id>org.inkscape.effect.image_attributes</id> - - <dependency type="executable" location="extensions">image_attributes.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="tab_main" type="notebook"> - - <!-- render images like in 0.48 --> - <page name="tab_basic" _gui-text="Basic"> - <_param name="basic_desc1" type="description">Render all bitmap images like in older Inskcape versions. - -Available options:</_param> - <param name="fix_scaling" type="boolean" _gui-text="Support non-uniform scaling">true</param> - <param name="fix_rendering" type="boolean" _gui-text="Render images blocky">false</param> - </page> - - <!-- image aspect ratio --> - <page name="tab_aspectRatio" _gui-text="Image Aspect Ratio"> - <param name="aspect_ratio" type="enum" _gui-text="preserveAspectRatio attribute:"> - <item value="none">none</item> - <_item value="unset">Unset</_item> - <item value="xMinYMin">xMinYMin</item> - <item value="xMidYMin">xMidYMin</item> - <item value="xMaxYMin">xMaxYMin</item> - <item value="xMinYMid">xMinYMid</item> - <item value="xMidYMid">xMidYMid</item> - <item value="xMaxYMid">xMaxYMid</item> - <item value="xMinYMax">xMinYMax</item> - <item value="xMidYMax">xMidYMax</item> - <item value="xMaxYMax">xMaxYMax</item> - </param> - <param name="aspect_clip" type="enum" _gui-text="meetOrSlice:"> - <item value="unset">-</item> - <item value="meet">meet</item> - <item value="slice">slice</item> - </param> - <param name="aspect_ratio_scope" type="enum" _gui-text="Scope:"> - <_item value="selected_only">Change only selected image(s)</_item> - <_item value="in_selection">Change all images in selection</_item> - <_item value="in_document">Change all images in document</_item> - </param> - </page> - - <!-- image-rendering --> - <page name="tab_image_rendering" _gui-text="Image Rendering Quality"> - <param name="image_rendering" type="enum" _gui-text="Image rendering attribute:"> - <_item value="unset">Unset</_item> - <item value="auto">auto</item> - <item value="optimizeQuality">optimizeQuality</item> - <item value="optimizeSpeed">optimizeSpeed</item> - <item value="inherit">inherit</item> - </param> - <param name="image_rendering_scope" type="enum" _gui-text="Scope:"> - <_item value="selected_only">Change only selected image(s)</_item> - <_item value="in_selection">Change all images in selection</_item> - <_item value="in_document">Change all images in document</_item> - <_item value="on_parent_group">Apply attribute to parent group of selection</_item> - <_item value="on_root_only" >Apply attribute to SVG root</_item> - </param> - </page> - - </param> - - <effect needs-document="true" needs-live-preview="true"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Images"/> - </effects-menu> - </effect> - - <script> - <command reldir="extensions" interpreter="python">image_attributes.py</command> - </script> - - <options silent="false"></options> - -</inkscape-extension> - diff --git a/share/extensions/image_attributes.py b/share/extensions/image_attributes.py deleted file mode 100755 index 98cc5204f..000000000 --- a/share/extensions/image_attributes.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python -''' -image_attributes.py - adjust image attributes which don't have global -GUI options yet - -Tool for Inkscape 0.91 to adjust rendering of drawings with linked -or embedded bitmap images created with older versions of Inkscape -or third-party applications. - -Copyright (C) 2015, ~suv <suv-sf@users.sf.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 -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# local library -import inkex -import simplestyle - - -class SetAttrImage(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - # main options - self.OptionParser.add_option("--fix_scaling", - action="store", type="inkbool", - dest="fix_scaling", default=True, - help="") - self.OptionParser.add_option("--fix_rendering", - action="store", type="inkbool", - dest="fix_rendering", default=False, - help="") - self.OptionParser.add_option("--aspect_ratio", - action="store", type="string", - dest="aspect_ratio", default="none", - help="Value for attribute 'preserveAspectRatio'") - self.OptionParser.add_option("--aspect_clip", - action="store", type="string", - dest="aspect_clip", default="unset", - help="optional 'meetOrSlice' value") - self.OptionParser.add_option("--aspect_ratio_scope", - action="store", type="string", - dest="aspect_ratio_scope", default="selected_only", - help="scope within which to edit 'preserveAspectRatio' attribute") - self.OptionParser.add_option("--image_rendering", - action="store", type="string", - dest="image_rendering", default="unset", - help="Value for attribute 'image-rendering'") - self.OptionParser.add_option("--image_rendering_scope", - action="store", type="string", - dest="image_rendering_scope", default="selected_only", - help="scope within which to edit 'image-rendering' attribute") - # tabs - self.OptionParser.add_option("--tab_main", - action="store", type="string", - dest="tab_main") - - # core method - - def change_attribute(self, node, attribute): - for key, value in attribute.items(): - if key == 'preserveAspectRatio': - # set presentation attribute - if value != "unset": - node.set(key, str(value)) - else: - if node.get(key): - del node.attrib[key] - elif key == 'image-rendering': - node_style = simplestyle.parseStyle(node.get('style')) - if key not in node_style: - # set presentation attribute - if value != "unset": - node.set(key, str(value)) - else: - if node.get(key): - del node.attrib[key] - else: - # set style property - if value != "unset": - node_style[key] = str(value) - else: - del node_style[key] - node.set('style', simplestyle.formatStyle(node_style)) - else: - pass - - def change_all_images(self, node, attribute): - path = 'descendant-or-self::svg:image' - for img in node.xpath(path, namespaces=inkex.NSS): - self.change_attribute(img, attribute) - - # methods called via dispatcher - - def change_selected_only(self, selected, attribute): - if selected: - for node_id, node in selected.iteritems(): - if node.tag == inkex.addNS('image', 'svg'): - self.change_attribute(node, attribute) - - def change_in_selection(self, selected, attribute): - if selected: - for node_id, node in selected.iteritems(): - self.change_all_images(node, attribute) - - def change_in_document(self, selected, attribute): - self.change_all_images(self.document.getroot(), attribute) - - def change_on_parent_group(self, selected, attribute): - if selected: - for node_id, node in selected.iteritems(): - self.change_attribute(node.getparent(), attribute) - - def change_on_root_only(self, selected, attribute): - self.change_attribute(self.document.getroot(), attribute) - - # main - - def effect(self): - attr_val = [] - attr_dict = {} - cmd_scope = None - if self.options.tab_main == '"tab_basic"': - cmd_scope = "in_document" - attr_dict['preserveAspectRatio'] = ("none" if self.options.fix_scaling else "unset") - attr_dict['image-rendering'] = ("optimizeSpeed" if self.options.fix_rendering else "unset") - elif self.options.tab_main == '"tab_aspectRatio"': - attr_val = [self.options.aspect_ratio] - if self.options.aspect_clip != "unset": - attr_val.append(self.options.aspect_clip) - attr_dict['preserveAspectRatio'] = ' '.join(attr_val) - cmd_scope = self.options.aspect_ratio_scope - elif self.options.tab_main == '"tab_image_rendering"': - attr_dict['image-rendering'] = self.options.image_rendering - cmd_scope = self.options.image_rendering_scope - else: # help tab - pass - # dispatcher - if cmd_scope is not None: - try: - change_cmd = getattr(self, 'change_{0}'.format(cmd_scope)) - change_cmd(self.selected, attr_dict) - except AttributeError: - inkex.errormsg('Scope "{0}" not supported'.format(cmd_scope)) - - -if __name__ == '__main__': - e = SetAttrImage() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/ink2canvas.inx b/share/extensions/ink2canvas.inx deleted file mode 100644 index c76c6a946..000000000 --- a/share/extensions/ink2canvas.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Convert to html5 canvas</_name> - <id>org.inkscape.output.html5canvas</id> - <dependency type="executable" location="extensions">ink2canvas.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.html</extension> - <mimetype>text/html</mimetype> - <_filetypename>HTML 5 canvas (*.html)</_filetypename> - <_filetypetooltip>HTML 5 canvas code</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">ink2canvas.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/ink2canvas.py b/share/extensions/ink2canvas.py deleted file mode 100755 index f44c3e48f..000000000 --- a/share/extensions/ink2canvas.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Karlisson Bezerra <contact@hacktoon.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -from ink2canvas.canvas import Canvas -import ink2canvas.svg as svg - -log = inkex.debug #alias to debug method - - -class Ink2Canvas(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.canvas = None - - def output(self): - import sys - sys.stdout.write(self.canvas.output()) - - def get_tag_name(self, node): - # remove namespace part from "{http://www.w3.org/2000/svg}elem" - return node.tag.split("}")[1] - - def get_gradient_defs(self, elem): - url_id = elem.get_gradient_href() - # get the gradient element - gradient = self.xpathSingle("//*[@id='%s']" % url_id) - # get the color stops - url_stops = gradient.get(inkex.addNS("href", "xlink")) - gstops = self.xpathSingle("//svg:linearGradient[@id='%s']" % url_stops[1:]) - colors = [] - for stop in gstops: - colors.append(stop.get("style")) - if gradient.get("r"): - return svg.RadialGradientDef(gradient, colors) - else: - return svg.LinearGradientDef(gradient, colors) - - def get_clip_defs(self, elem): - if elem.has_clip(): - pass - return - - def walk_tree(self, root): - for node in root: - if node.tag is inkex.etree.Comment: - continue - tag = self.get_tag_name(node) - class_name = tag.capitalize() - if not hasattr(svg, class_name): - continue - gradient = None - clip = None - # creates a instance of 'elem' - # similar to 'elem = Rect(tag, node, ctx)' - elem = getattr(svg, class_name)(tag, node, self.canvas) - if elem.has_gradient(): - gradient = self.get_gradient_defs(elem) - elem.start(gradient) - elem.draw() - self.walk_tree(node) - elem.end() - - def effect(self): - """Applies the effect""" - svg_root = self.document.getroot() - width = self.unittouu(svg_root.get("width")) - height = self.unittouu(svg_root.get("height")) - self.canvas = Canvas(self, width, height) - self.walk_tree(svg_root) - - -if __name__ == "__main__": - ink = Ink2Canvas() - ink.affect() diff --git a/share/extensions/ink2canvas/__init__.py b/share/extensions/ink2canvas/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/share/extensions/ink2canvas/__init__.py +++ /dev/null diff --git a/share/extensions/ink2canvas/canvas.py b/share/extensions/ink2canvas/canvas.py deleted file mode 100644 index a88d368d3..000000000 --- a/share/extensions/ink2canvas/canvas.py +++ /dev/null @@ -1,194 +0,0 @@ -''' -Copyright (C) 2011 Karlisson Bezerra <contact@hacktoon.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle - -class Canvas: - """Canvas API helper class""" - - def __init__(self, parent, width, height, context = "ctx"): - self.obj = context - self.code = [] #stores the code - self.style = {} - self.styleCache = {} #stores the previous style applied - self.parent = parent - self.width = width - self.height = height - - def write(self, text): - self.code.append("\t" + text.replace("ctx", self.obj) + "\n") - - def output(self): - from textwrap import dedent - html = """ - <!DOCTYPE html> - <html> - <head> - <title>Inkscape Output</title> - </head> - <body> - <canvas id='canvas' width='%d' height='%d'></canvas> - <script> - var %s = document.getElementById("canvas").getContext("2d"); - %s - </script> - </body> - </html> - """ - return dedent(html) % (self.width, self.height, self.obj, "".join(self.code)) - - def equalStyle(self, style, key): - """Checks if the last style used is the same or there's no style yet""" - if key in self.styleCache: - return True - if key not in style: - return True - return style[key] == self.styleCache[key] - - def beginPath(self): - self.write("ctx.beginPath();") - - def createLinearGradient(self, href, x1, y1, x2, y2): - data = (href, x1, y1, x2, y2) - self.write("var %s = \ - ctx.createLinearGradient(%f,%f,%f,%f);" % data) - - def createRadialGradient(self, href, cx1, cy1, rx, cx2, cy2, ry): - data = (href, cx1, cy1, rx, cx2, cy2, ry) - self.write("var %s = ctx.createRadialGradient\ - (%f,%f,%f,%f,%f,%f);" % data) - - def addColorStop(self, href, pos, color): - self.write("%s.addColorStop(%f, %s);" % (href, pos, color)) - - def getColor(self, rgb, a): - r, g, b = simplestyle.parseColor(rgb) - a = float(a) - if a < 1: - return "'rgba(%d, %d, %d, %.1f)'" % (r, g, b, a) - else: - return "'rgb(%d, %d, %d)'" % (r, g, b) - - def setGradient(self, href): - """ - for stop in gstops: - style = simplestyle.parseStyle(stop.get("style")) - stop_color = style["stop-color"] - opacity = style["stop-opacity"] - color = self.getColor(stop_color, opacity) - pos = float(stop.get("offset")) - self.addColorStop(href, pos, color) - """ - return None #href - - def setOpacity(self, value): - self.write("ctx.globalAlpha = %.1f;" % float(value)) - - def setFill(self, value): - try: - alpha = self.style["fill-opacity"] - except: - alpha = 1 - if not value.startswith("url("): - fill = self.getColor(value, alpha) - self.write("ctx.fillStyle = %s;" % fill) - - def setStroke(self, value): - try: - alpha = self.style["stroke-opacity"] - except: - alpha = 1 - self.write("ctx.strokeStyle = %s;" % self.getColor(value, alpha)) - - def setStrokeWidth(self, value): - self.write("ctx.lineWidth = %f;" % self.parent.unittouu(value)) - - def setStrokeLinecap(self, value): - self.write("ctx.lineCap = '%s';" % value) - - def setStrokeLinejoin(self, value): - self.write("ctx.lineJoin = '%s';" % value) - - def setStrokeMiterlimit(self, value): - self.write("ctx.miterLimit = %s;" % value) - - def setFont(self, value): - self.write("ctx.font = \"%s\";" % value) - - def moveTo(self, x, y): - self.write("ctx.moveTo(%f, %f);" % (x, y)) - - def lineTo(self, x, y): - self.write("ctx.lineTo(%f, %f);" % (x, y)) - - def quadraticCurveTo(self, cpx, cpy, x, y): - data = (cpx, cpy, x, y) - self.write("ctx.quadraticCurveTo(%f, %f, %f, %f);" % data) - - def bezierCurveTo(self, x1, y1, x2, y2, x, y): - data = (x1, y1, x2, y2, x, y) - self.write("ctx.bezierCurveTo(%f, %f, %f, %f, %f, %f);" % data) - - def rect(self, x, y, w, h, rx = 0, ry = 0): - if rx or ry: - #rounded rectangle, starts top-left anticlockwise - self.moveTo(x, y + ry) - self.lineTo(x, y+h-ry) - self.quadraticCurveTo(x, y+h, x+rx, y+h) - self.lineTo(x+w-rx, y+h) - self.quadraticCurveTo(x+w, y+h, x+w, y+h-ry) - self.lineTo(x+w, y+ry) - self.quadraticCurveTo(x+w, y, x+w-rx, y) - self.lineTo(x+rx, y) - self.quadraticCurveTo(x, y, x, y+ry) - else: - self.write("ctx.rect(%f, %f, %f, %f);" % (x, y, w, h)) - - def arc(self, x, y, r, a1, a2, flag): - data = (x, y, r, a1, a2, flag) - self.write("ctx.arc(%f, %f, %f, %f, %.8f, %d);" % data) - - def fillText(self, text, x, y): - self.write("ctx.fillText(\"%s\", %f, %f);" % (text, x, y)) - - def translate(self, cx, cy): - self.write("ctx.translate(%f, %f);" % (cx, cy)) - - def rotate(self, angle): - self.write("ctx.rotate(%f);" % angle) - - def scale(self, rx, ry): - self.write("ctx.scale(%f, %f);" % (rx, ry)) - - def transform(self, m11, m12, m21, m22, dx, dy): - data = (m11, m12, m21, m22, dx, dy) - self.write("ctx.transform(%f, %f, %f, %f, %f, %f);" % data) - - def save(self): - self.write("ctx.save();") - - def restore(self): - self.write("ctx.restore();") - - def closePath(self): - if "fill" in self.style and self.style["fill"] != "none": - self.write("ctx.fill();") - if "stroke" in self.style and self.style["stroke"] != "none": - self.write("ctx.stroke();") - #self.write("%s.closePath();" % self.obj) diff --git a/share/extensions/ink2canvas/svg.py b/share/extensions/ink2canvas/svg.py deleted file mode 100644 index f4dca8279..000000000 --- a/share/extensions/ink2canvas/svg.py +++ /dev/null @@ -1,372 +0,0 @@ -''' -Copyright (C) 2011 Karlisson Bezerra <contact@hacktoon.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle -from simplepath import parsePath -from simpletransform import parseTransform - -class Element: - def attr(self, val, ns=""): - if ns: - val = inkex.addNS(val, ns) - try: - attr = float(self.node.get(val)) - except: - attr = self.node.get(val) - return attr - - -class GradientDef(Element): - def __init__(self, node, stops): - self.node = node - self.stops = stops - - -class LinearGradientDef(GradientDef): - def get_data(self): - x1 = self.attr("x1") - y1 = self.attr("y1") - x2 = self.attr("x2") - y2 = self.attr("y2") - #self.createLinearGradient(href, x1, y1, x2, y2) - - def draw(self): - pass - - -class RadialGradientDef(GradientDef): - def get_data(self): - cx = self.attr("cx") - cy = self.attr("cy") - r = self.attr("r") - #self.createRadialGradient(href, cx, cy, r, cx, cy, r) - - def draw(self): - pass - -class AbstractShape(Element): - def __init__(self, command, node, ctx): - self.node = node - self.command = command - self.ctx = ctx - - def get_data(self): - return - - def get_style(self): - style = simplestyle.parseStyle(self.attr("style")) - #remove any trailing space in dict keys/values - style = dict([(str.strip(k), str.strip(v)) for k,v in style.items()]) - return style - - def set_style(self, style): - """Translates style properties names into method calls""" - self.ctx.style = style - for key in style: - tmp_list = map(str.capitalize, key.split("-")) - method = "set" + "".join(tmp_list) - if hasattr(self.ctx, method) and style[key] != "none": - getattr(self.ctx, method)(style[key]) - #saves style to compare in next iteration - self.ctx.style_cache = style - - def has_transform(self): - return bool(self.attr("transform")) - - def get_transform(self): - data = self.node.get("transform") - if not data: - return - matrix = parseTransform(data) - m11, m21, dx = matrix[0] - m12, m22, dy = matrix[1] - return m11, m12, m21, m22, dx, dy - - def has_gradient(self): - style = self.get_style() - if "fill" in style: - fill = style["fill"] - return fill.startswith("url(#linear") or \ - fill.startswith("url(#radial") - return False - - def get_gradient_href(self): - style = self.get_style() - if "fill" in style: - return style["fill"][5:-1] - return - - def has_clip(self): - return bool(self.attr("clip-path")) - - def start(self, gradient): - self.gradient = gradient - self.ctx.write("\n// #%s" % self.attr("id")) - if self.has_transform() or self.has_clip(): - self.ctx.save() - - def draw(self): - data = self.get_data() - style = self.get_style() - self.ctx.beginPath() - if self.has_transform(): - trans_matrix = self.get_transform() - self.ctx.transform(*trans_matrix) # unpacks argument list - if self.has_gradient(): - self.gradient.draw() - self.set_style(style) - # unpacks "data" in parameters to given method - getattr(self.ctx, self.command)(*data) - self.ctx.closePath() - - def end(self): - if self.has_transform() or self.has_clip(): - self.ctx.restore() - - -class G(AbstractShape): - def draw(self): - #get layer label, if exists - gtype = self.attr("groupmode", "inkscape") or "group" - if self.has_transform(): - trans_matrix = self.get_transform() - self.ctx.transform(*trans_matrix) - - -class Rect(AbstractShape): - def get_data(self): - x = self.attr("x") - y = self.attr("y") - w = self.attr("width") - h = self.attr("height") - rx = self.attr("rx") or 0 - ry = self.attr("ry") or 0 - return x, y, w, h, rx, ry - - -class Circle(AbstractShape): - def __init__(self, command, node, ctx): - AbstractShape.__init__(self, command, node, ctx) - self.command = "arc" - - def get_data(self): - import math - cx = self.attr("cx") - cy = self.attr("cy") - r = self.attr("r") - return cx, cy, r, 0, math.pi * 2, True - - -class Ellipse(AbstractShape): - def get_data(self): - cx = self.attr("cx") - cy = self.attr("cy") - rx = self.attr("rx") - ry = self.attr("ry") - return cx, cy, rx, ry - - def draw(self): - import math - cx, cy, rx, ry = self.get_data() - style = self.get_style() - self.ctx.beginPath() - if self.has_transform(): - trans_matrix = self.get_transform() - self.ctx.transform(*trans_matrix) # unpacks argument list - self.set_style(style) - - KAPPA = 4 * ((math.sqrt(2) - 1) / 3) - self.ctx.moveTo(cx, cy - ry) - self.ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy) - self.ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry) - self.ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy) - self.ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry) - self.ctx.closePath() - - -class Path(AbstractShape): - def get_data(self): - #path data is already converted to float - return parsePath(self.attr("d")) - - def pathMoveTo(self, data): - self.ctx.moveTo(data[0], data[1]) - self.currentPosition = data[0], data[1] - - def pathLineTo(self, data): - self.ctx.lineTo(data[0], data[1]) - self.currentPosition = data[0], data[1] - - def pathCurveTo(self, data): - x1, y1, x2, y2 = data[0], data[1], data[2], data[3] - x, y = data[4], data[5] - self.ctx.bezierCurveTo(x1, y1, x2, y2, x, y) - self.currentPosition = x, y - - def pathArcTo(self, data): - #http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - # code adapted from http://code.google.com/p/canvg/ - import math - x1 = self.currentPosition[0] - y1 = self.currentPosition[1] - x2 = data[5] - y2 = data[6] - rx = data[0] - ry = data[1] - angle = data[2] * (math.pi / 180.0) - arcflag = data[3] - sweepflag = data[4] - - #compute (x1', y1') - _x1 = math.cos(angle) * (x1 - x2) / 2.0 + math.sin(angle) * (y1 - y2) / 2.0 - _y1 = -math.sin(angle) * (x1 - x2) / 2.0 + math.cos(angle) * (y1 - y2) / 2.0 - - #adjust radii - l = _x1**2 / rx**2 + _y1**2 / ry**2 - if l > 1: - rx *= math.sqrt(l) - ry *= math.sqrt(l) - - #compute (cx', cy') - numr = (rx**2 * ry**2) - (rx**2 * _y1**2) - (ry**2 * _x1**2) - demr = (rx**2 * _y1**2) + (ry**2 * _x1**2) - sig = -1 if arcflag == sweepflag else 1 - sig = sig * math.sqrt(numr / demr) - if math.isnan(sig): sig = 0; - _cx = sig * rx * _y1 / ry - _cy = sig * -ry * _x1 / rx - - #compute (cx, cy) from (cx', cy') - cx = (x1 + x2) / 2.0 + math.cos(angle) * _cx - math.sin(angle) * _cy - cy = (y1 + y2) / 2.0 + math.sin(angle) * _cx + math.cos(angle) * _cy - - #compute startAngle & endAngle - #vector magnitude - m = lambda v: math.sqrt(v[0]**2 + v[1]**2) - #ratio between two vectors - r = lambda u, v: (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v)) - #angle between two vectors - a = lambda u, v: (-1 if u[0]*v[1] < u[1]*v[0] else 1) * math.acos(r(u,v)) - #initial angle - a1 = a([1,0], [(_x1 - _cx) / rx, (_y1 - _cy)/ry]) - #angle delta - u = [(_x1 - _cx) / rx, (_y1 - _cy) / ry] - v = [(-_x1 - _cx) / rx, (-_y1 - _cy) / ry] - ad = a(u, v) - if r(u,v) <= -1: ad = math.pi - if r(u,v) >= 1: ad = 0 - - if sweepflag == 0 and ad > 0: ad = ad - 2 * math.pi; - if sweepflag == 1 and ad < 0: ad = ad + 2 * math.pi; - - r = rx if rx > ry else ry - sx = 1 if rx > ry else rx / ry - sy = ry / rx if rx > ry else 1 - - self.ctx.translate(cx, cy) - self.ctx.rotate(angle) - self.ctx.scale(sx, sy) - self.ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepflag) - self.ctx.scale(1/sx, 1/sy) - self.ctx.rotate(-angle) - self.ctx.translate(-cx, -cy) - self.currentPosition = x2, y2 - - def draw(self): - path = self.get_data() - style = self.get_style() - """Gets the node type and calls the given method""" - self.ctx.beginPath() - if self.has_transform(): - trans_matrix = self.get_transform() - self.ctx.transform(*trans_matrix) # unpacks argument list - self.set_style(style) - - """Draws path commands""" - path_command = {"M": self.pathMoveTo, - "L": self.pathLineTo, - "C": self.pathCurveTo, - "A": self.pathArcTo} - for pt in path: - comm, data = pt - if comm in path_command: - path_command[comm](data) - - self.ctx.closePath() - - -class Line(Path): - def get_data(self): - x1 = self.attr("x1") - y1 = self.attr("y1") - x2 = self.attr("x2") - y2 = self.attr("y2") - return (("M", (x1, y1)), ("L", (x2, y2))) - - -class Polygon(Path): - def get_data(self): - points = self.attr("points").strip().split(" ") - points = map(lambda x: x.split(","), points) - comm = [] - for pt in points: # creating path command similar - pt = map(float, pt) - comm.append(["L", pt]) - comm[0][0] = "M" # first command must be a 'M' => moveTo - return comm - - -class Polyline(Polygon): - pass - - -class Text(AbstractShape): - def text_helper(self, tspan): - if not len(tspan): - return unicode(tspan.text) - for ts in tspan: - return ts.text + self.text_helper(ts) + ts.tail - - def set_text_style(self, style): - keys = ("font-style", "font-weight", "font-size", "font-family") - text = [] - for key in keys: - if key in style: - text.append(style[key]) - self.ctx.setFont(" ".join(text)) - - def get_data(self): - x = self.attr("x") - y = self.attr("y") - return x, y - - def draw(self): - x, y = self.get_data() - style = self.get_style() - if self.has_transform(): - trans_matrix = self.get_transform() - self.ctx.transform(*trans_matrix) # unpacks argument list - self.set_style(style) - self.set_text_style(style) - - for tspan in self.node: - text = self.text_helper(tspan) - _x = float(tspan.get("x")) - _y = float(tspan.get("y")) - self.ctx.fillText(text, _x, _y) diff --git a/share/extensions/inkex.py b/share/extensions/inkex.py deleted file mode 100755 index 9d3bb0c6d..000000000 --- a/share/extensions/inkex.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -inkex.py -A helper module for creating Inkscape extensions - -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 -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" -import copy -import gettext -import optparse -import os -import random -import re -import sys -from math import * - -# a dictionary of all of the xmlns prefixes in a standard inkscape doc -NSS = { -u'sodipodi' :u'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd', -u'cc' :u'http://creativecommons.org/ns#', -u'ccOLD' :u'http://web.resource.org/cc/', -u'svg' :u'http://www.w3.org/2000/svg', -u'dc' :u'http://purl.org/dc/elements/1.1/', -u'rdf' :u'http://www.w3.org/1999/02/22-rdf-syntax-ns#', -u'inkscape' :u'http://www.inkscape.org/namespaces/inkscape', -u'xlink' :u'http://www.w3.org/1999/xlink', -u'xml' :u'http://www.w3.org/XML/1998/namespace' -} - - -def localize(): - domain = 'inkscape' - if sys.platform.startswith('win'): - import locale - current_locale, encoding = locale.getdefaultlocale() - os.environ['LANG'] = current_locale - try: - localdir = os.environ['INKSCAPE_LOCALEDIR'] - trans = gettext.translation(domain, localdir, [current_locale], fallback=True) - except KeyError: - trans = gettext.translation(domain, fallback=True) - elif sys.platform.startswith('darwin'): - try: - localdir = os.environ['INKSCAPE_LOCALEDIR'] - trans = gettext.translation(domain, localdir, fallback=True) - except KeyError: - try: - localdir = os.environ['PACKAGE_LOCALE_DIR'] - trans = gettext.translation(domain, localdir, fallback=True) - except KeyError: - trans = gettext.translation(domain, fallback=True) - else: - try: - localdir = os.environ['PACKAGE_LOCALE_DIR'] - trans = gettext.translation(domain, localdir, fallback=True) - except KeyError: - trans = gettext.translation(domain, fallback=True) - #sys.stderr.write(str(localdir) + "\n") - trans.install() - - -def debug(what): - sys.stderr.write(str(what) + "\n") - return what - - -def errormsg(msg): - """Intended for end-user-visible error messages. - - (Currently just writes to stderr with an appended newline, but could do - something better in future: e.g. could add markup to distinguish error - messages from status messages or debugging output.) - - Note that this should always be combined with translation: - - import inkex - ... - inkex.errormsg(_("This extension requires two selected paths.")) - """ - if isinstance(msg, unicode): - sys.stderr.write(msg.encode("utf-8") + "\n") - else: - sys.stderr.write((unicode(msg, "utf-8", errors='replace') + "\n").encode("utf-8")) - - -def are_near_relative(a, b, eps): - return (a-b <= a*eps) and (a-b >= -a*eps) - - -# third party library -try: - from lxml import etree -except ImportError as e: - localize() - errormsg(_("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, ))) - sys.exit() - - -def check_inkbool(option, opt, value): - if str(value).capitalize() == 'True': - return True - elif str(value).capitalize() == 'False': - return False - else: - raise optparse.OptionValueError("option %s: invalid inkbool value: %s" % (opt, value)) - - -def addNS(tag, ns=None): - val = tag - if ns is not None and len(ns) > 0 and ns in NSS and len(tag) > 0 and tag[0] != '{': - val = "{%s}%s" % (NSS[ns], tag) - return val - - -class InkOption(optparse.Option): - TYPES = optparse.Option.TYPES + ("inkbool",) - TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER) - TYPE_CHECKER["inkbool"] = check_inkbool - - -class Effect: - """A class for creating Inkscape SVG Effects""" - - def __init__(self, *args, **kwargs): - self.document = None - self.original_document = None - self.ctx = None - self.selected = {} - self.doc_ids = {} - self.options = None - self.args = None - self.OptionParser = optparse.OptionParser(usage="usage: %prog [options] SVGfile", - option_class=InkOption) - self.OptionParser.add_option("--id", - action="append", type="string", dest="ids", default=[], - help="id attribute of object to manipulate") - self.OptionParser.add_option("--selected-nodes", - action="append", type="string", dest="selected_nodes", default=[], - help="id:subpath:position of selected nodes, if any") - # TODO write a parser for this - - def effect(self): - """Apply some effects on the document. Extensions subclassing Effect - must override this function and define the transformations - in it.""" - pass - - def getoptions(self,args=sys.argv[1:]): - """Collect command line arguments""" - self.options, self.args = self.OptionParser.parse_args(args) - - def parse(self, filename=None): - """Parse document in specified file or on stdin""" - - # First try to open the file from the function argument - if filename is not None: - try: - stream = open(filename, 'r') - except IOError: - errormsg(_("Unable to open specified file: %s") % filename) - sys.exit() - - # If it wasn't specified, try to open the file specified as - # an object member - elif self.svg_file is not None: - try: - stream = open(self.svg_file, 'r') - except IOError: - errormsg(_("Unable to open object member file: %s") % self.svg_file) - sys.exit() - - # Finally, if the filename was not specified anywhere, use - # standard input stream - else: - stream = sys.stdin - - p = etree.XMLParser(huge_tree=True) - self.document = etree.parse(stream, parser=p) - self.original_document = copy.deepcopy(self.document) - stream.close() - - # defines view_center in terms of document units - def getposinlayer(self): - #defaults - self.current_layer = self.document.getroot() - self.view_center = (0.0, 0.0) - - layerattr = self.document.xpath('//sodipodi:namedview/@inkscape:current-layer', namespaces=NSS) - if layerattr: - layername = layerattr[0] - layer = self.document.xpath('//svg:g[@id="%s"]' % layername, namespaces=NSS) - if layer: - self.current_layer = layer[0] - - xattr = self.document.xpath('//sodipodi:namedview/@inkscape:cx', namespaces=NSS) - yattr = self.document.xpath('//sodipodi:namedview/@inkscape:cy', namespaces=NSS) - if xattr and yattr: - x = self.unittouu(xattr[0] + 'px') - y = self.unittouu(yattr[0] + 'px') - doc_height = self.unittouu(self.getDocumentHeight()) - if x and y: - self.view_center = (float(x), doc_height - float(y)) - # FIXME: y-coordinate flip, eliminate it when it's gone in Inkscape - - def getselected(self): - """Collect selected nodes""" - for i in self.options.ids: - path = '//*[@id="%s"]' % i - for node in self.document.xpath(path, namespaces=NSS): - self.selected[i] = node - - def getElementById(self, id): - path = '//*[@id="%s"]' % id - el_list = self.document.xpath(path, namespaces=NSS) - if el_list: - return el_list[0] - else: - return None - - def getParentNode(self, node): - for parent in self.document.getiterator(): - if node in parent.getchildren(): - return parent - - def getdocids(self): - docIdNodes = self.document.xpath('//@id', namespaces=NSS) - for m in docIdNodes: - self.doc_ids[m] = 1 - - def getNamedView(self): - return self.document.xpath('//sodipodi:namedview', namespaces=NSS)[0] - - def createGuide(self, posX, posY, angle): - atts = { - 'position': str(posX)+','+str(posY), - 'orientation': str(sin(radians(angle)))+','+str(-cos(radians(angle))) - } - guide = etree.SubElement( - self.getNamedView(), - addNS('guide','sodipodi'), atts) - return guide - - def output(self): - """Serialize document into XML on stdout""" - original = etree.tostring(self.original_document) - result = etree.tostring(self.document) - if original != result: - self.document.write(sys.stdout) - - def affect(self, args=sys.argv[1:], output=True): - """Affect an SVG document with a callback effect""" - self.svg_file = args[-1] - localize() - self.getoptions(args) - self.parse() - self.getposinlayer() - self.getselected() - self.getdocids() - self.effect() - if output: - self.output() - - def uniqueId(self, old_id, make_new_id=True): - new_id = old_id - if make_new_id: - while new_id in self.doc_ids: - new_id += random.choice('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') - self.doc_ids[new_id] = 1 - return new_id - - def xpathSingle(self, path): - try: - retval = self.document.xpath(path, namespaces=NSS)[0] - except: - errormsg(_("No matching node for expression: %s") % path) - retval = None - return retval - - # a dictionary of unit to user unit conversion factors - __uuconv = {'in': 96.0, 'pt': 1.33333333333, 'px': 1.0, 'mm': 3.77952755913, 'cm': 37.7952755913, - 'm': 3779.52755913, 'km': 3779527.55913, 'pc': 16.0, 'yd': 3456.0, 'ft': 1152.0} - - # Fault tolerance for lazily defined SVG - def getDocumentWidth(self): - width = self.document.getroot().get('width') - if width: - return width - else: - viewbox = self.document.getroot().get('viewBox') - if viewbox: - return viewbox.split()[2] - else: - return '0' - - # Fault tolerance for lazily defined SVG - def getDocumentHeight(self): - """Returns a string corresponding to the height of the document, as - defined in the SVG file. If it is not defined, returns the height - as defined by the viewBox attribute. If viewBox is not defined, - returns the string '0'.""" - height = self.document.getroot().get('height') - if height: - return height - else: - viewbox = self.document.getroot().get('viewBox') - if viewbox: - return viewbox.split()[3] - else: - return '0' - - def getDocumentUnit(self): - """Returns the unit used for in the SVG document. - In the case the SVG document lacks an attribute that explicitly - defines what units are used for SVG coordinates, it tries to calculate - the unit from the SVG width and viewBox attributes. - Defaults to 'px' units.""" - svgunit = 'px' # default to pixels - - svgwidth = self.getDocumentWidth() - viewboxstr = self.document.getroot().get('viewBox') - if viewboxstr: - unitmatch = re.compile('(%s)$' % '|'.join(self.__uuconv.keys())) - param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - - p = param.match(svgwidth) - u = unitmatch.search(svgwidth) - - width = 100 # default - viewboxwidth = 100 # default - svgwidthunit = 'px' # default assume 'px' unit - if p: - width = float(p.string[p.start():p.end()]) - else: - errormsg(_("SVG Width not set correctly! Assuming width = 100")) - if u: - svgwidthunit = u.string[u.start():u.end()] - - viewboxnumbers = [] - for t in viewboxstr.split(): - try: - viewboxnumbers.append(float(t)) - except ValueError: - pass - if len(viewboxnumbers) == 4: # check for correct number of numbers - viewboxwidth = viewboxnumbers[2] - - svgunitfactor = self.__uuconv[svgwidthunit] * width / viewboxwidth - - # try to find the svgunitfactor in the list of units known. If we don't find something, ... - eps = 0.01 # allow 1% error in factor - for key in self.__uuconv: - if are_near_relative(self.__uuconv[key], svgunitfactor, eps): - # found match! - svgunit = key - - return svgunit - - def unittouu(self, string): - """Returns userunits given a string representation of units in another system""" - unit = re.compile('(%s)$' % '|'.join(self.__uuconv.keys())) - param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - - p = param.match(string) - u = unit.search(string) - if p: - retval = float(p.string[p.start():p.end()]) - else: - retval = 0.0 - if u: - try: - return retval * (self.__uuconv[u.string[u.start():u.end()]] / self.__uuconv[self.getDocumentUnit()]) - except KeyError: - pass - else: # default assume 'px' unit - return retval / self.__uuconv[self.getDocumentUnit()] - - return retval - - def uutounit(self, val, unit): - return val / (self.__uuconv[unit] / self.__uuconv[self.getDocumentUnit()]) - - def addDocumentUnit(self, value): - """Add document unit when no unit is specified in the string """ - try: - float(value) - return value + self.getDocumentUnit() - except ValueError: - return value - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/inkscape.extension.rng b/share/extensions/inkscape.extension.rng deleted file mode 100644 index c352cd122..000000000 --- a/share/extensions/inkscape.extension.rng +++ /dev/null @@ -1,324 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" ns="http://www.inkscape.org/namespace/inkscape/extension"> - <start> - <element name="inkscape-extension"> - <element name="_name"> - <text/> - </element> - <element name="id"> - <text/> - </element> - <zeroOrMore> - <element name="dependency"> - <attribute name="type"> - <ref name="inx.dependency-type.values"/> - </attribute> - <optional> - <attribute name="location"> - <ref name="inx.location.values"/> - </attribute> - </optional> - <optional> - <attribute name="_description"> - <text/> - </attribute> - </optional> - <text/> - </element> - </zeroOrMore> - <zeroOrMore> - <choice> - <ref name="inx.parameters"/> - <element name="param"> - <attribute name="name"/> - <attribute name="type"> - <value>notebook</value> - </attribute> - <oneOrMore> - <element name="page"> - <attribute name="name"/> - <attribute name="_gui-text"/> - <oneOrMore> - <ref name="inx.parameters"/> - </oneOrMore> - </element> - </oneOrMore> - </element> - </choice> - </zeroOrMore> - <choice> - <element name="input"> - <ref name="inx.io.common"/> - <optional> - <element name="output_extension"> - <text/> - </element> - </optional> - </element> - <element name="output"> - <ref name="inx.io.common"/> - <optional> - <element name="dataloss"> - <data type="boolean"/> - </element> - </optional> - </element> - <element name="effect"> - <optional> - <attribute name="needs-document"> - <data type="boolean"/> - </attribute> - </optional> - <optional> - <attribute name="needs-live-preview"> - <data type="boolean"/> - </attribute> - </optional> - <element name="object-type"> - <choice> - <value type="token">all</value> - <value type="token">path</value> - <value type="token">rect</value> - </choice> - </element> - <element name="effects-menu"> - <choice> - <attribute name="hidden"> - <value type="boolean">true</value> - </attribute> - <group> - <element name="submenu"> - <attribute name="_name"> - <text/> - </attribute> - <empty/> - </element> - </group> - </choice> - </element> - </element> - <element name="path-effect"> - <empty/> - </element> - <element name="print"> - <empty/> - </element> - </choice> - <choice> - <element name="script"> - <group> - <element name="command"> - <ref name="inx.reldir.attr"/> - <optional> - <attribute name="interpreter"> - <choice> - <value>python</value> - <value>perl</value> - </choice> - </attribute> - </optional> - <text/> - </element> - <optional> - <element name="helper_extension"> - <data type="NMTOKEN"/> - </element> - </optional> - <zeroOrMore> - <element name="check"> - <ref name="inx.reldir.attr"/> - <text/> - </element> - </zeroOrMore> - </group> - </element> - <element name="xslt"> - <element name="file"> - <ref name="inx.reldir.attr"/> - <text/> - </element> - </element> - <element name="plugin"> - <element name="name"> - <text/> - </element> - </element> - </choice> - </element> - </start> - <define name="inx.reldir.attr"> - <attribute name="reldir"> - <ref name="inx.location.values"/> - </attribute> - </define> - <define name="inx.location.values"> - <choice> - <value>extensions</value> - <value>path</value> - <value>plugins</value> - </choice> - </define> - <define name="inx.dependency-type.values"> - <choice> - <value>extension</value> - <value>executable</value> - <value>plugin</value> - </choice> - </define> - <define name="inx.io.common"> - <element name="extension"> - <text/> - </element> - <element name="mimetype"> - <text/> - </element> - <optional> - <element name="_filetypename"> - <text/> - </element> - </optional> - <optional> - <element name="_filetypetooltip"> - <text/> - </element> - </optional> - </define> - <define name="inx.parameter"> - <attribute name="name"> - <data type="token"/> - </attribute> - <optional> - <attribute name="gui-hidden"> - <data type="boolean"/> - </attribute> - </optional> - <optional> - <attribute name="_gui-text"/> - </optional> - <choice> - <group> - <attribute name="type"> - <value>int</value> - </attribute> - <optional> - <attribute name="min"> - <data type="integer"/> - </attribute> - </optional> - <optional> - <attribute name="max"> - <data type="integer"/> - </attribute> - </optional> - <choice> - <empty/> - <data type="integer"/> - </choice> - </group> - <group> - <attribute name="type"> - <value>float</value> - </attribute> - <optional> - <attribute name="precision"> - <data type="integer"/> - </attribute> - </optional> - <optional> - <attribute name="min"> - <data type="float"/> - </attribute> - </optional> - <optional> - <attribute name="max"> - <data type="float"/> - </attribute> - </optional> - <data type="float"/> - </group> - <group> - <attribute name="type"> - <value>boolean</value> - </attribute> - <data type="boolean"/> - </group> - <group> - <attribute name="type"> - <value>string</value> - </attribute> - <optional> - <attribute name="max_length"> - <data type="integer"/> - </attribute> - </optional> - <choice> - <empty/> - <text/> - </choice> - </group> - <group> - <attribute name="type"> - <value>description</value> - </attribute> - <text/> - </group> - <group> - <attribute name="type"> - <value>enum</value> - </attribute> - <oneOrMore> - <choice> - <element name="_item"> - <ref name="inx.parameter.enum.item"/> - </element> - <element name="item"> - <ref name="inx.parameter.enum.item"/> - </element> - </choice> - </oneOrMore> - </group> - <group> - <attribute name="type"> - <value>optiongroup</value> - </attribute> - <optional> - <attribute name="appearance"> - <value>minimal</value> - </attribute> - </optional> - <oneOrMore> - <choice> - <element name="option"> - <ref name="inx.parameter.optiongroup.option"/> - </element> - <element name="_option"> - <ref name="inx.parameter.optiongroup.option"/> - </element> - </choice> - </oneOrMore> - </group> - </choice> - </define> - <define name="inx.parameters"> - <choice> - <element name="param"> - <ref name="inx.parameter"/> - </element> - <element name="_param"> - <ref name="inx.parameter"/> - </element> - </choice> - </define> - <define name="inx.parameter.enum.item"> - <attribute name="value"/> - <data type="token"/> - </define> - <define name="inx.parameter.optiongroup.option"> - <optional> - <attribute name="value"> - <text/> - </attribute> - </optional> - <text/> - </define> -</grammar> diff --git a/share/extensions/inkscape_follow_link.inx b/share/extensions/inkscape_follow_link.inx deleted file mode 100644 index d2ee0a8a1..000000000 --- a/share/extensions/inkscape_follow_link.inx +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Follow Link</_name> - <id>org.inkscape.followlink</id> - <dependency type="executable" location="extensions">inkscape_follow_link.py</dependency> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <script> - <command reldir="extensions" interpreter="python">inkscape_follow_link.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/inkscape_follow_link.py b/share/extensions/inkscape_follow_link.py deleted file mode 100755 index bf19cb84f..000000000 --- a/share/extensions/inkscape_follow_link.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python - -import threading -import webbrowser - -import inkex - -class VisitWebSiteWithoutLockingInkscape(threading.Thread): - def __init__(self, url): - threading.Thread.__init__ (self) - self.url = url - - def run(self): - webbrowser.open(self.url) - -class FollowLink(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - if (self.options.ids): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('a','svg'): - self.url = node.get(inkex.addNS('href','xlink')) - vwswli = VisitWebSiteWithoutLockingInkscape(self.url) - vwswli.start() - #inkex.errormsg("Link: %s" % self.url) - break - - -if __name__ == '__main__': - e = FollowLink() - e.affect(output=False) - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/inkscape_help_askaquestion.inx b/share/extensions/inkscape_help_askaquestion.inx deleted file mode 100644 index b093558cb..000000000 --- a/share/extensions/inkscape_help_askaquestion.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Ask Us a Question</_name> - <id>org.inkscape.help.askaquestion</id> - <dependency type="executable" location="extensions">launch_webbrowser.py</dependency> - <_param name="url" gui-hidden="true" type="string">https://inkscape.org/en/ask/</_param> - <effect needs-document="false"> - <object-type>all</object-type> - <effects-menu hidden="true"/> - </effect> - <script> - <command reldir="extensions" interpreter="python">launch_webbrowser.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/inkscape_help_commandline.inx b/share/extensions/inkscape_help_commandline.inx deleted file mode 100644 index b87b154f6..000000000 --- a/share/extensions/inkscape_help_commandline.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Command Line Options</_name>
- <id>org.inkscape.help.commandline</id>
- <dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
- <!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/inkscape-man.html</_param>
- <effect needs-document="false">
- <object-type>all</object-type>
- <effects-menu hidden="true" />
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">launch_webbrowser.py</command>
- </script>
-</inkscape-extension> diff --git a/share/extensions/inkscape_help_faq.inx b/share/extensions/inkscape_help_faq.inx deleted file mode 100644 index fda97c08b..000000000 --- a/share/extensions/inkscape_help_faq.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>FAQ</_name>
- <id>org.inkscape.help.faq</id>
- <dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
- <param name="url" gui-hidden="true" type="string">https://inkscape.org/learn/faq/</param>
- <effect needs-document="false">
- <object-type>all</object-type>
- <effects-menu hidden="true" />
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">launch_webbrowser.py</command>
- </script>
-</inkscape-extension> diff --git a/share/extensions/inkscape_help_keys.inx b/share/extensions/inkscape_help_keys.inx deleted file mode 100644 index 5aabbea41..000000000 --- a/share/extensions/inkscape_help_keys.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Keys and Mouse Reference</_name>
- <id>org.inkscape.help.keys</id>
- <dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
- <!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/keys092.html</_param>
- <effect needs-document="false">
- <object-type>all</object-type>
- <effects-menu hidden="true" />
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">launch_webbrowser.py</command>
- </script>
-</inkscape-extension> diff --git a/share/extensions/inkscape_help_manual.inx b/share/extensions/inkscape_help_manual.inx deleted file mode 100644 index e96f4ff8c..000000000 --- a/share/extensions/inkscape_help_manual.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>Inkscape Manual</_name>
- <id>org.inkscape.help.manual</id>
- <dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
- <!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://tavmjong.free.fr/INKSCAPE/MANUAL/html/index.php</_param>
- <effect needs-document="false">
- <object-type>all</object-type>
- <effects-menu hidden="true" />
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">launch_webbrowser.py</command>
- </script>
-</inkscape-extension> diff --git a/share/extensions/inkscape_help_relnotes.inx b/share/extensions/inkscape_help_relnotes.inx deleted file mode 100644 index 5c5b1b4e8..000000000 --- a/share/extensions/inkscape_help_relnotes.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
- <_name>New in This Version</_name>
- <id>org.inkscape.help.relnotes</id>
- <dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
- <!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://wiki.inkscape.org/wiki/index.php/Release_notes/0.92</_param>
- <effect needs-document="false">
- <object-type>all</object-type>
- <effects-menu hidden="true" />
- </effect>
- <script>
- <command reldir="extensions" interpreter="python">launch_webbrowser.py</command>
- </script>
-</inkscape-extension> diff --git a/share/extensions/inkscape_help_reportabug.inx b/share/extensions/inkscape_help_reportabug.inx deleted file mode 100644 index 81239a8ed..000000000 --- a/share/extensions/inkscape_help_reportabug.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Report a Bug</_name> - <id>org.inkscape.help.reportabug</id> - <dependency type="executable" location="extensions">launch_webbrowser.py</dependency> - <param name="url" gui-hidden="true" type="string">http://inkscape.org/contribute/report-bugs/</param> - <effect needs-document="false"> - <object-type>all</object-type> - <effects-menu hidden="true"/> - </effect> - <script> - <command reldir="extensions" interpreter="python">launch_webbrowser.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/inkscape_help_svgspec.inx b/share/extensions/inkscape_help_svgspec.inx deleted file mode 100644 index 34a111839..000000000 --- a/share/extensions/inkscape_help_svgspec.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>SVG 1.1 Specification</_name> - <id>org.inkscape.help.svgspec</id> - <dependency type="executable" location="extensions">launch_webbrowser.py</dependency> - <param name="url" gui-hidden="true" type="string">http://www.w3.org/TR/SVG11/</param> - <effect needs-document="false"> - <object-type>all</object-type> - <effects-menu hidden="true"/> - </effect> - <script> - <command reldir="extensions" interpreter="python">launch_webbrowser.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/inkweb.js b/share/extensions/inkweb.js deleted file mode 100644 index 142f51bab..000000000 --- a/share/extensions/inkweb.js +++ /dev/null @@ -1,192 +0,0 @@ -/* -** InkWeb - Inkscape's Javscript features for the open vector web -** -** Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot com -** -** ********* Bugs and New Fetures ************************************* -** If you found any bug on this script or if you want to propose a -** new feature, please report it in the inkscape bug traker -** https://bugs.launchpad.net/inkscape/+filebug -** and assign that to Aurium. -** ******************************************************************** -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU Lesser General Public License as published -** by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. -** -** You should have received a copy of the GNU Lesser General Public License -** along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -var InkWeb = { - - version: 0.04, - - NS: { - svg: "http://www.w3.org/2000/svg", - sodipodi: "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd", - inkscape: "http://www.inkscape.org/namespaces/inkscape", - cc: "http://creativecommons.org/ns#", - dc: "http://purl.org/dc/elements/1.1/", - rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - xlink: "http://www.w3.org/1999/xlink", - xml: "http://www.w3.org/XML/1998/namespace" - } - -}; - -InkWeb.el = function (tag, attributes) { - // A helper to create SVG elements - var element = document.createElementNS( this.NS.svg, tag ); - for ( var att in attributes ) { - switch ( att ) { - case "parent": - attributes.parent.appendChild( element ); - break; - case "text": - element.appendChild( document.createTextNode( attributes.text ) ); - break; - default: - element.setAttribute( att, attributes[att] ); - } - } - return element; -} - -InkWeb.reGetStyleAttVal = function (att) { - return new RegExp( "(^|.*;)[ ]*"+ att +":([^;]*)(;.*|$)" ) -} - -InkWeb.getStyle = function (el, att) { - // This method is needed because el.style is only working - // to HTML style in the Firefox 3.0 - if ( typeof(el) == "string" ) - el = document.getElementById(el); - var style = el.getAttribute("style"); - var match = this.reGetStyleAttVal(att).exec(style); - if ( match ) { - return match[2]; - } else { - return false; - } -} - -InkWeb.setStyle = function (el, att, val) { - if ( typeof(el) == "string" ) - el = document.getElementById(el); - var style = el.getAttribute("style"); - re = this.reGetStyleAttVal(att); - if ( re.test(style) ) { - style = style.replace( re, "$1"+ att +":"+ val +"$3" ); - } else { - style += ";"+ att +":"+ val; - } - el.setAttribute( "style", style ); - return val -} - -InkWeb.transmitAtt = function (conf) { - conf.att = conf.att.split( /\s+/ ); - if ( typeof(conf.from) == "string" ) - conf.from = document.getElementById( conf.from ); - if ( ! conf.to.join ) - conf.to = [ conf.to ]; - for ( var toEl,elN=0; toEl=conf.to[elN]; elN++ ) { - if ( typeof(toEl) == "string" ) - toEl = document.getElementById( toEl ); - for ( var i=0; i<conf.att.length; i++ ) { - var val = this.getStyle( conf.from, conf.att[i] ); - if ( val ) { - this.setStyle( toEl, conf.att[i], val ); - } else { - val = conf.from.getAttribute(conf.att[i]); - toEl.setAttribute( conf.att[i], val ); - } - } - } -} - -InkWeb.setAtt = function (conf) { - if ( ! conf.el.join ) - conf.to = [ conf.el ]; - conf.att = conf.att.split( /\s+/ ); - conf.val = conf.val.split( /\s+/ ); - for ( var el,elN=0; el=conf.el[elN]; elN++ ) { - if ( typeof(el) == "string" ) - el = document.getElementById( el ); - for ( var att,i=0; att=conf.att[i]; i++ ) { - if ( - att == "width" || - att == "height" || - att == "x" || - att == "y" || - att == "cx" || - att == "cy" || - att == "r" || - att == "rx" || - att == "ry" || - att == "transform" - ) { - el.setAttribute( att, conf.val[i] ); - } else { - this.setStyle( el, att, conf.val[i] ); - } - } - } -} - -InkWeb.moveElTo = function (startConf) { - if ( typeof(startConf) == "string" ) { - // startConf may be only a element Id, to timeout recursive calls. - var el = document.getElementById( startConf ); - } else { - if ( typeof(startConf.el) == "string" ) - startConf.el = document.getElementById( startConf.el ); - var el = startConf.el; - } - if ( ! el.inkWebMoving ) { - el.inkWebMoving = { - step: 0 - }; - } - var conf = el.inkWebMoving; - if ( conf.step == 0 ) { - conf.x = startConf.x; - conf.y = startConf.y; - // dur : duration of the animation in seconds - if ( startConf.dur ) { conf.dur = startConf.dur } - else { conf.dur = 1 } - // steps : animation steps in a second - if ( startConf.stepsBySec ) { conf.stepsBySec = startConf.stepsBySec } - else { conf.stepsBySec = 16 } - conf.sleep = Math.round( 1000 / conf.stepsBySec ); - conf.steps = conf.dur * conf.stepsBySec; - var startPos = el.getBBox(); - conf.xInc = ( conf.x - startPos.x ) / conf.steps; - conf.yInc = ( conf.y - startPos.y ) / conf.steps; - conf.transform = el.transform.baseVal.consolidate(); - if ( ! conf.transform ) { - conf.transform = el.ownerSVGElement.createSVGTransform(); - } - el.transform.baseVal.clear(); - el.transform.baseVal.appendItem(conf.transform); - } - if ( conf.step < conf.steps ) { - conf.step++; - conf.transform.matrix.e += conf.xInc; - conf.transform.matrix.f += conf.yInc; - try{ el.ownerSVGElement.forceRedraw() } - catch(e){ this.log(e, "this "+el.ownerSVGElement+" has no forceRedraw().") } - conf.timeout = setTimeout( 'InkWeb.moveElTo("'+el.id+'")', conf.sleep ); - } else { - delete el.inkWebMoving; - } -} - -InkWeb.log = function () { /* if you need that, use the inkweb-debug.js too */ } diff --git a/share/extensions/inkwebeffect.py b/share/extensions/inkwebeffect.py deleted file mode 100755 index 4e29892de..000000000 --- a/share/extensions/inkwebeffect.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex, sys, os, re - -class InkWebEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.reUpdateJS = '/\\*\\s* inkweb.js [^*]* InkWebEffect:AutoUpdate \\s*\\*/' - - def mustAddInkWebJSCode(self, scriptEl): - if not scriptEl.text: return True - if len(scriptEl.text) == 0: return True - if re.search(self.reUpdateJS, scriptEl.text): return True - return False - - def addInkWebJSCode(self, scriptEl): - js = open( os.path.join(sys.path[0], "inkweb.js"), 'r' ) - if hasattr(inkex.etree, "CDATA"): - scriptEl.text = \ - inkex.etree.CDATA( - "\n/* inkweb.js - InkWebEffect:AutoUpdate */\n" + js.read() - ) - else: - scriptEl.text = \ - "\n/* inkweb.js - InkWebEffect:AutoUpdate */\n" + js.read() - js.close() - - def ensureInkWebSupport(self): - # Search for the script tag with the inkweb.js code: - scriptEl = None - scripts = self.document.xpath('//svg:script', namespaces=inkex.NSS) - for s in scripts: - if re.search(self.reUpdateJS, s.text): - scriptEl = s - - if scriptEl is None: - root = self.document.getroot() - scriptEl = inkex.etree.Element( "script" ) - scriptEl.set( "id", "inkwebjs" ) - scriptEl.set( "type", "text/javascript" ) - root.insert( 0, scriptEl ) - - if self.mustAddInkWebJSCode(scriptEl): - self.addInkWebJSCode(scriptEl) - diff --git a/share/extensions/interp.inx b/share/extensions/interp.inx deleted file mode 100644 index 470d5dc10..000000000 --- a/share/extensions/interp.inx +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Interpolate</_name> - <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="dup" type="boolean" _gui-text="Duplicate endpaths">true</param> - <param name="style" type="boolean" _gui-text="Interpolate style">false</param> - <param name="zsort" type="boolean" _gui-text="Use Z-order" _gui-description="Workaround for reversed selection order in Live Preview cycles">false</param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">interp.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/interp.py b/share/extensions/interp.py deleted file mode 100755 index fd80ab412..000000000 --- a/share/extensions/interp.py +++ /dev/null @@ -1,336 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, cubicsuperpath, simplestyle, copy, math, bezmisc, simpletransform, pathmodifier - -def numsegs(csp): - return sum([len(p)-1 for p in csp]) -def interpcoord(v1,v2,p): - return v1+((v2-v1)*p) -def interppoints(p1,p2,p): - return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)] -def pointdistance((x1,y1),(x2,y2)): - return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2)) -def bezlenapprx(sp1, sp2): - return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1]) -def tpoint((x1,y1), (x2,y2), t = 0.5): - return [x1+t*(x2-x1),y1+t*(y2-y1)] -def cspbezsplit(sp1, sp2, t = 0.5): - m1=tpoint(sp1[1],sp1[2],t) - m2=tpoint(sp1[2],sp2[0],t) - m3=tpoint(sp2[0],sp2[1],t) - m4=tpoint(m1,m2,t) - m5=tpoint(m2,m3,t) - m=tpoint(m4,m5,t) - return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]] -def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001): - bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) - t = bezmisc.beziertatlength(bez, l, tolerance) - return cspbezsplit(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: - lengths.append([]) - for i in xrange(1,len(sp)): - l = cspseglength(sp[i-1],sp[i]) - lengths[-1].append(l) - total += l - return lengths, total - -def tweenstylefloat(property, start, end, time): - sp = float(start[property]) - ep = float(end[property]) - return str(sp + (time * (ep - sp))) -def tweenstylecolor(property, start, end, time): - sr,sg,sb = parsecolor(start[property]) - er,eg,eb = parsecolor(end[property]) - return '#%s%s%s' % (tweenhex(time,sr,er),tweenhex(time,sg,eg),tweenhex(time,sb,eb)) -def tweenhex(time,s,e): - s = float(int(s,16)) - e = float(int(e,16)) - retval = hex(int(math.floor(s + (time * (e - s)))))[2:] - if len(retval)==1: - retval = '0%s' % retval - return retval -def parsecolor(c): - r,g,b = '0','0','0' - if c[:1]=='#': - if len(c)==4: - r,g,b = c[1:2],c[2:3],c[3:4] - elif len(c)==7: - r,g,b = c[1:3],c[3:5],c[5:7] - return r,g,b - -class Interp(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-e", "--exponent", - action="store", type="float", - dest="exponent", default=0.0, - help="values other than zero give non linear interpolation") - self.OptionParser.add_option("-s", "--steps", - action="store", type="int", - dest="steps", default=5, - help="number of interpolation steps") - self.OptionParser.add_option("-m", "--method", - action="store", type="int", - dest="method", default=2, - help="method of interpolation") - self.OptionParser.add_option("-d", "--dup", - action="store", type="inkbool", - dest="dup", default=True, - help="duplicate endpaths") - self.OptionParser.add_option("--style", - action="store", type="inkbool", - dest="style", default=True, - help="try interpolation of some style properties") - self.OptionParser.add_option("--zsort", - action="store", type="inkbool", - dest="zsort", default=False, - help="use z-order instead of selection order") - - def tweenstyleunit(self, property, start, end, time): # moved here so we can call 'unittouu' - scale = self.unittouu('1px') - sp = self.unittouu(start.get(property, '1px')) / scale - ep = self.unittouu(end.get(property, '1px')) / scale - return str(sp + (time * (ep - sp))) - - def effect(self): - exponent = self.options.exponent - if exponent>= 0: - exponent = 1.0 + exponent - else: - exponent = 1.0/(1.0 - exponent) - steps = [1.0/(self.options.steps + 1.0)] - for i in range(self.options.steps - 1): - steps.append(steps[0] + steps[-1]) - steps = [step**exponent for step in steps] - - paths = {} - styles = {} - - if self.options.zsort: - # work around selection order swapping with Live Preview - sorted_ids = pathmodifier.zSort(self.document.getroot(),self.selected.keys()) - else: - # use selection order (default) - sorted_ids = self.options.ids - - for id in sorted_ids: - node = self.selected[id] - if node.tag ==inkex.addNS('path','svg'): - paths[id] = cubicsuperpath.parsePath(node.get('d')) - styles[id] = simplestyle.parseStyle(node.get('style')) - trans = node.get('transform') - if trans: - simpletransform.applyTransformToPath(simpletransform.parseTransform(trans), paths[id]) - else: - sorted_ids.remove(id) - - for i in range(1,len(sorted_ids)): - start = copy.deepcopy(paths[sorted_ids[i-1]]) - end = copy.deepcopy(paths[sorted_ids[i]]) - sst = copy.deepcopy(styles[sorted_ids[i-1]]) - est = copy.deepcopy(styles[sorted_ids[i]]) - basestyle = copy.deepcopy(sst) - if basestyle.has_key('stroke-width'): - basestyle['stroke-width'] = self.tweenstyleunit('stroke-width',sst,est,0) - - #prepare for experimental style tweening - if self.options.style: - dostroke = True - dofill = True - styledefaults = {'opacity':'1.0', 'stroke-opacity':'1.0', 'fill-opacity':'1.0', - 'stroke-width':'1.0', 'stroke':'none', 'fill':'none'} - for key in styledefaults.keys(): - sst.setdefault(key,styledefaults[key]) - est.setdefault(key,styledefaults[key]) - isnotplain = lambda x: not (x=='none' or x[:1]=='#') - if isnotplain(sst['stroke']) or isnotplain(est['stroke']) or (sst['stroke']=='none' and est['stroke']=='none'): - dostroke = False - if isnotplain(sst['fill']) or isnotplain(est['fill']) or (sst['fill']=='none' and est['fill']=='none'): - dofill = False - if dostroke: - if sst['stroke']=='none': - sst['stroke-width'] = '0.0' - sst['stroke-opacity'] = '0.0' - sst['stroke'] = est['stroke'] - elif est['stroke']=='none': - est['stroke-width'] = '0.0' - est['stroke-opacity'] = '0.0' - est['stroke'] = sst['stroke'] - if dofill: - if sst['fill']=='none': - sst['fill-opacity'] = '0.0' - sst['fill'] = est['fill'] - elif est['fill']=='none': - est['fill-opacity'] = '0.0' - est['fill'] = sst['fill'] - - - - if self.options.method == 2: - #subdivide both paths into segments of relatively equal lengths - slengths, stotal = csplength(start) - elengths, etotal = csplength(end) - lengths = {} - t = 0 - for sp in slengths: - for l in sp: - t += l / stotal - lengths.setdefault(t,0) - lengths[t] += 1 - t = 0 - for sp in elengths: - for l in sp: - t += l / etotal - lengths.setdefault(t,0) - lengths[t] += -1 - sadd = [k for (k,v) in lengths.iteritems() if v < 0] - sadd.sort() - eadd = [k for (k,v) in lengths.iteritems() if v > 0] - eadd.sort() - - t = 0 - s = [[]] - for sp in slengths: - if not start[0]: - s.append(start.pop(0)) - s[-1].append(start[0].pop(0)) - for l in sp: - pt = t - t += l / stotal - if sadd and t > sadd[0]: - while sadd and sadd[0] < t: - nt = (sadd[0] - pt) / (t - pt) - bezes = cspbezsplitatlength(s[-1][-1][:],start[0][0][:], nt) - s[-1][-1:] = bezes[:2] - start[0][0] = bezes[2] - pt = sadd.pop(0) - s[-1].append(start[0].pop(0)) - t = 0 - e = [[]] - for sp in elengths: - if not end[0]: - e.append(end.pop(0)) - e[-1].append(end[0].pop(0)) - for l in sp: - pt = t - t += l / etotal - if eadd and t > eadd[0]: - while eadd and eadd[0] < t: - nt = (eadd[0] - pt) / (t - pt) - bezes = cspbezsplitatlength(e[-1][-1][:],end[0][0][:], nt) - e[-1][-1:] = bezes[:2] - end[0][0] = bezes[2] - pt = eadd.pop(0) - e[-1].append(end[0].pop(0)) - start = s[:] - end = e[:] - else: - #which path has fewer segments? - lengthdiff = numsegs(start) - numsegs(end) - #swap shortest first - if lengthdiff > 0: - start, end = end, start - #subdivide the shorter path - for x in range(abs(lengthdiff)): - maxlen = 0 - subpath = 0 - segment = 0 - for y in range(len(start)): - for z in range(1, len(start[y])): - leng = bezlenapprx(start[y][z-1], start[y][z]) - if leng > maxlen: - maxlen = leng - subpath = y - segment = z - sp1, sp2 = start[subpath][segment - 1:segment + 1] - start[subpath][segment - 1:segment + 1] = cspbezsplit(sp1, sp2) - #if swapped, swap them back - if lengthdiff > 0: - start, end = end, start - - #break paths so that corresponding subpaths have an equal number of segments - s = [[]] - e = [[]] - while start and end: - if start[0] and end[0]: - s[-1].append(start[0].pop(0)) - e[-1].append(end[0].pop(0)) - elif end[0]: - s.append(start.pop(0)) - e[-1].append(end[0][0]) - e.append([end[0].pop(0)]) - elif start[0]: - e.append(end.pop(0)) - s[-1].append(start[0][0]) - s.append([start[0].pop(0)]) - else: - s.append(start.pop(0)) - e.append(end.pop(0)) - - if self.options.dup: - steps = [0] + steps + [1] - #create an interpolated path for each interval - group = inkex.etree.SubElement(self.current_layer,inkex.addNS('g','svg')) - for time in steps: - interp = [] - #process subpaths - for ssp,esp in zip(s, e): - if not (ssp or esp): - break - interp.append([]) - #process superpoints - for sp,ep in zip(ssp, esp): - if not (sp or ep): - break - interp[-1].append([]) - #process points - for p1,p2 in zip(sp, ep): - if not (sp or ep): - break - interp[-1][-1].append(interppoints(p1, p2, time)) - - #remove final subpath if empty. - if not interp[-1]: - del interp[-1] - - #basic style tweening - if self.options.style: - basestyle['opacity'] = tweenstylefloat('opacity',sst,est,time) - if dostroke: - basestyle['stroke-opacity'] = tweenstylefloat('stroke-opacity',sst,est,time) - basestyle['stroke-width'] = self.tweenstyleunit('stroke-width',sst,est,time) - basestyle['stroke'] = tweenstylecolor('stroke',sst,est,time) - if dofill: - basestyle['fill-opacity'] = tweenstylefloat('fill-opacity',sst,est,time) - basestyle['fill'] = tweenstylecolor('fill',sst,est,time) - attribs = {'style':simplestyle.formatStyle(basestyle),'d':cubicsuperpath.formatPath(interp)} - new = inkex.etree.SubElement(group,inkex.addNS('path','svg'), attribs) - -if __name__ == '__main__': - e = Interp() - e.affect() - - -# 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 deleted file mode 100644 index 5f6c3d7a4..000000000 --- a/share/extensions/interp_att_g.inx +++ /dev/null @@ -1,61 +0,0 @@ -<?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="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-header" type="description" appearance="header">Other Attribute</_param> - <_param name="other-info" type="description">If you selected "Other" above, you must specify the details for this "other" here.</_param> - <param name="att-other" type="string" _gui-text="Other Attribute:" _gui-description="Examples: r, width, inkscape:rounded, sodipodi:sides"></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="numbers" type="description" appearance="header">Values</_param> - <param name="start-val" type="string" _gui-text="Start Value:" _gui-description="Examples: 0.5, 5, #rgb, #rrggbb or r, g, b"></param> - <param name="end-val" type="string" _gui-text="End Value:" _gui-description="Examples: 0.5, 5, #rgb, #rrggbb or r, g, b"></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> - <param name="zsort" type="boolean" _gui-text="Use Z-order" _gui-description="Workaround for reversed selection order in Live Preview cycles" gui-hidden="true">true</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 deleted file mode 100755 index ec6abbf47..000000000 --- a/share/extensions/interp_att_g.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import sys -import math -import re -import string -# local library -import inkex -import simplestyle -from pathmodifier import zSort - - -class InterpAttG(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-a", "--att", - action="store", type="string", - dest="att", default="fill", - help="Attribute to be interpolated.") - self.OptionParser.add_option("-o", "--att-other", - action="store", type="string", - dest="att_other", - help="Other attribute (for a limited UI).") - self.OptionParser.add_option("-t", "--att-other-type", - action="store", type="string", - dest="att_other_type", - help="The other attribute type.") - self.OptionParser.add_option("-w", "--att-other-where", - action="store", type="string", - dest="att_other_where", - help="That is a tag attribute or a style attribute?") - self.OptionParser.add_option("-s", "--start-val", - action="store", type="string", - dest="start_val", default="#F00", - help="Initial interpolation value.") - self.OptionParser.add_option("-e", "--end-val", - action="store", type="string", - dest="end_val", default="#00F", - help="End interpolation value.") - self.OptionParser.add_option("-u", "--unit", - action="store", type="string", - dest="unit", default="color", - help="Values unit.") - self.OptionParser.add_option("--zsort", - action="store", type="inkbool", - dest="zsort", default=True, - help="use z-order instead of selection order") - 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, '#', '' ) - ev = string.replace( self.options.end_val, '#', '' ) - - # index 0: start color, index 1: end color - self.R, self.G, self.B = [0,0],[0,0],[0,0] - raw_colors = [sv, ev] - - for i in [0,1]: - if re.search('\s|,', raw_colors[i]): - # There are separators. That must be an integer RGB color definition. - raw_colors[i] = re.split( '[\s,]+', raw_colors[i]) - self.R[i] = int(raw_colors[i][0]) - self.G[i] = int(raw_colors[i][1]) - self.B[i] = int(raw_colors[i][2]) - else: - # There is no separator. That must be a Hex RGB color definition. - if len(raw_colors[i]) == 3: - self.R[i] = int(raw_colors[i][0] + raw_colors[i][0], 16) - self.G[i] = int(raw_colors[i][1] + raw_colors[i][1], 16) - self.B[i] = int(raw_colors[i][2] + raw_colors[i][2], 16) - else: # the len must be 6 - self.R[i] = int( raw_colors[i][0] + raw_colors[i][1], 16) - self.G[i] = int( raw_colors[i][2] + raw_colors[i][3], 16) - self.B[i] = int( raw_colors[i][4] + raw_colors[i][5], 16) - - self.R_inc = (self.R[1] - self.R[0]) / float(self.tot_el - 1) - self.G_inc = (self.G[1] - self.G[0]) / float(self.tot_el - 1) - self.B_inc = (self.B[1] - self.B[0]) / float(self.tot_el - 1) - self.R_cur = self.R[0] - self.G_cur = self.G[0] - self.B_cur = self.B[0] - - def getNumberValues(self): - sv = self.options.start_val.replace(",", ".") - ev = self.options.end_val.replace(",", ".") - unit = self.options.unit - - if unit != 'none': - sv = self.unittouu(sv + unit) - ev = self.unittouu(ev + unit) - else: - sv = float(sv) - ev = float(ev) - self.val_cur = self.val_ini = sv - self.val_end = ev - self.val_inc = (ev - sv)/float(self.tot_el - 1) - - def getTotElements(self): - self.tot_el = 0 - self.collection = None - if len( self.selected ) == 0: - return False - if len( self.selected ) > 1: - # multiple selection - if self.options.zsort: - sorted_ids = zSort(self.document.getroot(),self.selected.keys()) - else: - sorted_ids = self.options.ids - self.collection = list(sorted_ids) - for i in sorted_ids: - path = '//*[@id="%s"]' % i - self.collection[self.tot_el] = self.document.xpath(path, namespaces=inkex.NSS)[0] - self.tot_el += 1 - else: - # must be a group - self.collection = self.selected[ self.options.ids[0] ] - for i in self.collection: - self.tot_el += 1 - - def effect(self): - if self.options.att == 'other': - if self.options.att_other is not None: - self.inte_att = self.options.att_other - else: - inkex.errormsg(_("You selected 'Other'. Please enter an attribute to interpolate.")) - sys.exit(0) - self.inte_att_type = self.options.att_other_type - self.where = self.options.att_other_where - else: - self.inte_att = self.options.att - if self.inte_att == 'width': - self.inte_att_type = 'float' - self.where = 'tag' - elif self.inte_att == 'height': - self.inte_att_type = 'float' - self.where = 'tag' - elif self.inte_att == 'scale': - self.inte_att_type = 'float' - self.where = 'transform' - elif self.inte_att == 'trans-x': - self.inte_att_type = 'float' - self.where = 'transform' - elif self.inte_att == 'trans-y': - self.inte_att_type = 'float' - self.where = 'transform' - elif self.inte_att == 'fill': - self.inte_att_type = 'color' - self.where = 'style' - elif self.inte_att == 'opacity': - self.inte_att_type = 'float' - self.where = 'style' - - self.getTotElements() - - if self.inte_att_type == 'color': - self.getColorValues() - else: - self.getNumberValues() - - if self.collection is None: - inkex.errormsg( _('There is no selection to interpolate' )) - return False - - for node in self.collection: - if self.inte_att_type == 'color': - val = 'rgb('+ \ - str(int(round(self.R_cur))) +','+ \ - str(int(round(self.G_cur))) +','+ \ - str(int(round(self.B_cur))) +')' - else: - if self.inte_att_type == 'float': - val = self.val_cur - else: # inte_att_type == 'int' - val = int(round(self.val_cur)) - - if self.where == 'style': - s = node.get('style') - re_find = '(^|;)'+ self.inte_att +':[^;]*(;|$)' - if re.search( re_find, s ): - s = re.sub( re_find, '\\1'+ self.inte_att +':'+ str(val) +'\\2', s ) - else: - s += ';'+ self.inte_att +':'+ str(val) - node.set( 'style', s ) - elif self.where == 'transform': - t = node.get('transform') - if t == None: t = "" - if self.inte_att == 'trans-x': - val = "translate("+ str(val) +",0)" - elif self.inte_att == 'trans-y': - val = "translate(0,"+ str(val) +")" - else: - val = self.inte_att + "("+ str(val) +")" - node.set( 'transform', t +" "+ val ) - else: # self.where == 'tag': - if ":" in self.inte_att: - ns, attrib = self.inte_att.split(":") - node.set(inkex.addNS(attrib, ns), str(val)) - else: - node.set( self.inte_att, str(val) ) - - if self.inte_att_type == 'color': - self.R_cur += self.R_inc - self.G_cur += self.G_inc - self.B_cur += self.B_inc - else: - self.val_cur += self.val_inc - - return True - -if __name__ == '__main__': - e = InterpAttG() - if e.affect(): - exit(0) - else: - exit(1) diff --git a/share/extensions/jessyInk.js b/share/extensions/jessyInk.js deleted file mode 100644 index 3ccf707d3..000000000 --- a/share/extensions/jessyInk.js +++ /dev/null @@ -1,2727 +0,0 @@ -// Copyright 2008, 2009 Hannes Hochreiner -// 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 3 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, see http://www.gnu.org/licenses/. - -// Set onload event handler. -window.onload = jessyInkInit; - -// Creating a namespace dictionary. The standard Inkscape namespaces are taken from inkex.py. -var NSS = new Object(); -NSS['sodipodi']='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'; -NSS['cc']='http://web.resource.org/cc/'; -NSS['svg']='http://www.w3.org/2000/svg'; -NSS['dc']='http://purl.org/dc/elements/1.1/'; -NSS['rdf']='http://www.w3.org/1999/02/22-rdf-syntax-ns#'; -NSS['inkscape']='http://www.inkscape.org/namespaces/inkscape'; -NSS['xlink']='http://www.w3.org/1999/xlink'; -NSS['xml']='http://www.w3.org/XML/1998/namespace'; -NSS['jessyink']='https://launchpad.net/jessyink'; - -// Keycodes. -var LEFT_KEY = 37; // cursor left keycode -var UP_KEY = 38; // cursor up keycode -var RIGHT_KEY = 39; // cursor right keycode -var DOWN_KEY = 40; // cursor down keycode -var PAGE_UP_KEY = 33; // page up keycode -var PAGE_DOWN_KEY = 34; // page down keycode -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; -var INDEX_MODE = 2; -var DRAWING_MODE = 3; - -// Mouse handler actions. -var MOUSE_UP = 1; -var MOUSE_DOWN = 2; -var MOUSE_MOVE = 3; -var MOUSE_WHEEL = 4; - -// Parameters. -var ROOT_NODE = document.getElementsByTagNameNS(NSS["svg"], "svg")[0]; -var HEIGHT = 0; -var WIDTH = 0; -var INDEX_COLUMNS_DEFAULT = 4; -var INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; -var INDEX_OFFSET = 0; -var STATE_START = -1; -var STATE_END = -2; -var BACKGROUND_COLOR = null; -var slides = new Array(); - -// Initialisation. -var currentMode = SLIDE_MODE; -var masterSlide = null; -var activeSlide = 0; -var activeEffect = 0; -var timeStep = 30; // 40 ms equal 25 frames per second. -var lastFrameTime = null; -var processingEffect = false; -var transCounter = 0; -var effectArray = 0; -var defaultTransitionInDict = new Object(); -defaultTransitionInDict["name"] = "appear"; -var defaultTransitionOutDict = new Object(); -defaultTransitionOutDict["name"] = "appear"; -var jessyInkInitialised = false; - -// Initialise char and key code dictionaries. -var charCodeDictionary = getDefaultCharCodeDictionary(); -var keyCodeDictionary = getDefaultKeyCodeDictionary(); - -// Initialise mouse handler dictionary. -var mouseHandlerDictionary = getDefaultMouseHandlerDictionary(); - -var progress_bar_visible = false; -var timer_elapsed = 0; -var timer_start = timer_elapsed; -var timer_duration = 15; // 15 minutes - -var history_counter = 0; -var history_original_elements = new Array(); -var history_presentation_elements = new Array(); - -var mouse_original_path = null; -var mouse_presentation_path = null; -var mouse_last_x = -1; -var mouse_last_y = -1; -var mouse_min_dist_sqr = 3 * 3; -var path_colour = "red"; -var path_width_default = 3; -var path_width = path_width_default; -var path_paint_width = path_width; - -var number_of_added_slides = 0; - -/** Initialisation function. - * The whole presentation is set-up in this function. - */ -function jessyInkInit() -{ - // Make sure we only execute this code once. Double execution can occur if the onload event handler is set - // in the main svg tag as well (as was recommended in earlier versions). Executing this function twice does - // not lead to any problems, but it takes more time. - if (jessyInkInitialised) - return; - - // Making the presentation scalable. - var VIEWBOX = ROOT_NODE.getAttribute("viewBox"); - - if (VIEWBOX) - { - WIDTH = ROOT_NODE.viewBox.animVal.width; - HEIGHT = ROOT_NODE.viewBox.animVal.height; - } - else - { - HEIGHT = parseFloat(ROOT_NODE.getAttribute("height")); - WIDTH = parseFloat(ROOT_NODE.getAttribute("width")); - ROOT_NODE.setAttribute("viewBox", "0 0 " + WIDTH + " " + HEIGHT); - } - - ROOT_NODE.setAttribute("width", "100%"); - ROOT_NODE.setAttribute("height", "100%"); - - // Setting the background color. - var namedViews = document.getElementsByTagNameNS(NSS["sodipodi"], "namedview"); - - for (var counter = 0; counter < namedViews.length; counter++) - { - if (namedViews[counter].hasAttribute("id") && namedViews[counter].hasAttribute("pagecolor")) - { - if (namedViews[counter].getAttribute("id") == "base") - { - BACKGROUND_COLOR = namedViews[counter].getAttribute("pagecolor"); - var newAttribute = "background-color:" + BACKGROUND_COLOR + ";"; - - if (ROOT_NODE.hasAttribute("style")) - newAttribute += ROOT_NODE.getAttribute("style"); - - ROOT_NODE.setAttribute("style", newAttribute); - } - } - } - - // Defining clip-path. - var defsNodes = document.getElementsByTagNameNS(NSS["svg"], "defs"); - - if (defsNodes.length > 0) - { - var existingClipPath = document.getElementById("jessyInkSlideClipPath"); - - if (!existingClipPath) - { - var rectNode = document.createElementNS(NSS["svg"], "rect"); - var clipPath = document.createElementNS(NSS["svg"], "clipPath"); - - rectNode.setAttribute("x", 0); - rectNode.setAttribute("y", 0); - rectNode.setAttribute("width", WIDTH); - rectNode.setAttribute("height", HEIGHT); - - clipPath.setAttribute("id", "jessyInkSlideClipPath"); - clipPath.setAttribute("clipPathUnits", "userSpaceOnUse"); - - clipPath.appendChild(rectNode); - defsNodes[0].appendChild(clipPath); - } - } - - // Making a list of the slide and finding the master slide. - var nodes = document.getElementsByTagNameNS(NSS["svg"], "g"); - var tempSlides = new Array(); - var existingJessyInkPresentationLayer = null; - - for (var counter = 0; counter < nodes.length; counter++) - { - if (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") && (nodes[counter].getAttributeNS(NSS["inkscape"], "groupmode") == "layer")) - { - if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "masterSlide") == "masterSlide") - masterSlide = nodes[counter]; - else if (nodes[counter].getAttributeNS(NSS["inkscape"], "label") && nodes[counter].getAttributeNS(NSS["jessyink"], "presentationLayer") == "presentationLayer") - existingJessyInkPresentationLayer = nodes[counter]; - else - tempSlides.push(nodes[counter].getAttribute("id")); - } - else if (nodes[counter].getAttributeNS(NSS['jessyink'], 'element')) - { - handleElement(nodes[counter]); - } - } - - // Hide master slide set default transitions. - if (masterSlide) - { - masterSlide.style.display = "none"; - - if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionIn")) - defaultTransitionInDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionIn")); - - if (masterSlide.hasAttributeNS(NSS["jessyink"], "transitionOut")) - defaultTransitionOutDict = propStrToDict(masterSlide.getAttributeNS(NSS["jessyink"], "transitionOut")); - } - - if (existingJessyInkPresentationLayer != null) - { - existingJessyInkPresentationLayer.parentNode.removeChild(existingJessyInkPresentationLayer); - } - - // Set start slide. - var hashObj = new LocationHash(window.location.hash); - - activeSlide = hashObj.slideNumber; - activeEffect = hashObj.effectNumber; - - if (activeSlide < 0) - activeSlide = 0; - else if (activeSlide >= tempSlides.length) - activeSlide = tempSlides.length - 1; - - var originalNode = document.getElementById(tempSlides[counter]); - - var JessyInkPresentationLayer = document.createElementNS(NSS["svg"], "g"); - JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); - JessyInkPresentationLayer.setAttributeNS(NSS["inkscape"], "label", "JessyInk Presentation Layer"); - JessyInkPresentationLayer.setAttributeNS(NSS["jessyink"], "presentationLayer", "presentationLayer"); - JessyInkPresentationLayer.setAttribute("id", "jessyink_presentation_layer"); - JessyInkPresentationLayer.style.display = "inherit"; - ROOT_NODE.appendChild(JessyInkPresentationLayer); - - // Gathering all the information about the transitions and effects of the slides, set the background - // from the master slide and substitute the auto-texts. - for (var counter = 0; counter < tempSlides.length; counter++) - { - var originalNode = document.getElementById(tempSlides[counter]); - originalNode.style.display = "none"; - var node = suffixNodeIds(originalNode.cloneNode(true), "_" + counter); - JessyInkPresentationLayer.appendChild(node); - slides[counter] = new Object(); - slides[counter]["original_element"] = originalNode; - slides[counter]["element"] = node; - - // Set build in transition. - slides[counter]["transitionIn"] = new Object(); - - var dict; - - if (node.hasAttributeNS(NSS["jessyink"], "transitionIn")) - dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionIn")); - else - dict = defaultTransitionInDict; - - slides[counter]["transitionIn"]["name"] = dict["name"]; - slides[counter]["transitionIn"]["options"] = new Object(); - - for (key in dict) - if (key != "name") - slides[counter]["transitionIn"]["options"][key] = dict[key]; - - // Set build out transition. - slides[counter]["transitionOut"] = new Object(); - - if (node.hasAttributeNS(NSS["jessyink"], "transitionOut")) - dict = propStrToDict(node.getAttributeNS(NSS["jessyink"], "transitionOut")); - else - dict = defaultTransitionOutDict; - - slides[counter]["transitionOut"]["name"] = dict["name"]; - slides[counter]["transitionOut"]["options"] = new Object(); - - for (key in dict) - if (key != "name") - slides[counter]["transitionOut"]["options"][key] = dict[key]; - - // Copy master slide content. - if (masterSlide) - { - var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + counter); - clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); - clonedNode.removeAttributeNS(NSS["inkscape"], "label"); - clonedNode.style.display = "inherit"; - - node.insertBefore(clonedNode, node.firstChild); - } - - // Setting clip path. - node.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); - - // Substitute auto texts. - substituteAutoTexts(node, node.getAttributeNS(NSS["inkscape"], "label"), counter + 1, tempSlides.length); - - node.removeAttributeNS(NSS["inkscape"], "groupmode"); - node.removeAttributeNS(NSS["inkscape"], "label"); - - // Set effects. - var tempEffects = new Array(); - var groups = new Object(); - - for (var IOCounter = 0; IOCounter <= 1; IOCounter++) - { - var propName = ""; - var dir = 0; - - if (IOCounter == 0) - { - propName = "effectIn"; - dir = 1; - } - else if (IOCounter == 1) - { - propName = "effectOut"; - dir = -1; - } - - var effects = getElementsByPropertyNS(node, NSS["jessyink"], propName); - - for (var effectCounter = 0; effectCounter < effects.length; effectCounter++) - { - var element = document.getElementById(effects[effectCounter]); - var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], propName)); - - // Put every element that has an effect associated with it, into its own group. - // Unless of course, we already put it into its own group. - if (!(groups[element.id])) - { - var newGroup = document.createElementNS(NSS["svg"], "g"); - - element.parentNode.insertBefore(newGroup, element); - newGroup.appendChild(element.parentNode.removeChild(element)); - groups[element.id] = newGroup; - } - - var effectDict = new Object(); - - effectDict["effect"] = dict["name"]; - effectDict["dir"] = dir; - effectDict["element"] = groups[element.id]; - - for (var option in dict) - { - if ((option != "name") && (option != "order")) - { - if (!effectDict["options"]) - effectDict["options"] = new Object(); - - effectDict["options"][option] = dict[option]; - } - } - - if (!tempEffects[dict["order"]]) - tempEffects[dict["order"]] = new Array(); - - tempEffects[dict["order"]][tempEffects[dict["order"]].length] = effectDict; - } - } - - // Make invisible, but keep in rendering tree to ensure that bounding box can be calculated. - node.setAttribute("opacity",0); - node.style.display = "inherit"; - - // Create a transform group. - var transformGroup = document.createElementNS(NSS["svg"], "g"); - - // Add content to transform group. - while (node.firstChild) - transformGroup.appendChild(node.firstChild); - - // Transfer the transform attribute from the node to the transform group. - if (node.getAttribute("transform")) - { - transformGroup.setAttribute("transform", node.getAttribute("transform")); - node.removeAttribute("transform"); - } - - // Create a view group. - var viewGroup = document.createElementNS(NSS["svg"], "g"); - - viewGroup.appendChild(transformGroup); - slides[counter]["viewGroup"] = node.appendChild(viewGroup); - - // Insert background. - if (BACKGROUND_COLOR != null) - { - var rectNode = document.createElementNS(NSS["svg"], "rect"); - - rectNode.setAttribute("x", 0); - rectNode.setAttribute("y", 0); - rectNode.setAttribute("width", WIDTH); - rectNode.setAttribute("height", HEIGHT); - rectNode.setAttribute("id", "jessyInkBackground" + counter); - rectNode.setAttribute("fill", BACKGROUND_COLOR); - - slides[counter]["viewGroup"].insertBefore(rectNode, slides[counter]["viewGroup"].firstChild); - } - - // Set views. - var tempViews = new Array(); - var views = getElementsByPropertyNS(node, NSS["jessyink"], "view"); - var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - - // Set initial view even if there are no other views. - slides[counter]["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); - slides[counter].initialView = matrixOld.toAttribute(); - - for (var viewCounter = 0; viewCounter < views.length; viewCounter++) - { - var element = document.getElementById(views[viewCounter]); - var dict = propStrToDict(element.getAttributeNS(NSS["jessyink"], "view")); - - if (dict["order"] == 0) - { - matrixOld = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); - slides[counter].initialView = matrixOld.toAttribute(); - } - else - { - var effectDict = new Object(); - - effectDict["effect"] = dict["name"]; - effectDict["dir"] = 1; - effectDict["element"] = slides[counter]["viewGroup"]; - effectDict["order"] = dict["order"]; - - for (var option in dict) - { - if ((option != "name") && (option != "order")) - { - if (!effectDict["options"]) - effectDict["options"] = new Object(); - - effectDict["options"][option] = dict[option]; - } - } - - effectDict["options"]["matrixNew"] = pointMatrixToTransformation(rectToMatrix(element)).mult((new matrixSVG()).fromSVGMatrix(slides[counter].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(element.parentNode.getScreenCTM())).inv()); - - tempViews[dict["order"]] = effectDict; - } - - // Remove element. - element.parentNode.removeChild(element); - } - - // Consolidate view array and append it to the effect array. - if (tempViews.length > 0) - { - for (var viewCounter = 0; viewCounter < tempViews.length; viewCounter++) - { - if (tempViews[viewCounter]) - { - tempViews[viewCounter]["options"]["matrixOld"] = matrixOld; - matrixOld = tempViews[viewCounter]["options"]["matrixNew"]; - - if (!tempEffects[tempViews[viewCounter]["order"]]) - tempEffects[tempViews[viewCounter]["order"]] = new Array(); - - tempEffects[tempViews[viewCounter]["order"]][tempEffects[tempViews[viewCounter]["order"]].length] = tempViews[viewCounter]; - } - } - } - - // Set consolidated effect array. - if (tempEffects.length > 0) - { - slides[counter]["effects"] = new Array(); - - for (var effectCounter = 0; effectCounter < tempEffects.length; effectCounter++) - { - if (tempEffects[effectCounter]) - slides[counter]["effects"][slides[counter]["effects"].length] = tempEffects[effectCounter]; - } - } - - node.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); - - // Set visibility for initial state. - if (counter == activeSlide) - { - node.style.display = "inherit"; - node.setAttribute("opacity",1); - } - else - { - node.style.display = "none"; - node.setAttribute("opacity",0); - } - } - - // Set key handler. - var jessyInkObjects = document.getElementsByTagNameNS(NSS["svg"], "g"); - - for (var counter = 0; counter < jessyInkObjects.length; counter++) - { - var elem = jessyInkObjects[counter]; - - if (elem.getAttributeNS(NSS["jessyink"], "customKeyBindings")) - { - if (elem.getCustomKeyBindings != undefined) - keyCodeDictionary = elem.getCustomKeyBindings(); - - if (elem.getCustomCharBindings != undefined) - charCodeDictionary = elem.getCustomCharBindings(); - } - } - - // Set mouse handler. - var jessyInkMouseHandler = document.getElementsByTagNameNS(NSS["jessyink"], "mousehandler"); - - for (var counter = 0; counter < jessyInkMouseHandler.length; counter++) - { - var elem = jessyInkMouseHandler[counter]; - - if (elem.getMouseHandler != undefined) - { - var tempDict = elem.getMouseHandler(); - - for (mode in tempDict) - { - if (!mouseHandlerDictionary[mode]) - mouseHandlerDictionary[mode] = new Object(); - - for (handler in tempDict[mode]) - mouseHandlerDictionary[mode][handler] = tempDict[mode][handler]; - } - } - } - - // Check effect number. - if ((activeEffect < 0) || (!slides[activeSlide].effects)) - { - activeEffect = 0; - } - else if (activeEffect > slides[activeSlide].effects.length) - { - activeEffect = slides[activeSlide].effects.length; - } - - createProgressBar(JessyInkPresentationLayer); - hideProgressBar(); - setProgressBarValue(activeSlide); - setTimeIndicatorValue(0); - setInterval("updateTimer()", 1000); - setSlideToState(activeSlide, activeEffect); - jessyInkInitialised = true; -} - -/** Function to substitute the auto-texts. - * - * @param node the node - * @param slideName name of the slide the node is on - * @param slideNumber number of the slide the node is on - * @param numberOfSlides number of slides in the presentation - */ -function substituteAutoTexts(node, slideName, slideNumber, numberOfSlides) -{ - var texts = node.getElementsByTagNameNS(NSS["svg"], "tspan"); - - for (var textCounter = 0; textCounter < texts.length; textCounter++) - { - if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideNumber") - texts[textCounter].firstChild.nodeValue = slideNumber; - else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "numberOfSlides") - texts[textCounter].firstChild.nodeValue = numberOfSlides; - else if (texts[textCounter].getAttributeNS(NSS["jessyink"], "autoText") == "slideTitle") - texts[textCounter].firstChild.nodeValue = slideName; - } -} - -/** Convenience function to get an element depending on whether it has a property with a particular name. - * This function emulates some dearly missed XPath functionality. - * - * @param node the node - * @param namespace namespace of the attribute - * @param name attribute name - */ -function getElementsByPropertyNS(node, namespace, name) -{ - var elems = new Array(); - - if (node.getAttributeNS(namespace, name)) - elems.push(node.getAttribute("id")); - - for (var counter = 0; counter < node.childNodes.length; counter++) - { - if (node.childNodes[counter].nodeType == 1) - elems = elems.concat(getElementsByPropertyNS(node.childNodes[counter], namespace, name)); - } - - return elems; -} - -/** Function to dispatch the next effect, if there is none left, change the slide. - * - * @param dir direction of the change (1 = forwards, -1 = backwards) - */ -function dispatchEffects(dir) -{ - if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) - { - processingEffect = true; - - if (dir == 1) - { - effectArray = slides[activeSlide]["effects"][activeEffect]; - activeEffect += dir; - } - else if (dir == -1) - { - activeEffect += dir; - effectArray = slides[activeSlide]["effects"][activeEffect]; - } - - transCounter = 0; - startTime = (new Date()).getTime(); - lastFrameTime = null; - effect(dir); - } - else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) - { - changeSlide(dir); - } -} - -/** Function to skip effects and directly either put the slide into start or end state or change slides. - * - * @param dir direction of the change (1 = forwards, -1 = backwards) - */ -function skipEffects(dir) -{ - if (slides[activeSlide]["effects"] && (((dir == 1) && (activeEffect < slides[activeSlide]["effects"].length)) || ((dir == -1) && (activeEffect > 0)))) - { - processingEffect = true; - - if (slides[activeSlide]["effects"] && (dir == 1)) - activeEffect = slides[activeSlide]["effects"].length; - else - activeEffect = 0; - - if (dir == 1) - setSlideToState(activeSlide, STATE_END); - else - setSlideToState(activeSlide, STATE_START); - - processingEffect = false; - } - else if (((dir == 1) && (activeSlide < (slides.length - 1))) || (((dir == -1) && (activeSlide > 0)))) - { - changeSlide(dir); - } -} - -/** Function to change between slides. - * - * @param dir direction (1 = forwards, -1 = backwards) - */ -function changeSlide(dir) -{ - processingEffect = true; - effectArray = new Array(); - - effectArray[0] = new Object(); - if (dir == 1) - { - effectArray[0]["effect"] = slides[activeSlide]["transitionOut"]["name"]; - effectArray[0]["options"] = slides[activeSlide]["transitionOut"]["options"]; - effectArray[0]["dir"] = -1; - } - else if (dir == -1) - { - effectArray[0]["effect"] = slides[activeSlide]["transitionIn"]["name"]; - effectArray[0]["options"] = slides[activeSlide]["transitionIn"]["options"]; - effectArray[0]["dir"] = 1; - } - effectArray[0]["element"] = slides[activeSlide]["element"]; - - activeSlide += dir; - setProgressBarValue(activeSlide); - - effectArray[1] = new Object(); - - if (dir == 1) - { - effectArray[1]["effect"] = slides[activeSlide]["transitionIn"]["name"]; - effectArray[1]["options"] = slides[activeSlide]["transitionIn"]["options"]; - effectArray[1]["dir"] = 1; - } - else if (dir == -1) - { - effectArray[1]["effect"] = slides[activeSlide]["transitionOut"]["name"]; - effectArray[1]["options"] = slides[activeSlide]["transitionOut"]["options"]; - effectArray[1]["dir"] = -1; - } - - effectArray[1]["element"] = slides[activeSlide]["element"]; - - if (slides[activeSlide]["effects"] && (dir == -1)) - activeEffect = slides[activeSlide]["effects"].length; - else - activeEffect = 0; - - if (dir == -1) - setSlideToState(activeSlide, STATE_END); - else - setSlideToState(activeSlide, STATE_START); - - transCounter = 0; - startTime = (new Date()).getTime(); - lastFrameTime = null; - effect(dir); -} - -/** Function to toggle between index and slide mode. -*/ -function toggleSlideIndex() -{ - var suspendHandle = ROOT_NODE.suspendRedraw(500); - - if (currentMode == SLIDE_MODE) - { - hideProgressBar(); - INDEX_OFFSET = -1; - indexSetPageSlide(activeSlide); - currentMode = INDEX_MODE; - } - else if (currentMode == INDEX_MODE) - { - for (var counter = 0; counter < slides.length; counter++) - { - slides[counter]["element"].setAttribute("transform","scale(1)"); - - if (counter == activeSlide) - { - slides[counter]["element"].style.display = "inherit"; - slides[counter]["element"].setAttribute("opacity",1); - activeEffect = 0; - } - else - { - slides[counter]["element"].setAttribute("opacity",0); - slides[counter]["element"].style.display = "none"; - } - } - currentMode = SLIDE_MODE; - setSlideToState(activeSlide, STATE_START); - setProgressBarValue(activeSlide); - - if (progress_bar_visible) - { - showProgressBar(); - } - } - - ROOT_NODE.unsuspendRedraw(suspendHandle); - ROOT_NODE.forceRedraw(); -} - -/** Function to run an effect. - * - * @param dir direction in which to play the effect (1 = forwards, -1 = backwards) - */ -function effect(dir) -{ - var done = true; - - var suspendHandle = ROOT_NODE.suspendRedraw(200); - - for (var counter = 0; counter < effectArray.length; counter++) - { - if (effectArray[counter]["effect"] == "fade") - done &= fade(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); - else if (effectArray[counter]["effect"] == "appear") - done &= appear(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); - else if (effectArray[counter]["effect"] == "pop") - done &= pop(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); - else if (effectArray[counter]["effect"] == "view") - done &= view(parseInt(effectArray[counter]["dir"]) * dir, effectArray[counter]["element"], transCounter, effectArray[counter]["options"]); - } - - ROOT_NODE.unsuspendRedraw(suspendHandle); - ROOT_NODE.forceRedraw(); - - if (!done) - { - var currentTime = (new Date()).getTime(); - var timeDiff = 1; - - transCounter = currentTime - startTime; - - if (lastFrameTime != null) - { - timeDiff = timeStep - (currentTime - lastFrameTime); - - if (timeDiff <= 0) - timeDiff = 1; - } - - lastFrameTime = currentTime; - - window.setTimeout("effect(" + dir + ")", timeDiff); - } - else - { - window.location.hash = (activeSlide + 1) + '_' + activeEffect; - processingEffect = false; - } -} - -/** Function to display the index sheet. - * - * @param offsetNumber offset number - */ -function displayIndex(offsetNumber) -{ - var offsetX = 0; - var offsetY = 0; - - if (offsetNumber < 0) - offsetNumber = 0; - else if (offsetNumber >= slides.length) - offsetNumber = slides.length - 1; - - for (var counter = 0; counter < slides.length; counter++) - { - if ((counter < offsetNumber) || (counter > offsetNumber + INDEX_COLUMNS * INDEX_COLUMNS - 1)) - { - slides[counter]["element"].setAttribute("opacity",0); - slides[counter]["element"].style.display = "none"; - } - else - { - offsetX = ((counter - offsetNumber) % INDEX_COLUMNS) * WIDTH; - offsetY = Math.floor((counter - offsetNumber) / INDEX_COLUMNS) * HEIGHT; - - slides[counter]["element"].setAttribute("transform","scale("+1/INDEX_COLUMNS+") translate("+offsetX+","+offsetY+")"); - slides[counter]["element"].style.display = "inherit"; - slides[counter]["element"].setAttribute("opacity",0.5); - } - - setSlideToState(counter, STATE_END); - } - - //do we need to save the current offset? - if (INDEX_OFFSET != offsetNumber) - INDEX_OFFSET = offsetNumber; -} - -/** Function to set the active slide in the slide view. - * - * @param nbr index of the active slide - */ -function slideSetActiveSlide(nbr) -{ - if (nbr >= slides.length) - nbr = slides.length - 1; - else if (nbr < 0) - nbr = 0; - - slides[activeSlide]["element"].setAttribute("opacity",0); - slides[activeSlide]["element"].style.display = "none"; - - activeSlide = parseInt(nbr); - - setSlideToState(activeSlide, STATE_START); - slides[activeSlide]["element"].style.display = "inherit"; - slides[activeSlide]["element"].setAttribute("opacity",1); - - activeEffect = 0; - setProgressBarValue(nbr); -} - -/** Function to set the active slide in the index view. - * - * @param nbr index of the active slide - */ -function indexSetActiveSlide(nbr) -{ - if (nbr >= slides.length) - nbr = slides.length - 1; - else if (nbr < 0) - nbr = 0; - - slides[activeSlide]["element"].setAttribute("opacity",0.5); - - activeSlide = parseInt(nbr); - window.location.hash = (activeSlide + 1) + '_0'; - - slides[activeSlide]["element"].setAttribute("opacity",1); -} - -/** Function to set the page and active slide in index view. - * - * @param nbr index of the active slide - * - * NOTE: To force a redraw, - * set INDEX_OFFSET to -1 before calling indexSetPageSlide(). - * - * This is necessary for zooming (otherwise the index might not - * get redrawn) and when switching to index mode. - * - * INDEX_OFFSET = -1 - * indexSetPageSlide(activeSlide); - */ -function indexSetPageSlide(nbr) -{ - if (nbr >= slides.length) - nbr = slides.length - 1; - else if (nbr < 0) - nbr = 0; - - //calculate the offset - var offset = nbr - nbr % (INDEX_COLUMNS * INDEX_COLUMNS); - - if (offset < 0) - offset = 0; - - //if different from kept offset, then record and change the page - if (offset != INDEX_OFFSET) - { - INDEX_OFFSET = offset; - displayIndex(INDEX_OFFSET); - } - - //set the active slide - indexSetActiveSlide(nbr); -} - -/** Event handler for key press. - * - * @param e the event - */ -function keydown(e) -{ - if (!e) - e = window.event; - - code = e.keyCode || e.charCode; - - if (!processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code]) - return keyCodeDictionary[currentMode][code](); - else - document.onkeypress = keypress; -} -// Set event handler for key down. -document.onkeydown = keydown; - -/** Event handler for key press. - * - * @param e the event - */ -function keypress(e) -{ - document.onkeypress = null; - - if (!e) - e = window.event; - - str = String.fromCharCode(e.keyCode || e.charCode); - - if (!processingEffect && charCodeDictionary[currentMode] && charCodeDictionary[currentMode][str]) - return charCodeDictionary[currentMode][str](); -} - -/** Function to supply the default char code dictionary. - * - * @returns default char code dictionary - */ -function getDefaultCharCodeDictionary() -{ - var charCodeDict = new Object(); - - charCodeDict[SLIDE_MODE] = new Object(); - charCodeDict[INDEX_MODE] = new Object(); - charCodeDict[DRAWING_MODE] = new Object(); - - 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; -} - -/** Function to supply the default key code dictionary. - * - * @returns default key code dictionary - */ -function getDefaultKeyCodeDictionary() -{ - var keyCodeDict = new Object(); - - keyCodeDict[SLIDE_MODE] = new Object(); - keyCodeDict[INDEX_MODE] = new Object(); - keyCodeDict[DRAWING_MODE] = new Object(); - - 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; -} - -/** Function to handle all mouse events. - * - * @param evnt event - * @param action type of event (e.g. mouse up, mouse wheel) - */ -function mouseHandlerDispatch(evnt, action) -{ - if (!evnt) - evnt = window.event; - - var retVal = true; - - if (!processingEffect && mouseHandlerDictionary[currentMode] && mouseHandlerDictionary[currentMode][action]) - { - var subRetVal = mouseHandlerDictionary[currentMode][action](evnt); - - if (subRetVal != null && subRetVal != undefined) - retVal = subRetVal; - } - - if (evnt.preventDefault && !retVal) - evnt.preventDefault(); - - evnt.returnValue = retVal; - - return retVal; -} - -// Set mouse event handler. -document.onmousedown = function(e) { return mouseHandlerDispatch(e, MOUSE_DOWN); }; -document.onmouseup = function(e) { return mouseHandlerDispatch(e, MOUSE_UP); }; -document.onmousemove = function(e) { return mouseHandlerDispatch(e, MOUSE_MOVE); }; - -// Moz -if (window.addEventListener) -{ - window.addEventListener('DOMMouseScroll', function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }, false); -} - -// Opera Safari OK - may not work in IE -window.onmousewheel = function(e) { return mouseHandlerDispatch(e, MOUSE_WHEEL); }; - -/** Function to supply the default mouse handler dictionary. - * - * @returns default mouse handler dictionary - */ -function getDefaultMouseHandlerDictionary() -{ - var mouseHandlerDict = new Object(); - - mouseHandlerDict[SLIDE_MODE] = new Object(); - mouseHandlerDict[INDEX_MODE] = new Object(); - mouseHandlerDict[DRAWING_MODE] = new Object(); - - 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) { return toggleSlideIndex(); }; - - 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; -} - -/** Function to switch from slide mode to drawing mode. -*/ -function slideSwitchToDrawingMode() -{ - currentMode = DRAWING_MODE; - - var tempDict; - - if (ROOT_NODE.hasAttribute("style")) - tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); - else - tempDict = new Object(); - - tempDict["cursor"] = "crosshair"; - ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); -} - -/** Function to switch from drawing mode to slide mode. -*/ -function drawingSwitchToSlideMode() -{ - currentMode = SLIDE_MODE; - - var tempDict; - - if (ROOT_NODE.hasAttribute("style")) - tempDict = propStrToDict(ROOT_NODE.getAttribute("style")); - else - tempDict = new Object(); - - tempDict["cursor"] = "auto"; - ROOT_NODE.setAttribute("style", dictToPropStr(tempDict)); -} - -/** Function to decrease the number of columns in index mode. -*/ -function indexDecreaseNumberOfColumns() -{ - if (INDEX_COLUMNS >= 3) - { - INDEX_COLUMNS -= 1; - INDEX_OFFSET = -1 - indexSetPageSlide(activeSlide); - } -} - -/** Function to increase the number of columns in index mode. -*/ -function indexIncreaseNumberOfColumns() -{ - if (INDEX_COLUMNS < 7) - { - INDEX_COLUMNS += 1; - INDEX_OFFSET = -1 - indexSetPageSlide(activeSlide); - } -} - -/** Function to reset the number of columns in index mode. -*/ -function indexResetNumberOfColumns() -{ - if (INDEX_COLUMNS != INDEX_COLUMNS_DEFAULT) - { - INDEX_COLUMNS = INDEX_COLUMNS_DEFAULT; - INDEX_OFFSET = -1 - indexSetPageSlide(activeSlide); - } -} - -/** Function to reset path width in drawing mode. -*/ -function drawingResetPathWidth() -{ - path_width = path_width_default; - set_path_paint_width(); -} - -/** Function to set path width in drawing mode. - * - * @param width new path width - */ -function drawingSetPathWidth(width) -{ - path_width = width; - set_path_paint_width(); -} - -/** Function to set path colour in drawing mode. - * - * @param colour new path colour - */ -function drawingSetPathColour(colour) -{ - path_colour = colour; -} - -/** Function to query the duration of the presentation from the user in slide mode. -*/ -function slideQueryDuration() -{ - var new_duration = prompt("Length of presentation in minutes?", timer_duration); - - if ((new_duration != null) && (new_duration != '')) - { - timer_duration = new_duration; - } - - updateTimer(); -} - -/** Function to add new slide in slide mode. - * - * @param afterSlide after which slide to insert the new one - */ -function slideAddSlide(afterSlide) -{ - addSlide(afterSlide); - slideSetActiveSlide(afterSlide + 1); - updateTimer(); -} - -/** Function to toggle the visibility of the progress bar in slide mode. -*/ -function slideToggleProgressBarVisibility() -{ - if (progress_bar_visible) - { - progress_bar_visible = false; - hideProgressBar(); - } - else - { - progress_bar_visible = true; - showProgressBar(); - } -} - -/** Function to reset the timer in slide mode. -*/ -function slideResetTimer() -{ - timer_start = timer_elapsed; - updateTimer(); -} - -/** Convenience function to pad a string with zero in front up to a certain length. - */ -function padString(str, len) -{ - var outStr = str; - - while (outStr.length < len) - { - outStr = '0' + outStr; - } - - return outStr; -} - -/** Function to update the export layer. - */ -function slideUpdateExportLayer() -{ - // Suspend redraw since we are going to mess with the slides. - var suspendHandle = ROOT_NODE.suspendRedraw(2000); - - var tmpActiveSlide = activeSlide; - var tmpActiveEffect = activeEffect; - var exportedLayers = new Array(); - - for (var counterSlides = 0; counterSlides < slides.length; counterSlides++) - { - var exportNode; - - setSlideToState(counterSlides, STATE_START); - - var maxEffect = 0; - - if (slides[counterSlides].effects) - { - maxEffect = slides[counterSlides].effects.length; - } - - exportNode = slides[counterSlides].element.cloneNode(true); - exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); - exportNode.setAttributeNS(NSS["inkscape"], "label", "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString("0", maxEffect.toString().length)); - - exportedLayers.push(exportNode); - - if (slides[counterSlides]["effects"]) - { - for (var counter = 0; counter < slides[counterSlides]["effects"].length; counter++) - { - for (var subCounter = 0; subCounter < slides[counterSlides]["effects"][counter].length; subCounter++) - { - var effect = slides[counterSlides]["effects"][counter][subCounter]; - if (effect["effect"] == "fade") - fade(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "appear") - appear(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "pop") - pop(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "view") - view(parseInt(effect["dir"]), effect["element"], STATE_END, effect["options"]); - } - - var layerName = "slide_" + padString((counterSlides + 1).toString(), slides.length.toString().length) + "_effect_" + padString((counter + 1).toString(), maxEffect.toString().length); - exportNode = slides[counterSlides].element.cloneNode(true); - exportNode.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); - exportNode.setAttributeNS(NSS["inkscape"], "label", layerName); - exportNode.setAttribute("id", layerName); - - exportedLayers.push(exportNode); - } - } - } - - activeSlide = tmpActiveSlide; - activeEffect = tmpActiveEffect; - setSlideToState(activeSlide, activeEffect); - - // Copy image. - var newDoc = document.documentElement.cloneNode(true); - - // Delete viewbox form new imag and set width and height. - newDoc.removeAttribute('viewbox'); - newDoc.setAttribute('width', WIDTH); - newDoc.setAttribute('height', HEIGHT); - - // Delete all layers and script elements. - var nodesToBeRemoved = new Array(); - - for (var childCounter = 0; childCounter < newDoc.childNodes.length; childCounter++) - { - var child = newDoc.childNodes[childCounter]; - - if (child.nodeType == 1) - { - if ((child.nodeName.toUpperCase() == 'G') || (child.nodeName.toUpperCase() == 'SCRIPT')) - { - nodesToBeRemoved.push(child); - } - } - } - - for (var ndCounter = 0; ndCounter < nodesToBeRemoved.length; ndCounter++) - { - 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); - } - - // Set current layer. - if (exportedLayers[0]) - { - var namedView; - - for (var nodeCounter = 0; nodeCounter < newDoc.childNodes.length; nodeCounter++) - { - if ((newDoc.childNodes[nodeCounter].nodeType == 1) && (newDoc.childNodes[nodeCounter].getAttribute('id') == 'base')) - { - namedView = newDoc.childNodes[nodeCounter]; - } - } - - if (namedView) - { - namedView.setAttributeNS(NSS['inkscape'], 'current-layer', exportedLayers[0].getAttributeNS(NSS['inkscape'], 'label')); - } - } - - // Add exported layers. - while (exportedLayers.length > 0) - { - var nd = exportedLayers.pop(); - - nd.setAttribute("opacity",1); - nd.style.display = "inherit"; - - newDoc.appendChild(nd); - } - - // Serialise the new document. - window.location = 'data:application/svg+xml;base64;charset=utf-8,' + window.btoa(unescape(encodeURIComponent((new XMLSerializer()).serializeToString(newDoc)))); - - // Unsuspend redraw. - ROOT_NODE.unsuspendRedraw(suspendHandle); - ROOT_NODE.forceRedraw(); -} - -/** Function to undo last drawing operation. -*/ -function drawingUndo() -{ - mouse_presentation_path = null; - mouse_original_path = null; - - if (history_presentation_elements.length > 0) - { - var p = history_presentation_elements.pop(); - var parent = p.parentNode.removeChild(p); - - p = history_original_elements.pop(); - parent = p.parentNode.removeChild(p); - } -} - -/** Event handler for mouse down in drawing mode. - * - * @param e the event - */ -function drawingMousedown(e) -{ - var value = 0; - - if (e.button) - value = e.button; - else if (e.which) - value = e.which; - - if (value == 1) - { - history_counter++; - - var p = calcCoord(e); - - mouse_last_x = e.clientX; - mouse_last_y = e.clientY; - mouse_original_path = document.createElementNS(NSS["svg"], "path"); - mouse_original_path.setAttribute("stroke", path_colour); - mouse_original_path.setAttribute("stroke-width", path_paint_width); - mouse_original_path.setAttribute("fill", "none"); - mouse_original_path.setAttribute("id", "path " + Date()); - mouse_original_path.setAttribute("d", "M" + p.x + "," + p.y); - slides[activeSlide]["original_element"].appendChild(mouse_original_path); - history_original_elements.push(mouse_original_path); - - mouse_presentation_path = document.createElementNS(NSS["svg"], "path"); - mouse_presentation_path.setAttribute("stroke", path_colour); - mouse_presentation_path.setAttribute("stroke-width", path_paint_width); - mouse_presentation_path.setAttribute("fill", "none"); - mouse_presentation_path.setAttribute("id", "path " + Date() + " presentation copy"); - mouse_presentation_path.setAttribute("d", "M" + p.x + "," + p.y); - - if (slides[activeSlide]["viewGroup"]) - slides[activeSlide]["viewGroup"].appendChild(mouse_presentation_path); - else - slides[activeSlide]["element"].appendChild(mouse_presentation_path); - - history_presentation_elements.push(mouse_presentation_path); - - return false; - } - - return true; -} - -/** Event handler for mouse up in drawing mode. - * - * @param e the event - */ -function drawingMouseup(e) -{ - if(!e) - e = window.event; - - if (mouse_presentation_path != null) - { - var p = calcCoord(e); - var d = mouse_presentation_path.getAttribute("d"); - d += " L" + p.x + "," + p.y; - mouse_presentation_path.setAttribute("d", d); - mouse_presentation_path = null; - mouse_original_path.setAttribute("d", d); - mouse_original_path = null; - - return false; - } - - return true; -} - -/** Event handler for mouse move in drawing mode. - * - * @param e the event - */ -function drawingMousemove(e) -{ - if(!e) - e = window.event; - - var dist = (mouse_last_x - e.clientX) * (mouse_last_x - e.clientX) + (mouse_last_y - e.clientY) * (mouse_last_y - e.clientY); - - if (mouse_presentation_path == null) - { - return true; - } - - if (dist >= mouse_min_dist_sqr) - { - var p = calcCoord(e); - var d = mouse_presentation_path.getAttribute("d"); - d += " L" + p.x + "," + p.y; - mouse_presentation_path.setAttribute("d", d); - mouse_original_path.setAttribute("d", d); - mouse_last_x = e.clientX; - mouse_last_y = e.clientY; - } - - return false; -} - -/** Event handler for mouse wheel events in slide mode. - * based on http://adomas.org/javascript-mouse-wheel/ - * - * @param e the event - */ -function slideMousewheel(e) -{ - var delta = 0; - - if (!e) - e = window.event; - - if (e.wheelDelta) - { // IE Opera - delta = e.wheelDelta/120; - } - else if (e.detail) - { // MOZ - delta = -e.detail/3; - } - - if (delta > 0) - skipEffects(-1); - else if (delta < 0) - skipEffects(1); - - if (e.preventDefault) - e.preventDefault(); - - e.returnValue = false; -} - -/** Event handler for mouse wheel events in index mode. - * based on http://adomas.org/javascript-mouse-wheel/ - * - * @param e the event - */ -function indexMousewheel(e) -{ - var delta = 0; - - if (!e) - e = window.event; - - if (e.wheelDelta) - { // IE Opera - delta = e.wheelDelta/120; - } - else if (e.detail) - { // MOZ - delta = -e.detail/3; - } - - if (delta > 0) - indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS); - else if (delta < 0) - indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS); - - if (e.preventDefault) - e.preventDefault(); - - e.returnValue = false; -} - -/** Function to set the path paint width. -*/ -function set_path_paint_width() -{ - var svgPoint1 = document.documentElement.createSVGPoint(); - var svgPoint2 = document.documentElement.createSVGPoint(); - - svgPoint1.x = 0.0; - svgPoint1.y = 0.0; - svgPoint2.x = 1.0; - svgPoint2.y = 0.0; - - var matrix = slides[activeSlide]["element"].getTransformToElement(ROOT_NODE); - - if (slides[activeSlide]["viewGroup"]) - matrix = slides[activeSlide]["viewGroup"].getTransformToElement(ROOT_NODE); - - svgPoint1 = svgPoint1.matrixTransform(matrix); - svgPoint2 = svgPoint2.matrixTransform(matrix); - - path_paint_width = path_width / Math.sqrt((svgPoint2.x - svgPoint1.x) * (svgPoint2.x - svgPoint1.x) + (svgPoint2.y - svgPoint1.y) * (svgPoint2.y - svgPoint1.y)); -} - -/** The view effect. - * - * @param dir direction the effect should be played (1 = forwards, -1 = backwards) - * @param element the element the effect should be applied to - * @param time the time that has elapsed since the beginning of the effect - * @param options a dictionary with additional options (e.g. length of the effect); for the view effect the options need to contain the old and the new matrix. - */ -function view(dir, element, time, options) -{ - var length = 250; - var fraction; - - if (!options["matrixInitial"]) - { - var tempString = slides[activeSlide]["viewGroup"].getAttribute("transform"); - - if (tempString) - options["matrixInitial"] = (new matrixSVG()).fromAttribute(tempString); - else - options["matrixInitial"] = (new matrixSVG()).fromSVGElements(1, 0, 0, 1, 0, 0); - } - - if ((time == STATE_END) || (time == STATE_START)) - fraction = 1; - else - { - if (options && options["length"]) - length = options["length"]; - - fraction = time / length; - } - - if (dir == 1) - { - if (fraction <= 0) - { - element.setAttribute("transform", options["matrixInitial"].toAttribute()); - } - else if (fraction >= 1) - { - element.setAttribute("transform", options["matrixNew"].toAttribute()); - - set_path_paint_width(); - - options["matrixInitial"] = null; - return true; - } - else - { - element.setAttribute("transform", options["matrixInitial"].mix(options["matrixNew"], fraction).toAttribute()); - } - } - else if (dir == -1) - { - if (fraction <= 0) - { - element.setAttribute("transform", options["matrixInitial"].toAttribute()); - } - else if (fraction >= 1) - { - element.setAttribute("transform", options["matrixOld"].toAttribute()); - set_path_paint_width(); - - options["matrixInitial"] = null; - return true; - } - else - { - element.setAttribute("transform", options["matrixInitial"].mix(options["matrixOld"], fraction).toAttribute()); - } - } - - return false; -} - -/** The fade effect. - * - * @param dir direction the effect should be played (1 = forwards, -1 = backwards) - * @param element the element the effect should be applied to - * @param time the time that has elapsed since the beginning of the effect - * @param options a dictionary with additional options (e.g. length of the effect) - */ -function fade(dir, element, time, options) -{ - var length = 250; - var fraction; - - if ((time == STATE_END) || (time == STATE_START)) - fraction = 1; - else - { - if (options && options["length"]) - length = options["length"]; - - fraction = time / length; - } - - if (dir == 1) - { - if (fraction <= 0) - { - element.style.display = "none"; - element.setAttribute("opacity", 0); - } - else if (fraction >= 1) - { - element.style.display = "inherit"; - element.setAttribute("opacity", 1); - return true; - } - else - { - element.style.display = "inherit"; - element.setAttribute("opacity", fraction); - } - } - else if (dir == -1) - { - if (fraction <= 0) - { - element.style.display = "inherit"; - element.setAttribute("opacity", 1); - } - else if (fraction >= 1) - { - element.setAttribute("opacity", 0); - element.style.display = "none"; - return true; - } - else - { - element.style.display = "inherit"; - element.setAttribute("opacity", 1 - fraction); - } - } - return false; -} - -/** The appear effect. - * - * @param dir direction the effect should be played (1 = forwards, -1 = backwards) - * @param element the element the effect should be applied to - * @param time the time that has elapsed since the beginning of the effect - * @param options a dictionary with additional options (e.g. length of the effect) - */ -function appear(dir, element, time, options) -{ - if (dir == 1) - { - element.style.display = "inherit"; - element.setAttribute("opacity",1); - } - else if (dir == -1) - { - element.style.display = "none"; - element.setAttribute("opacity",0); - } - return true; -} - -/** The pop effect. - * - * @param dir direction the effect should be played (1 = forwards, -1 = backwards) - * @param element the element the effect should be applied to - * @param time the time that has elapsed since the beginning of the effect - * @param options a dictionary with additional options (e.g. length of the effect) - */ -function pop(dir, element, time, options) -{ - var length = 500; - var fraction; - - if ((time == STATE_END) || (time == STATE_START)) - fraction = 1; - else - { - if (options && options["length"]) - length = options["length"]; - - fraction = time / length; - } - - if (dir == 1) - { - if (fraction <= 0) - { - element.setAttribute("opacity", 0); - element.setAttribute("transform", "scale(0)"); - element.style.display = "none"; - } - else if (fraction >= 1) - { - element.setAttribute("opacity", 1); - element.removeAttribute("transform"); - element.style.display = "inherit"; - return true; - } - else - { - element.style.display = "inherit"; - var opacityFraction = fraction * 3; - if (opacityFraction > 1) - opacityFraction = 1; - element.setAttribute("opacity", opacityFraction); - var offsetX = WIDTH * (1.0 - fraction) / 2.0; - var offsetY = HEIGHT * (1.0 - fraction) / 2.0; - element.setAttribute("transform", "translate(" + offsetX + "," + offsetY + ") scale(" + fraction + ")"); - } - } - else if (dir == -1) - { - if (fraction <= 0) - { - element.setAttribute("opacity", 1); - element.setAttribute("transform", "scale(1)"); - element.style.display = "inherit"; - } - else if (fraction >= 1) - { - element.setAttribute("opacity", 0); - element.removeAttribute("transform"); - element.style.display = "none"; - return true; - } - else - { - element.setAttribute("opacity", 1 - fraction); - element.setAttribute("transform", "scale(" + 1 - fraction + ")"); - element.style.display = "inherit"; - } - } - return false; -} - -/** Function to set a slide either to the start or the end state. - * - * @param slide the slide to use - * @param state the state into which the slide should be set - */ -function setSlideToState(slide, state) -{ - slides[slide]["viewGroup"].setAttribute("transform", slides[slide].initialView); - - if (slides[slide]["effects"]) - { - if (state == STATE_END) - { - for (var counter = 0; counter < slides[slide]["effects"].length; counter++) - { - for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) - { - var effect = slides[slide]["effects"][counter][subCounter]; - if (effect["effect"] == "fade") - fade(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "appear") - appear(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "pop") - pop(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "view") - view(effect["dir"], effect["element"], STATE_END, effect["options"]); - } - } - } - else if (state == STATE_START) - { - for (var counter = slides[slide]["effects"].length - 1; counter >= 0; counter--) - { - for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) - { - var effect = slides[slide]["effects"][counter][subCounter]; - if (effect["effect"] == "fade") - fade(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); - else if (effect["effect"] == "appear") - appear(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); - else if (effect["effect"] == "pop") - pop(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); - else if (effect["effect"] == "view") - view(parseInt(effect["dir"]) * -1, effect["element"], STATE_START, effect["options"]); - } - } - } - else - { - setSlideToState(slide, STATE_START); - - for (var counter = 0; counter < slides[slide]["effects"].length && counter < state; counter++) - { - for (var subCounter = 0; subCounter < slides[slide]["effects"][counter].length; subCounter++) - { - var effect = slides[slide]["effects"][counter][subCounter]; - if (effect["effect"] == "fade") - fade(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "appear") - appear(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "pop") - pop(effect["dir"], effect["element"], STATE_END, effect["options"]); - else if (effect["effect"] == "view") - view(effect["dir"], effect["element"], STATE_END, effect["options"]); - } - } - } - } - - window.location.hash = (activeSlide + 1) + '_' + activeEffect; -} - -/** Convenience function to translate a attribute string into a dictionary. - * - * @param str the attribute string - * @return a dictionary - * @see dictToPropStr - */ -function propStrToDict(str) -{ - var list = str.split(";"); - var obj = new Object(); - - for (var counter = 0; counter < list.length; counter++) - { - var subStr = list[counter]; - var subList = subStr.split(":"); - if (subList.length == 2) - { - obj[subList[0]] = subList[1]; - } - } - - return obj; -} - -/** Convenience function to translate a dictionary into a string that can be used as an attribute. - * - * @param dict the dictionary to convert - * @return a string that can be used as an attribute - * @see propStrToDict - */ -function dictToPropStr(dict) -{ - var str = ""; - - for (var key in dict) - { - str += key + ":" + dict[key] + ";"; - } - - return str; -} - -/** Sub-function to add a suffix to the ids of the node and all its children. - * - * @param node the node to change - * @param suffix the suffix to add - * @param replace dictionary of replaced ids - * @see suffixNodeIds - */ -function suffixNoneIds_sub(node, suffix, replace) -{ - if (node.nodeType == 1) - { - if (node.getAttribute("id")) - { - var id = node.getAttribute("id") - replace["#" + id] = id + suffix; - node.setAttribute("id", id + suffix); - } - - if ((node.nodeName == "use") && (node.getAttributeNS(NSS["xlink"], "href")) && (replace[node.getAttribute(NSS["xlink"], "href")])) - node.setAttribute(NSS["xlink"], "href", node.getAttribute(NSS["xlink"], "href") + suffix); - - if (node.childNodes) - { - for (var counter = 0; counter < node.childNodes.length; counter++) - suffixNoneIds_sub(node.childNodes[counter], suffix, replace); - } - } -} - -/** Function to add a suffix to the ids of the node and all its children. - * - * @param node the node to change - * @param suffix the suffix to add - * @return the changed node - * @see suffixNodeIds_sub - */ -function suffixNodeIds(node, suffix) -{ - var replace = new Object(); - - suffixNoneIds_sub(node, suffix, replace); - - return node; -} - -/** Function to build a progress bar. - * - * @param parent node to attach the progress bar to - */ -function createProgressBar(parent_node) -{ - var g = document.createElementNS(NSS["svg"], "g"); - g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); - g.setAttribute("id", "layer_progress_bar"); - g.setAttribute("style", "display: none;"); - - var rect_progress_bar = document.createElementNS(NSS["svg"], "rect"); - rect_progress_bar.setAttribute("style", "marker: none; fill: rgb(128, 128, 128); stroke: none;"); - rect_progress_bar.setAttribute("id", "rect_progress_bar"); - rect_progress_bar.setAttribute("x", 0); - rect_progress_bar.setAttribute("y", 0.99 * HEIGHT); - rect_progress_bar.setAttribute("width", 0); - rect_progress_bar.setAttribute("height", 0.01 * HEIGHT); - g.appendChild(rect_progress_bar); - - var circle_timer_indicator = document.createElementNS(NSS["svg"], "circle"); - circle_timer_indicator.setAttribute("style", "marker: none; fill: rgb(255, 0, 0); stroke: none;"); - circle_timer_indicator.setAttribute("id", "circle_timer_indicator"); - circle_timer_indicator.setAttribute("cx", 0.005 * HEIGHT); - circle_timer_indicator.setAttribute("cy", 0.995 * HEIGHT); - circle_timer_indicator.setAttribute("r", 0.005 * HEIGHT); - g.appendChild(circle_timer_indicator); - - parent_node.appendChild(g); -} - -/** Function to hide the progress bar. - * - */ -function hideProgressBar() -{ - var progress_bar = document.getElementById("layer_progress_bar"); - - if (!progress_bar) - { - return; - } - - progress_bar.setAttribute("style", "display: none;"); -} - -/** Function to show the progress bar. - * - */ -function showProgressBar() -{ - var progress_bar = document.getElementById("layer_progress_bar"); - - if (!progress_bar) - { - return; - } - - progress_bar.setAttribute("style", "display: inherit;"); -} - -/** Set progress bar value. - * - * @param value the current slide number - * - */ -function setProgressBarValue(value) -{ - var rect_progress_bar = document.getElementById("rect_progress_bar"); - - if (!rect_progress_bar) - { - return; - } - - if (value < 1) - { - // First slide, assumed to be the title of the presentation - var x = 0; - var w = 0.01 * HEIGHT; - } - else if (value >= slides.length - 1) - { - // Last slide, assumed to be the end of the presentation - var x = WIDTH - 0.01 * HEIGHT; - var w = 0.01 * HEIGHT; - } - else - { - value -= 1; - value /= (slides.length - 2); - - var x = WIDTH * value; - var w = WIDTH / (slides.length - 2); - } - - rect_progress_bar.setAttribute("x", x); - rect_progress_bar.setAttribute("width", w); -} - -/** Set time indicator. - * - * @param value the percentage of time elapse so far between 0.0 and 1.0 - * - */ -function setTimeIndicatorValue(value) -{ - var circle_timer_indicator = document.getElementById("circle_timer_indicator"); - - if (!circle_timer_indicator) - { - return; - } - - if (value < 0.0) - { - value = 0.0; - } - - if (value > 1.0) - { - value = 1.0; - } - - var cx = (WIDTH - 0.01 * HEIGHT) * value + 0.005 * HEIGHT; - circle_timer_indicator.setAttribute("cx", cx); -} - -/** Update timer. - * - */ -function updateTimer() -{ - timer_elapsed += 1; - setTimeIndicatorValue((timer_elapsed - timer_start) / (60 * timer_duration)); -} - -/** Convert screen coordinates to document coordinates. - * - * @param e event with screen coordinates - * - * @return coordinates in SVG file coordinate system - */ -function calcCoord(e) -{ - var svgPoint = document.documentElement.createSVGPoint(); - svgPoint.x = e.clientX + window.pageXOffset; - svgPoint.y = e.clientY + window.pageYOffset; - - var matrix = slides[activeSlide]["element"].getScreenCTM(); - - if (slides[activeSlide]["viewGroup"]) - matrix = slides[activeSlide]["viewGroup"].getScreenCTM(); - - svgPoint = svgPoint.matrixTransform(matrix.inverse()); - return svgPoint; -} - -/** Add slide. - * - * @param after_slide after which slide the new slide should be inserted into the presentation - */ -function addSlide(after_slide) -{ - number_of_added_slides++; - - var g = document.createElementNS(NSS["svg"], "g"); - g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); - g.setAttribute("id", "Whiteboard " + Date() + " presentation copy"); - g.setAttribute("style", "display: none;"); - - var new_slide = new Object(); - new_slide["element"] = g; - - // Set build in transition. - new_slide["transitionIn"] = new Object(); - var dict = defaultTransitionInDict; - new_slide["transitionIn"]["name"] = dict["name"]; - new_slide["transitionIn"]["options"] = new Object(); - - for (key in dict) - if (key != "name") - new_slide["transitionIn"]["options"][key] = dict[key]; - - // Set build out transition. - new_slide["transitionOut"] = new Object(); - dict = defaultTransitionOutDict; - new_slide["transitionOut"]["name"] = dict["name"]; - new_slide["transitionOut"]["options"] = new Object(); - - for (key in dict) - if (key != "name") - new_slide["transitionOut"]["options"][key] = dict[key]; - - // Copy master slide content. - if (masterSlide) - { - var clonedNode = suffixNodeIds(masterSlide.cloneNode(true), "_" + Date() + " presentation_copy"); - clonedNode.removeAttributeNS(NSS["inkscape"], "groupmode"); - clonedNode.removeAttributeNS(NSS["inkscape"], "label"); - clonedNode.style.display = "inherit"; - - g.appendChild(clonedNode); - } - - // Substitute auto texts. - substituteAutoTexts(g, "Whiteboard " + number_of_added_slides, "W" + number_of_added_slides, slides.length); - - g.setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + (after_slide + 1) + ")) { indexSetActiveSlide(" + (after_slide + 1) + "); };"); - - // Create a transform group. - var transformGroup = document.createElementNS(NSS["svg"], "g"); - - // Add content to transform group. - while (g.firstChild) - transformGroup.appendChild(g.firstChild); - - // Transfer the transform attribute from the node to the transform group. - if (g.getAttribute("transform")) - { - transformGroup.setAttribute("transform", g.getAttribute("transform")); - g.removeAttribute("transform"); - } - - // Create a view group. - var viewGroup = document.createElementNS(NSS["svg"], "g"); - - viewGroup.appendChild(transformGroup); - new_slide["viewGroup"] = g.appendChild(viewGroup); - - // Insert background. - if (BACKGROUND_COLOR != null) - { - var rectNode = document.createElementNS(NSS["svg"], "rect"); - - rectNode.setAttribute("x", 0); - rectNode.setAttribute("y", 0); - rectNode.setAttribute("width", WIDTH); - rectNode.setAttribute("height", HEIGHT); - rectNode.setAttribute("id", "jessyInkBackground" + Date()); - rectNode.setAttribute("fill", BACKGROUND_COLOR); - - new_slide["viewGroup"].insertBefore(rectNode, new_slide["viewGroup"].firstChild); - } - - // Set initial view even if there are no other views. - var matrixOld = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - - new_slide["viewGroup"].setAttribute("transform", matrixOld.toAttribute()); - new_slide.initialView = matrixOld.toAttribute(); - - // Insert slide - var node = slides[after_slide]["element"]; - var next_node = node.nextSibling; - var parent_node = node.parentNode; - - if (next_node) - { - parent_node.insertBefore(g, next_node); - } - else - { - parent_node.appendChild(g); - } - - g = document.createElementNS(NSS["svg"], "g"); - g.setAttributeNS(NSS["inkscape"], "groupmode", "layer"); - g.setAttributeNS(NSS["inkscape"], "label", "Whiteboard " + number_of_added_slides); - g.setAttribute("clip-path", "url(#jessyInkSlideClipPath)"); - g.setAttribute("id", "Whiteboard " + Date()); - g.setAttribute("style", "display: none;"); - - new_slide["original_element"] = g; - - node = slides[after_slide]["original_element"]; - next_node = node.nextSibling; - parent_node = node.parentNode; - - if (next_node) - { - parent_node.insertBefore(g, next_node); - } - else - { - parent_node.appendChild(g); - } - - before_new_slide = slides.slice(0, after_slide + 1); - after_new_slide = slides.slice(after_slide + 1); - slides = before_new_slide.concat(new_slide, after_new_slide); - - //resetting the counter attributes on the slides that follow the new slide... - for (var counter = after_slide+2; counter < slides.length; counter++) - { - slides[counter]["element"].setAttribute("onmouseover", "if ((currentMode == INDEX_MODE) && ( activeSlide != " + counter + ")) { indexSetActiveSlide(" + counter + "); };"); - } -} - -/** Convenience function to obtain a transformation matrix from a point matrix. - * - * @param mPoints Point matrix. - * @return A transformation matrix. - */ -function pointMatrixToTransformation(mPoints) -{ - mPointsOld = (new matrixSVG()).fromElements(0, WIDTH, WIDTH, 0, 0, HEIGHT, 1, 1, 1); - - return mPointsOld.mult(mPoints.inv()); -} - -/** Convenience function to obtain a matrix with three corners of a rectangle. - * - * @param rect an svg rectangle - * @return a matrixSVG containing three corners of the rectangle - */ -function rectToMatrix(rect) -{ - rectWidth = rect.getBBox().width; - rectHeight = rect.getBBox().height; - rectX = rect.getBBox().x; - rectY = rect.getBBox().y; - rectXcorr = 0; - rectYcorr = 0; - - scaleX = WIDTH / rectWidth; - scaleY = HEIGHT / rectHeight; - - if (scaleX > scaleY) - { - scaleX = scaleY; - rectXcorr -= (WIDTH / scaleX - rectWidth) / 2; - rectWidth = WIDTH / scaleX; - } - else - { - scaleY = scaleX; - rectYcorr -= (HEIGHT / scaleY - rectHeight) / 2; - rectHeight = HEIGHT / scaleY; - } - - if (rect.transform.baseVal.numberOfItems < 1) - { - mRectTrans = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - } - else - { - mRectTrans = (new matrixSVG()).fromSVGMatrix(rect.transform.baseVal.consolidate().matrix); - } - - newBasePoints = (new matrixSVG()).fromElements(rectX, rectX, rectX, rectY, rectY, rectY, 1, 1, 1); - newVectors = (new matrixSVG()).fromElements(rectXcorr, rectXcorr + rectWidth, rectXcorr + rectWidth, rectYcorr, rectYcorr, rectYcorr + rectHeight, 0, 0, 0); - - return mRectTrans.mult(newBasePoints.add(newVectors)); -} - -/** Function to handle JessyInk elements. - * - * @param node Element node. - */ -function handleElement(node) -{ - if (node.getAttributeNS(NSS['jessyink'], 'element') == 'core.video') - { - var url; - var width; - var height; - var x; - var y; - var transform; - - var tspans = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "tspan"); - - for (var tspanCounter = 0; tspanCounter < tspans.length; tspanCounter++) - { - if (tspans[tspanCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "url") - { - url = tspans[tspanCounter].firstChild.nodeValue; - } - } - - var rects = node.getElementsByTagNameNS("http://www.w3.org/2000/svg", "rect"); - - for (var rectCounter = 0; rectCounter < rects.length; rectCounter++) - { - if (rects[rectCounter].getAttributeNS("https://launchpad.net/jessyink", "video") == "rect") - { - x = rects[rectCounter].getAttribute("x"); - y = rects[rectCounter].getAttribute("y"); - width = rects[rectCounter].getAttribute("width"); - height = rects[rectCounter].getAttribute("height"); - transform = rects[rectCounter].getAttribute("transform"); - } - } - - for (var childCounter = 0; childCounter < node.childNodes.length; childCounter++) - { - if (node.childNodes[childCounter].nodeType == 1) - { - if (node.childNodes[childCounter].style) - { - node.childNodes[childCounter].style.display = 'none'; - } - else - { - node.childNodes[childCounter].setAttribute("style", "display: none;"); - } - } - } - - var foreignNode = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject"); - foreignNode.setAttribute("x", x); - foreignNode.setAttribute("y", y); - foreignNode.setAttribute("width", width); - foreignNode.setAttribute("height", height); - foreignNode.setAttribute("transform", transform); - - var videoNode = document.createElementNS("http://www.w3.org/1999/xhtml", "video"); - videoNode.setAttribute("src", url); - - foreignNode.appendChild(videoNode); - node.appendChild(foreignNode); - } -} - -/** Class processing the location hash. - * - * @param str location hash - */ -function LocationHash(str) -{ - this.slideNumber = 0; - this.effectNumber = 0; - - str = str.substr(1, str.length - 1); - - var parts = str.split('_'); - - // Try to extract slide number. - if (parts.length >= 1) - { - try - { - var slideNumber = parseInt(parts[0]); - - if (!isNaN(slideNumber)) - { - this.slideNumber = slideNumber - 1; - } - } - catch (e) - { - } - } - - // Try to extract effect number. - if (parts.length >= 2) - { - try - { - var effectNumber = parseInt(parts[1]); - - if (!isNaN(effectNumber)) - { - this.effectNumber = effectNumber; - } - } - catch (e) - { - } - } -} - -/** Class representing an svg matrix. -*/ -function matrixSVG() -{ - this.e11 = 0; // a - this.e12 = 0; // c - this.e13 = 0; // e - this.e21 = 0; // b - this.e22 = 0; // d - this.e23 = 0; // f - this.e31 = 0; - this.e32 = 0; - this.e33 = 0; -} - -/** Constructor function. - * - * @param a element a (i.e. 1, 1) as described in the svg standard. - * @param b element b (i.e. 2, 1) as described in the svg standard. - * @param c element c (i.e. 1, 2) as described in the svg standard. - * @param d element d (i.e. 2, 2) as described in the svg standard. - * @param e element e (i.e. 1, 3) as described in the svg standard. - * @param f element f (i.e. 2, 3) as described in the svg standard. - */ -matrixSVG.prototype.fromSVGElements = function(a, b, c, d, e, f) -{ - this.e11 = a; - this.e12 = c; - this.e13 = e; - this.e21 = b; - this.e22 = d; - this.e23 = f; - this.e31 = 0; - this.e32 = 0; - this.e33 = 1; - - return this; -} - -/** Constructor function. - * - * @param matrix an svg matrix as described in the svg standard. - */ -matrixSVG.prototype.fromSVGMatrix = function(m) -{ - this.e11 = m.a; - this.e12 = m.c; - this.e13 = m.e; - this.e21 = m.b; - this.e22 = m.d; - this.e23 = m.f; - this.e31 = 0; - this.e32 = 0; - this.e33 = 1; - - return this; -} - -/** Constructor function. - * - * @param e11 element 1, 1 of the matrix. - * @param e12 element 1, 2 of the matrix. - * @param e13 element 1, 3 of the matrix. - * @param e21 element 2, 1 of the matrix. - * @param e22 element 2, 2 of the matrix. - * @param e23 element 2, 3 of the matrix. - * @param e31 element 3, 1 of the matrix. - * @param e32 element 3, 2 of the matrix. - * @param e33 element 3, 3 of the matrix. - */ -matrixSVG.prototype.fromElements = function(e11, e12, e13, e21, e22, e23, e31, e32, e33) -{ - this.e11 = e11; - this.e12 = e12; - this.e13 = e13; - this.e21 = e21; - this.e22 = e22; - this.e23 = e23; - this.e31 = e31; - this.e32 = e32; - this.e33 = e33; - - return this; -} - -/** Constructor function. - * - * @param attrString string value of the "transform" attribute (currently only "matrix" is accepted) - */ -matrixSVG.prototype.fromAttribute = function(attrString) -{ - str = attrString.substr(7, attrString.length - 8); - - str = str.trim(); - - strArray = str.split(","); - - // Opera does not use commas to separate the values of the matrix, only spaces. - if (strArray.length != 6) - strArray = str.split(" "); - - this.e11 = parseFloat(strArray[0]); - this.e21 = parseFloat(strArray[1]); - this.e31 = 0; - this.e12 = parseFloat(strArray[2]); - this.e22 = parseFloat(strArray[3]); - this.e32 = 0; - this.e13 = parseFloat(strArray[4]); - this.e23 = parseFloat(strArray[5]); - this.e33 = 1; - - return this; -} - -/** Output function - * - * @return a string that can be used as the "transform" attribute. - */ -matrixSVG.prototype.toAttribute = function() -{ - return "matrix(" + this.e11 + ", " + this.e21 + ", " + this.e12 + ", " + this.e22 + ", " + this.e13 + ", " + this.e23 + ")"; -} - -/** Matrix nversion. - * - * @return the inverse of the matrix - */ -matrixSVG.prototype.inv = function() -{ - out = new matrixSVG(); - - det = this.e11 * (this.e33 * this.e22 - this.e32 * this.e23) - this.e21 * (this.e33 * this.e12 - this.e32 * this.e13) + this.e31 * (this.e23 * this.e12 - this.e22 * this.e13); - - out.e11 = (this.e33 * this.e22 - this.e32 * this.e23) / det; - out.e12 = -(this.e33 * this.e12 - this.e32 * this.e13) / det; - out.e13 = (this.e23 * this.e12 - this.e22 * this.e13) / det; - out.e21 = -(this.e33 * this.e21 - this.e31 * this.e23) / det; - out.e22 = (this.e33 * this.e11 - this.e31 * this.e13) / det; - out.e23 = -(this.e23 * this.e11 - this.e21 * this.e13) / det; - out.e31 = (this.e32 * this.e21 - this.e31 * this.e22) / det; - out.e32 = -(this.e32 * this.e11 - this.e31 * this.e12) / det; - out.e33 = (this.e22 * this.e11 - this.e21 * this.e12) / det; - - return out; -} - -/** Matrix multiplication. - * - * @param op another svg matrix - * @return this * op - */ -matrixSVG.prototype.mult = function(op) -{ - out = new matrixSVG(); - - out.e11 = this.e11 * op.e11 + this.e12 * op.e21 + this.e13 * op.e31; - out.e12 = this.e11 * op.e12 + this.e12 * op.e22 + this.e13 * op.e32; - out.e13 = this.e11 * op.e13 + this.e12 * op.e23 + this.e13 * op.e33; - out.e21 = this.e21 * op.e11 + this.e22 * op.e21 + this.e23 * op.e31; - out.e22 = this.e21 * op.e12 + this.e22 * op.e22 + this.e23 * op.e32; - out.e23 = this.e21 * op.e13 + this.e22 * op.e23 + this.e23 * op.e33; - out.e31 = this.e31 * op.e11 + this.e32 * op.e21 + this.e33 * op.e31; - out.e32 = this.e31 * op.e12 + this.e32 * op.e22 + this.e33 * op.e32; - out.e33 = this.e31 * op.e13 + this.e32 * op.e23 + this.e33 * op.e33; - - return out; -} - -/** Matrix addition. - * - * @param op another svg matrix - * @return this + op - */ -matrixSVG.prototype.add = function(op) -{ - out = new matrixSVG(); - - out.e11 = this.e11 + op.e11; - out.e12 = this.e12 + op.e12; - out.e13 = this.e13 + op.e13; - out.e21 = this.e21 + op.e21; - out.e22 = this.e22 + op.e22; - out.e23 = this.e23 + op.e23; - out.e31 = this.e31 + op.e31; - out.e32 = this.e32 + op.e32; - out.e33 = this.e33 + op.e33; - - return out; -} - -/** Matrix mixing. - * - * @param op another svg matrix - * @parma contribOp contribution of the other matrix (0 <= contribOp <= 1) - * @return (1 - contribOp) * this + contribOp * op - */ -matrixSVG.prototype.mix = function(op, contribOp) -{ - contribThis = 1.0 - contribOp; - out = new matrixSVG(); - - out.e11 = contribThis * this.e11 + contribOp * op.e11; - out.e12 = contribThis * this.e12 + contribOp * op.e12; - out.e13 = contribThis * this.e13 + contribOp * op.e13; - out.e21 = contribThis * this.e21 + contribOp * op.e21; - out.e22 = contribThis * this.e22 + contribOp * op.e22; - out.e23 = contribThis * this.e23 + contribOp * op.e23; - out.e31 = contribThis * this.e31 + contribOp * op.e31; - out.e32 = contribThis * this.e32 + contribOp * op.e32; - out.e33 = contribThis * this.e33 + contribOp * op.e33; - - return out; -} - -/** Trimming function for strings. -*/ -String.prototype.trim = function() -{ - return this.replace(/^\s+|\s+$/g, ''); -} - -/** SVGElement.getTransformToElement polyfill */ -SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) { - return elem.getScreenCTM().inverse().multiply(this.getScreenCTM()); -}; diff --git a/share/extensions/jessyInk_autoTexts.inx b/share/extensions/jessyInk_autoTexts.inx deleted file mode 100644 index 93e19b301..000000000 --- a/share/extensions/jessyInk_autoTexts.inx +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Auto-texts</_name> - <id>jessyink.autotexts</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_autoTexts.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <param name="autoText" type="optiongroup" _gui-text="Auto-Text:"> - <_option value="none">None (remove)</_option> - <_option value="slideTitle">Slide title</_option> - <_option value="slideNumber">Slide number</_option> - <_option value="numberOfSlides">Number of slides</_option> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to install, update and remove auto-texts for a JessyInk presentation. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_autoTexts.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_autoTexts.py b/share/extensions/jessyInk_autoTexts.py deleted file mode 100755 index 2c52964da..000000000 --- a/share/extensions/jessyInk_autoTexts.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - -class JessyInk_AutoTexts(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--autoText', action = 'store', type = 'string', dest = 'autoText', default = 'none') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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: - 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: - 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") - elif self.options.autoText == "slideNumber": - nodes[0].set("{" + inkex.NSS["jessyink"] + "}autoText","slideNumber") - elif self.options.autoText == "numberOfSlides": - nodes[0].set("{" + inkex.NSS["jessyink"] + "}autoText","numberOfSlides") - else: - if nodes[0].attrib.has_key("{" + inkex.NSS["jessyink"] + "}autoText"): - del nodes[0].attrib["{" + inkex.NSS["jessyink"] + "}autoText"] - -# Create effect instance -effect = JessyInk_AutoTexts() -effect.affect() - diff --git a/share/extensions/jessyInk_core_mouseHandler_noclick.js b/share/extensions/jessyInk_core_mouseHandler_noclick.js deleted file mode 100644 index 88579754a..000000000 --- a/share/extensions/jessyInk_core_mouseHandler_noclick.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2008, 2009 Hannes Hochreiner -// 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 3 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, see http://www.gnu.org/licenses/. - -// Add event listener for initialisation. -document.addEventListener("DOMContentLoaded", jessyInk_core_mouseHandler_noclick_init, false); - -/** Initialisation function. - * - * This function looks for the objects of the appropriate sub-type and hands them to another function that will add the required methods. - */ -function jessyInk_core_mouseHandler_noclick_init() -{ - var elems = document.getElementsByTagNameNS("https://launchpad.net/jessyink", "mousehandler"); - - for (var counter = 0; counter < elems.length; counter++) - { - if (elems[counter].getAttributeNS("https://launchpad.net/jessyink", "subtype") == "jessyInk_core_mouseHandler_noclick") - jessyInk_core_mouseHandler_noclick(elems[counter]); - } -} - -/** Function to initialise an object. - * - * @param obj Object to be initialised. - */ -function jessyInk_core_mouseHandler_noclick(obj) -{ - /** Function supplying a custom mouse handler. - * - * @returns A dictionary containing the new mouse handler functions. - */ - obj.getMouseHandler = function () - { - var handlerDictio = new Object(); - - handlerDictio[SLIDE_MODE] = new Object(); - handlerDictio[SLIDE_MODE][MOUSE_DOWN] = null; - - return handlerDictio; - } -} - diff --git a/share/extensions/jessyInk_core_mouseHandler_zoomControl.js b/share/extensions/jessyInk_core_mouseHandler_zoomControl.js deleted file mode 100644 index fba33d34f..000000000 --- a/share/extensions/jessyInk_core_mouseHandler_zoomControl.js +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2008, 2009 Hannes Hochreiner -// 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 3 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, see http://www.gnu.org/licenses/. - -// Add event listener for initialisation. -document.addEventListener("DOMContentLoaded", jessyInk_core_mouseHandler_zoomControl_init, false); - -/** Initialisation function. - * - * This function looks for the objects of the appropriate sub-type and hands them to another function that will add the required methods. - */ -function jessyInk_core_mouseHandler_zoomControl_init() -{ - var elems = document.getElementsByTagNameNS("https://launchpad.net/jessyink", "mousehandler"); - - for (var counter = 0; counter < elems.length; counter++) - { - if (elems[counter].getAttributeNS("https://launchpad.net/jessyink", "subtype") == "jessyInk_core_mouseHandler_zoomControl") - jessyInk_core_mouseHandler_zoomControl(elems[counter]); - } -} - -/** Function to initialise an object. - * - * @param obj Object to be initialised. - */ -function jessyInk_core_mouseHandler_zoomControl(obj) -{ - // Last dragging position. - obj.dragging_last; - // Flag to indicate whether dragging is active currently. - obj.dragging_active = false; - // Flag to indicate whether dragging is working currently. - obj.dragging_working = false; - // Flag to indicate whether the user clicked. - obj.click = false; - - /** Function supplying a custom mouse handler. - * - * @returns A dictionary containing the new mouse handler functions. - */ - obj.getMouseHandler = function () - { - var handlerDictio = new Object(); - - handlerDictio[SLIDE_MODE] = new Object(); - handlerDictio[SLIDE_MODE][MOUSE_DOWN] = obj.mousedown; - handlerDictio[SLIDE_MODE][MOUSE_MOVE] = obj.mousemove; - handlerDictio[SLIDE_MODE][MOUSE_UP] = obj.mouseup; - handlerDictio[SLIDE_MODE][MOUSE_WHEEL] = obj.mousewheel; - - return handlerDictio; - } - - /** Event handler for mouse clicks. - * - * @param e Event object. - */ - obj.mouseclick = function (e) - { - var elem = obj.getAdHocViewBbox(slides[activeSlide]["viewGroup"], obj.getCoords(e)); - - processingEffect = true; - - effectArray = new Array(); - - effectArray[0] = new Object(); - effectArray[0]["effect"] = "view"; - effectArray[0]["dir"] = 1; - effectArray[0]["element"] = slides[activeSlide]["viewGroup"]; - effectArray[0]["options"] = new Object(); - effectArray[0]["options"]["length"] = 200; - - if (elem == null) - effectArray[0]["options"]["matrixNew"] = (new matrixSVG()).fromSVGElements(1, 0, 0, 1, 0, 0); - else - effectArray[0]["options"]["matrixNew"] = obj.pointMatrixToTransformation(obj.rectToMatrix(elem)).mult((new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.getScreenCTM()).inv().mult((new matrixSVG()).fromSVGMatrix(elem.parentNode.getScreenCTM())).inv()); - - transCounter = 0; - startTime = (new Date()).getTime(); - lastFrameTime = null; - effect(1); - - return false; - } - - /** Function to search for the element the user clicked on. - * - * This function searches for the element with the highest z-order, which encloses the point the user clicked on - * and which view box fits entierly into the currently visible part of the slide. - * - * @param elem Element to start the search from. - * @param pnt Point where the user clicked. - * @returns The element the user clicked on or null, if no element could be found. - */ - obj.getAdHocViewBbox = function (elem, pnt) - { - var children = elem.childNodes; - - for (var counter = 0; counter < children.length; counter++) - { - if (children[counter].getBBox) - { - var childPointList = obj.projectRect(children[counter].getBBox(), children[counter].getScreenCTM()); - - var viewBbox = document.documentElement.createSVGRect(); - - viewBbox.x = 0.0; - viewBbox.y = 0.0; - viewBbox.width = WIDTH; - viewBbox.height = HEIGHT; - - var screenPointList = obj.projectRect(viewBbox, slides[activeSlide]["element"].getScreenCTM()); - - if (obj.pointsWithinRect([pnt], childPointList) && obj.pointsWithinRect(childPointList, screenPointList)) - return children[counter]; - - child = obj.getAdHocViewBbox(children[counter], pnt); - - if (child != null) - return child; - } - } - - return null; - } - - /** Function to project a rectangle using the projection matrix supplied. - * - * @param rect The rectangle to project. - * @param projectionMatrix The projection matrix. - * @returns A list of the four corners of the projected rectangle starting from the upper left corner and going counter-clockwise. - */ - obj.projectRect = function (rect, projectionMatrix) - { - var pntUL = document.documentElement.createSVGPoint(); - pntUL.x = rect.x; - pntUL.y = rect.y; - pntUL = pntUL.matrixTransform(projectionMatrix); - - var pntLL = document.documentElement.createSVGPoint(); - pntLL.x = rect.x; - pntLL.y = rect.y + rect.height; - pntLL = pntLL.matrixTransform(projectionMatrix); - - var pntUR = document.documentElement.createSVGPoint(); - pntUR.x = rect.x + rect.width; - pntUR.y = rect.y; - pntUR = pntUR.matrixTransform(projectionMatrix); - - var pntLR = document.documentElement.createSVGPoint(); - pntLR.x = rect.x + rect.width; - pntLR.y = rect.y + rect.height; - pntLR = pntLR.matrixTransform(projectionMatrix); - - return [pntUL, pntLL, pntUR, pntLR]; - } - - /** Function to determine whether all the points supplied in a list are within a rectangle. - * - * @param pnts List of points to check. - * @param pointList List of points representing the four corners of the rectangle. - * @return True, if all points are within the rectangle; false, otherwise. - */ - obj.pointsWithinRect = function (pnts, pointList) - { - var pntUL = pointList[0]; - var pntLL = pointList[1]; - var pntUR = pointList[2]; - - var matrixOrig = (new matrixSVG()).fromElements(pntUL.x, pntLL.x, pntUR.x, pntUL.y, pntLL.y, pntUR.y, 1, 1, 1); - var matrixProj = (new matrixSVG()).fromElements(0, 0, 1, 0, 1, 0, 1, 1, 1); - - var matrixProjection = matrixProj.mult(matrixOrig.inv()); - - for (var blockCounter = 0; blockCounter < Math.ceil(pnts.length / 3.0); blockCounter++) - { - var subPnts = new Array(); - - for (var pntCounter = 0; pntCounter < 3.0; pntCounter++) - { - if (blockCounter * 3.0 + pntCounter < pnts.length) - subPnts[pntCounter] = pnts[blockCounter * 3.0 + pntCounter]; - else - { - var tmpPnt = document.documentElement.createSVGPoint(); - - tmpPnt.x = 0.0; - tmpPnt.y = 0.0; - - subPnts[pntCounter] = tmpPnt; - } - } - - var matrixPnt = (new matrixSVG).fromElements(subPnts[0].x, subPnts[1].x, subPnts[2].x, subPnts[0].y, subPnts[1].y, subPnts[2].y, 1, 1, 1); - var matrixTrans = matrixProjection.mult(matrixPnt); - - for (var pntCounter = 0; pntCounter < 3.0; pntCounter++) - { - if (blockCounter * 3.0 + pntCounter < pnts.length) - { - if ((pntCounter == 0) && !((matrixTrans.e11 > 0.01) && (matrixTrans.e11 < 0.99) && (matrixTrans.e21 > 0.01) && (matrixTrans.e21 < 0.99))) - return false; - else if ((pntCounter == 1) && !((matrixTrans.e12 > 0.01) && (matrixTrans.e12 < 0.99) && (matrixTrans.e22 > 0.01) && (matrixTrans.e22 < 0.99))) - return false; - else if ((pntCounter == 2) && !((matrixTrans.e13 > 0.01) && (matrixTrans.e13 < 0.99) && (matrixTrans.e23 > 0.01) && (matrixTrans.e23 < 0.99))) - return false; - } - } - } - - return true; - } - - /** Event handler for mouse movements. - * - * @param e Event object. - */ - obj.mousemove = function (e) - { - obj.click = false; - - if (!obj.dragging_active || obj.dragging_working) - return false; - - obj.dragging_working = true; - - var p = obj.getCoords(e); - - if (slides[activeSlide].viewGroup.transform.baseVal.numberOfItems < 1) - { - var matrix = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - } - else - { - var matrix = (new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.transform.baseVal.consolidate().matrix); - } - - matrix.e13 += p.x - obj.dragging_last.x; - matrix.e23 += p.y - obj.dragging_last.y; - - slides[activeSlide]["viewGroup"].setAttribute("transform", matrix.toAttribute()); - - obj.dragging_last = p; - obj.dragging_working = false; - - return false; - } - - /** Event handler for mouse down. - * - * @param e Event object. - */ - obj.mousedown = function (e) - { - if (obj.dragging_active) - return false; - - var value = 0; - - if (e.button) - value = e.button; - else if (e.which) - value = e.which; - - if (value == 1) - { - obj.dragging_last = obj.getCoords(e); - obj.dragging_active = true; - obj.click = true; - } - - return false; - } - - /** Event handler for mouse up. - * - * @param e Event object. - */ - obj.mouseup = function (e) - { - obj.dragging_active = false; - - if (obj.click) - return obj.mouseclick(e); - else - return false; - } - - /** Function to get the coordinates of a point corrected for the offset of the viewport. - * - * @param e Point. - * @returns Coordinates of the point corrected for the offset of the viewport. - */ - obj.getCoords = function (e) - { - var svgPoint = document.documentElement.createSVGPoint(); - svgPoint.x = e.clientX + window.pageXOffset; - svgPoint.y = e.clientY + window.pageYOffset; - - return svgPoint; - } - - /** Event handler for scrolling. - * - * @param e Event object. - */ - obj.mousewheel = function(e) - { - var p = obj.projectCoords(obj.getCoords(e)); - - if (slides[activeSlide].viewGroup.transform.baseVal.numberOfItems < 1) - { - var matrix = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - } - else - { - var matrix = (new matrixSVG()).fromSVGMatrix(slides[activeSlide].viewGroup.transform.baseVal.consolidate().matrix); - } - - if (e.wheelDelta) - { // IE Opera - delta = e.wheelDelta/120; - } - else if (e.detail) - { // MOZ - delta = -e.detail/3; - } - - var widthOld = p.x * matrix.e11 + p.y * matrix.e12; - var heightOld = p.x * matrix.e21 + p.y * matrix.e22; - - matrix.e11 *= (1.0 - delta / 20.0); - matrix.e12 *= (1.0 - delta / 20.0); - matrix.e21 *= (1.0 - delta / 20.0); - matrix.e22 *= (1.0 - delta / 20.0); - - var widthNew = p.x * matrix.e11 + p.y * matrix.e12; - var heightNew = p.x * matrix.e21 + p.y * matrix.e22; - - matrix.e13 += (widthOld - widthNew); - matrix.e23 += (heightOld - heightNew); - - slides[activeSlide]["viewGroup"].setAttribute("transform", matrix.toAttribute()); - - return false; - } - - /** Function to project a point to screen coordinates. - * - * @param Point. - * @returns The point projected to screen coordinates. - */ - obj.projectCoords = function(pnt) - { - var matrix = slides[activeSlide]["element"].getScreenCTM(); - - if (slides[activeSlide]["viewGroup"]) - matrix = slides[activeSlide]["viewGroup"].getScreenCTM(); - - pnt = pnt.matrixTransform(matrix.inverse()); - return pnt; - } - - /** Function to convert a rectangle into a point matrix. - * - * The function figures out a rectangle that encloses the rectangle given and has the same width/height ratio as the viewport of the presentation. - * - * @param rect Rectangle. - * @return The upper left, upper right and lower right corner of the rectangle in a point matrix. - */ - obj.rectToMatrix = function(rect) - { - rectWidth = rect.getBBox().width; - rectHeight = rect.getBBox().height; - rectX = rect.getBBox().x; - rectY = rect.getBBox().y; - rectXcorr = 0; - rectYcorr = 0; - - scaleX = WIDTH / rectWidth; - scaleY = HEIGHT / rectHeight; - - if (scaleX > scaleY) - { - scaleX = scaleY; - rectXcorr -= (WIDTH / scaleX - rectWidth) / 2; - rectWidth = WIDTH / scaleX; - } - else - { - scaleY = scaleX; - rectYcorr -= (HEIGHT / scaleY - rectHeight) / 2; - rectHeight = HEIGHT / scaleY; - } - - if (rect.transform.baseVal.numberOfItems < 1) - { - mRectTrans = (new matrixSVG()).fromElements(1, 0, 0, 0, 1, 0, 0, 0, 1); - } - else - { - mRectTrans = (new matrixSVG()).fromSVGMatrix(rect.transform.baseVal.consolidate().matrix); - } - - newBasePoints = (new matrixSVG()).fromElements(rectX, rectX, rectX, rectY, rectY, rectY, 1, 1, 1); - newVectors = (new matrixSVG()).fromElements(rectXcorr, rectXcorr + rectWidth, rectXcorr + rectWidth, rectYcorr, rectYcorr, rectYcorr + rectHeight, 0, 0, 0); - - return mRectTrans.mult(newBasePoints.add(newVectors)); - } - - /** Function to return a transformation matrix from a point matrix. - * - * @param mPoints The point matrix. - * @returns The transformation matrix. - */ - obj.pointMatrixToTransformation = function(mPoints) - { - mPointsOld = (new matrixSVG()).fromElements(0, WIDTH, WIDTH, 0, 0, HEIGHT, 1, 1, 1); - - return mPointsOld.mult(mPoints.inv()); - } -} - diff --git a/share/extensions/jessyInk_effects.inx b/share/extensions/jessyInk_effects.inx deleted file mode 100644 index ce55b3859..000000000 --- a/share/extensions/jessyInk_effects.inx +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Effects</_name> - <id>jessyink.effects</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_effects.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <_param name="effectInLabel" type="description">Build-in effect</_param> - <param name="effectInOrder" type="int" min="1" max="100" _gui-text="Order:">1</param> - <param name="effectInDuration" precision="1" type="float" min="0.1" max="10.0" _gui-text="Duration in seconds:">0.8</param> - <param name="effectIn" type="optiongroup" _gui-text="Type:"> - <_option value="none">None (default)</_option> - <_option value="appear">Appear</_option> - <_option value="fade">Fade in</_option> - <_option value="pop">Pop</_option> - </param> - <_param name="effectOutLabel" type="description">Build-out effect</_param> - <param name="effectOutOrder" type="int" min="1" max="100" _gui-text="Order:">1</param> - <param name="effectOutDuration" precision="1" type="float" min="0.1" max="10.0" _gui-text="Duration in seconds:">0.8</param> - <param name="effectOut" type="optiongroup" _gui-text="Type:"> - <_option value="none">None (default)</_option> - <_option value="appear">Appear</_option> - <_option value="fade">Fade out</_option> - <_option value="pop">Pop</_option> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to install, update and remove object effects for a JessyInk presentation. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_effects.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_effects.py b/share/extensions/jessyInk_effects.py deleted file mode 100755 index dc56d3a75..000000000 --- a/share/extensions/jessyInk_effects.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - -class JessyInk_Effects(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--effectInOrder', action = 'store', type = 'string', dest = 'effectInOrder', default = 1) - self.OptionParser.add_option('--effectInDuration', action = 'store', type = 'float', dest = 'effectInDuration', default = 0.8) - self.OptionParser.add_option('--effectIn', action = 'store', type = 'string', dest = 'effectIn', default = 'none') - self.OptionParser.add_option('--effectOutOrder', action = 'store', type = 'string', dest = 'effectOutOrder', default = 2) - self.OptionParser.add_option('--effectOutDuration', action = 'store', type = 'float', dest = 'effectOutDuration', default = 0.8) - self.OptionParser.add_option('--effectOut', action = 'store', type = 'string', dest = 'effectOut', default = 'none') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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: - 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"): - node.set("{" + inkex.NSS["jessyink"] + "}effectIn","name:" + self.options.effectIn + ";order:" + self.options.effectInOrder + ";length:" + str(int(self.options.effectInDuration * 1000))) - # Remove possible view argument. - if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}view"): - del node.attrib["{" + inkex.NSS["jessyink"] + "}view"] - else: - if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}effectIn"): - del node.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"] - - if (self.options.effectOut == "appear") or (self.options.effectOut == "fade") or (self.options.effectOut == "pop"): - node.set("{" + inkex.NSS["jessyink"] + "}effectOut","name:" + self.options.effectOut + ";order:" + self.options.effectOutOrder + ";length:" + str(int(self.options.effectOutDuration * 1000))) - # Remove possible view argument. - if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}view"): - del node.attrib["{" + inkex.NSS["jessyink"] + "}view"] - else: - if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}effectOut"): - del node.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"] - -# Create effect instance -effect = JessyInk_Effects() -effect.affect() - diff --git a/share/extensions/jessyInk_export.inx b/share/extensions/jessyInk_export.inx deleted file mode 100644 index fc8536a71..000000000 --- a/share/extensions/jessyInk_export.inx +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>JessyInk zipped pdf or png output</_name> - <id>jessyink.export</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">jessyInk_export.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <param name="type" type="optiongroup" _gui-text="Type:"> - <_option value="PDF">PDF</_option> - <_option value="PNG">PNG</_option> - </param> - <param name="resolution" type="int" min="1" max="1000" _gui-text="Resolution:">92</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to export a JessyInk presentation once you created an export layer in your browser. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <output> - <extension>.zip</extension> - <mimetype>application/x-zip</mimetype> - <_filetypename>JessyInk zipped pdf or png output (*.zip)</_filetypename> - <_filetypetooltip>Creates a zip file containing pdfs or pngs of all slides of a JessyInk presentation.</_filetypetooltip> - <dataloss>TRUE</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">jessyInk_export.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/jessyInk_export.py b/share/extensions/jessyInk_export.py deleted file mode 100755 index 1c7cc8c37..000000000 --- a/share/extensions/jessyInk_export.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -import inkex, os.path -import subprocess -import tempfile -import os -import zipfile -import glob -import re - -def propStrToDict(inStr): - dictio = {} - - for prop in inStr.split(";"): - values = prop.split(":") - - if (len(values) == 2): - dictio[values[0].strip()] = values[1].strip() - - return dictio - -def dictToPropStr(dictio): - str = "" - - for key in dictio.keys(): - str += " " + key + ":" + dictio[key] + ";" - - return str[1:] - -def setStyle(node, propKey, propValue): - props = {} - - if node.attrib.has_key("style"): - props = propStrToDict(node.get("style")) - - props[propKey] = propValue - node.set("style", dictToPropStr(props)) - -class MyEffect(inkex.Effect): - inkscapeCommand = None - zipFile = None - - def __init__(self): - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--type', action = 'store', type = 'string', dest = 'type', default = '') - self.OptionParser.add_option('--resolution', action = 'store', type = 'string', dest = 'resolution', default = '') - - # Register jessyink namespace. - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - # Set inkscape command. - self.inkscapeCommand = self.findInkscapeCommand() - - if (self.inkscapeCommand == None): - inkex.errormsg(_("Could not find Inkscape command.\n")) - sys.exit(1) - - def output(self): - pass - - def effect(self): - # Remove any temporary files that might be left from last time. - self.removeJessyInkFilesInTempDir() - - # Check whether the JessyInk-script is present (indicating that the presentation has not been properly exported). - scriptNodes = self.document.xpath("//svg:script[@jessyink:version]", namespaces=inkex.NSS) - - if len(scriptNodes) != 0: - 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__") - - output = zipfile.ZipFile(zpFile, "w", compression=zipfile.ZIP_STORED) - - # Find layers. - exportNodes = self.document.xpath("//svg:g[@inkscape:groupmode='layer']", namespaces=inkex.NSS) - - if len(exportNodes) < 1: - sys.stderr.write("No layers found.") - - for node in exportNodes: - setStyle(node, "display", "none") - - for node in exportNodes: - setStyle(node, "display", "inherit") - setStyle(node, "opacity", "1") - self.takeSnapshot(output, node.attrib["{" + inkex.NSS["inkscape"] + "}label"]) - setStyle(node, "display", "none") - - # Write temporary zip file to stdout. - output.close() - out = open(zpFile,'rb') - - # Switch stdout to binary on Windows. - if sys.platform == "win32": - import os, msvcrt - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - - # Output the file. - sys.stdout.write(out.read()) - sys.stdout.close() - out.close() - - # Delete temporary files. - self.removeJessyInkFilesInTempDir() - - # Function to export the current state of the file using Inkscape. - def takeSnapshot(self, output, fileName): - # Write the svg file. - svgFileDesc, svgFile = tempfile.mkstemp(suffix=".svg", prefix="jessyInk__") - self.document.write(os.fdopen(svgFileDesc, "wb")) - - ext = str(self.options.type).lower() - - # Prepare output file. - outFileDesc, outFile = tempfile.mkstemp(suffix="." + ext, prefix="jessyInk__") - - proc = subprocess.Popen([self.inkscapeCommand + " --file=" + svgFile + " --without-gui --export-dpi=" + str(self.options.resolution) + " --export-" + ext + "=" + outFile], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout_value, stderr_value = proc.communicate() - - output.write(outFile, fileName + "." + ext) - - # Function to remove any temporary files created during the export. - def removeJessyInkFilesInTempDir(self): - for infile in glob.glob(os.path.join(tempfile.gettempdir(), 'jessyInk__*')): - try: - os.remove(infile) - except: - pass - - # Function to try and find the correct command to invoke Inkscape. - def findInkscapeCommand(self): - commands = [] - commands.append("inkscape") - commands.append("C:\Program Files\Inkscape\inkscape.exe") - commands.append("/Applications/Inkscape.app/Contents/Resources/bin/inkscape") - - for command in commands: - proc = subprocess.Popen([command + " --without-gui --version"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout_value, stderr_value = proc.communicate() - - if proc.returncode == 0: - return command - - return None - -e = MyEffect() -e.affect() diff --git a/share/extensions/jessyInk_install.inx b/share/extensions/jessyInk_install.inx deleted file mode 100644 index 0e89b60b4..000000000 --- a/share/extensions/jessyInk_install.inx +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Install/update</_name> - <id>jessyink.install</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_install.py</dependency> - <dependency type="executable" location="extensions">jessyInk.js</dependency> - <param name="tab" type="notebook"> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to install or update the JessyInk script in order to turn your SVG file into a presentation. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_install.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_install.py b/share/extensions/jessyInk_install.py deleted file mode 100755 index 5183cc14f..000000000 --- a/share/extensions/jessyInk_install.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -import os - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - -def propStrToList(str): - list = [] - propList = str.split(";") - for prop in propList: - if not (len(prop) == 0): - list.append(prop.strip()) - return list - -def listToPropStr(list): - str = "" - for prop in list: - str += " " + prop + ";" - return str[1:] - -class JessyInk_Install(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Find and delete old script node - for node in self.document.xpath("//svg:script[@id='JessyInk']", namespaces=inkex.NSS): - node.getparent().remove(node) - - # Create new script node - 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.5') - self.document.getroot().append(scriptElm) - - # Remove "jessyInkInit()" in the "onload" attribute, if present. - if self.document.getroot().get("onload"): - propList = propStrToList(self.document.getroot().get("onload")) - else: - propList = [] - - for prop in propList: - if prop == "jessyInkInit()": - propList.remove("jessyInkInit()") - - if len(propList) > 0: - self.document.getroot().set("onload", listToPropStr(propList)) - else: - if self.document.getroot().get("onload"): - del self.document.getroot().attrib["onload"] - - # Update effect attributes. - for node in self.document.xpath("//*[@jessyInk_effectIn]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"] = node.attrib["jessyInk_effectIn"] - del node.attrib["jessyInk_effectIn"] - - for node in self.document.xpath("//*[@jessyink:effectIn]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"] = node.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"].replace("=", ":") - - for node in self.document.xpath("//*[@jessyInk_effectOut]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"] = node.attrib["jessyInk_effectOut"] - del node.attrib["jessyInk_effectOut"] - - for node in self.document.xpath("//*[@jessyink:effectOut]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"] = node.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"].replace("=", ":") - - # Update master slide assignment. - for node in self.document.xpath("//*[@jessyInk_masterSlide]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}masterSlide"] = node.attrib["jessyInk_masterSlide"] - del node.attrib["jessyInk_masterSlide"] - - for node in self.document.xpath("//*[@jessyink:masterSlide]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}masterSlide"] = node.attrib["{" + inkex.NSS["jessyink"] + "}masterSlide"].replace("=", ":") - - # Update transitions. - for node in self.document.xpath("//*[@jessyInk_transitionIn]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}transitionIn"] = node.attrib["jessyInk_transitionIn"] - del node.attrib["jessyInk_transitionIn"] - - for node in self.document.xpath("//*[@jessyink:transitionIn]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}transitionIn"] = node.attrib["{" + inkex.NSS["jessyink"] + "}transitionIn"].replace("=", ":") - - for node in self.document.xpath("//*[@jessyInk_transitionOut]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}transitionOut"] = node.attrib["jessyInk_transitionOut"] - del node.attrib["jessyInk_transitionOut"] - - for node in self.document.xpath("//*[@jessyink:transitionOut]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}transitionOut"] = node.attrib["{" + inkex.NSS["jessyink"] + "}transitionOut"].replace("=", ":") - - # Update auto texts. - for node in self.document.xpath("//*[@jessyInk_autoText]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}autoText"] = node.attrib["jessyInk_autoText"] - del node.attrib["jessyInk_autoText"] - - for node in self.document.xpath("//*[@jessyink:autoText]", namespaces=inkex.NSS): - node.attrib["{" + inkex.NSS["jessyink"] + "}autoText"] = node.attrib["{" + inkex.NSS["jessyink"] + "}autoText"].replace("=", ":") - -# Create effect instance -effect = JessyInk_Install() -effect.affect() - diff --git a/share/extensions/jessyInk_keyBindings.inx b/share/extensions/jessyInk_keyBindings.inx deleted file mode 100644 index 99e5a9658..000000000 --- a/share/extensions/jessyInk_keyBindings.inx +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Key bindings</_name> - <id>jessyink.keyBindings</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_keyBindings.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Slide mode"> - <param name="slide_backWithEffects" type="string" _gui-text="Back (with effects):">LEFT, PAGE_UP</param> - <param name="slide_nextWithEffects" type="string" _gui-text="Next (with effects):">RIGHT, PAGE_DOWN, SPACE</param> - <param name="slide_backWithoutEffects" type="string" _gui-text="Back (without effects):">UP</param> - <param name="slide_nextWithoutEffects" type="string" _gui-text="Next (without effects):">DOWN</param> - <param name="slide_firstSlide" type="string" _gui-text="First slide:">HOME</param> - <param name="slide_lastSlide" type="string" _gui-text="Last slide:">END</param> - <param name="slide_switchToIndexMode" type="string" _gui-text="Switch to index mode:">i</param> - <param name="slide_switchToDrawingMode" type="string" _gui-text="Switch to drawing mode:">d</param> - <param name="slide_setDuration" type="string" _gui-text="Set duration:">D</param> - <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:">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> - <param name="drawing_pathWidth5" type="string" _gui-text="Set path width to 5:">5</param> - <param name="drawing_pathWidth7" type="string" _gui-text="Set path width to 7:">7</param> - <param name="drawing_pathWidth9" type="string" _gui-text="Set path width to 9:">9</param> - <param name="drawing_pathColourBlue" type="string" _gui-text="Set path color to blue:">b</param> - <param name="drawing_pathColourCyan" type="string" _gui-text="Set path color to cyan:">c</param> - <param name="drawing_pathColourGreen" type="string" _gui-text="Set path color to green:">g</param> - <param name="drawing_pathColourBlack" type="string" _gui-text="Set path color to black:">k</param> - <param name="drawing_pathColourMagenta" type="string" _gui-text="Set path color to magenta:">m</param> - <param name="drawing_pathColourOrange" type="string" _gui-text="Set path color to orange:">o</param> - <param name="drawing_pathColourRed" type="string" _gui-text="Set path color to red:">r</param> - <param name="drawing_pathColourWhite" type="string" _gui-text="Set path color to white:">w</param> - <param name="drawing_pathColourYellow" type="string" _gui-text="Set path color to yellow:">y</param> - <param name="drawing_undo" type="string" _gui-text="Undo last path segment:">z</param> - </page> - <page name="settings" _gui-text="Index mode"> - <param name="index_selectSlideToLeft" type="string" _gui-text="Select the slide to the left:">LEFT</param> - <param name="index_selectSlideToRight" type="string" _gui-text="Select the slide to the right:">RIGHT</param> - <param name="index_selectSlideAbove" type="string" _gui-text="Select the slide above:">UP</param> - <param name="index_selectSlideBelow" type="string" _gui-text="Select the slide below:">DOWN</param> - <param name="index_previousPage" type="string" _gui-text="Previous page:">PAGE_UP</param> - <param name="index_nextPage" type="string" _gui-text="Next page:">PAGE_DOWN</param> - <param name="index_firstSlide" type="string" _gui-text="First slide:">HOME</param> - <param name="index_lastSlide" type="string" _gui-text="Last slide:">END</param> - <param name="index_switchToSlideMode" type="string" _gui-text="Switch to slide mode:">ENTER, i</param> - <param name="index_decreaseNumberOfColumns" type="string" _gui-text="Decrease number of columns:">-</param> - <param name="index_increaseNumberOfColumns" type="string" _gui-text="Increase number of columns:">+, =</param> - <param name="index_setNumberOfColumnsToDefault" type="string" _gui-text="Set number of columns to default:">0</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you customize the key bindings JessyInk uses. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>g</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_keyBindings.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_keyBindings.py b/share/extensions/jessyInk_keyBindings.py deleted file mode 100755 index 2e2b48c7d..000000000 --- a/share/extensions/jessyInk_keyBindings.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - - -class JessyInk_CustomKeyBindings(inkex.Effect): - modes = ('slide', 'index', 'drawing') - keyCodes = ('LEFT', 'RIGHT', 'DOWN', 'UP', 'HOME', 'END', 'ENTER', 'SPACE', 'PAGE_UP', 'PAGE_DOWN', 'ESCAPE') - slideActions = {} - slideCharCodes = {} - slideKeyCodes = {} - drawingActions = {} - drawingCharCodes = {} - drawingKeyCodes = {} - indexActions = {} - indexCharCodes = {} - indexKeyCodes = {} - - - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--slide_backWithEffects', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_nextWithEffects', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_backWithoutEffects', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_nextWithoutEffects', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_firstSlide', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_lastSlide', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_switchToIndexMode', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_switchToDrawingMode', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - self.OptionParser.add_option('--slide_setDuration', action = 'callback', type = 'string', callback = self.slideOptions, default = '') - 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 = '') - self.OptionParser.add_option('--drawing_pathWidth2', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth3', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth4', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth5', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth6', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth7', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth8', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathWidth9', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourBlue', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourCyan', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourGreen', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourBlack', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourMagenta', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourOrange', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourRed', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourWhite', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_pathColourYellow', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--drawing_undo', action = 'callback', type = 'string', callback = self.drawingOptions, default = '') - self.OptionParser.add_option('--index_selectSlideToLeft', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_selectSlideToRight', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_selectSlideAbove', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_selectSlideBelow', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_previousPage', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_nextPage', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_firstSlide', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_lastSlide', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_switchToSlideMode', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_decreaseNumberOfColumns', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_increaseNumberOfColumns', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - self.OptionParser.add_option('--index_setNumberOfColumnsToDefault', action = 'callback', type = 'string', callback = self.indexOptions, default = '') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - self.slideActions["backWithEffects"] = "dispatchEffects(-1);" - self.slideActions["nextWithEffects"] = "dispatchEffects(1);" - self.slideActions["backWithoutEffects"] = "skipEffects(-1);" - self.slideActions["nextWithoutEffects"] = "skipEffects(1);" - self.slideActions["firstSlide"] = "slideSetActiveSlide(0);" - self.slideActions["lastSlide"] = "slideSetActiveSlide(slides.length - 1);" - self.slideActions["switchToIndexMode"] = "toggleSlideIndex();" - self.slideActions["switchToDrawingMode"] = "slideSwitchToDrawingMode();" - self.slideActions["setDuration"] = "slideQueryDuration();" - 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();" - self.drawingActions["pathWidth1"] = "drawingSetPathWidth(1.0);" - self.drawingActions["pathWidth3"] = "drawingSetPathWidth(3.0);" - self.drawingActions["pathWidth5"] = "drawingSetPathWidth(5.0);" - self.drawingActions["pathWidth7"] = "drawingSetPathWidth(7.0);" - self.drawingActions["pathWidth9"] = "drawingSetPathWidth(9.0);" - self.drawingActions["pathColourBlue"] = "drawingSetPathColour(\"blue\");" - self.drawingActions["pathColourCyan"] = "drawingSetPathColour(\"cyan\");" - self.drawingActions["pathColourGreen"] = "drawingSetPathColour(\"green\");" - self.drawingActions["pathColourBlack"] = "drawingSetPathColour(\"black\");" - self.drawingActions["pathColourMagenta"] = "drawingSetPathColour(\"magenta\");" - self.drawingActions["pathColourOrange"] = "drawingSetPathColour(\"orange\");" - self.drawingActions["pathColourRed"] = "drawingSetPathColour(\"red\");" - self.drawingActions["pathColourWhite"] = "drawingSetPathColour(\"white\");" - self.drawingActions["pathColourYellow"] = "drawingSetPathColour(\"yellow\");" - self.drawingActions["undo"] = "drawingUndo();" - - self.indexActions["selectSlideToLeft"] = "indexSetPageSlide(activeSlide - 1);" - self.indexActions["selectSlideToRight"] = "indexSetPageSlide(activeSlide + 1);" - self.indexActions["selectSlideAbove"] = "indexSetPageSlide(activeSlide - INDEX_COLUMNS);" - self.indexActions["selectSlideBelow"] = "indexSetPageSlide(activeSlide + INDEX_COLUMNS);" - self.indexActions["previousPage"] = "indexSetPageSlide(activeSlide - INDEX_COLUMNS * INDEX_COLUMNS);" - self.indexActions["nextPage"] = "indexSetPageSlide(activeSlide + INDEX_COLUMNS * INDEX_COLUMNS);" - self.indexActions["firstSlide"] = "indexSetPageSlide(0);" - self.indexActions["lastSlide"] = "indexSetPageSlide(slides.length - 1);" - self.indexActions["switchToSlideMode"] = "toggleSlideIndex();" - self.indexActions["decreaseNumberOfColumns"] = "indexDecreaseNumberOfColumns();" - self.indexActions["increaseNumberOfColumns"] = "indexIncreaseNumberOfColumns();" - self.indexActions["setNumberOfColumnsToDefault"] = "indexResetNumberOfColumns();" - - def slideOptions(self, option, opt_str, value, parser): - action = self.getAction(opt_str) - - valueArray = value.split(",") - - for val in valueArray: - val = val.strip() - - if val in self.keyCodes: - self.slideKeyCodes[val + "_KEY"] = self.slideActions[action] - elif len(val) == 1: - self.slideCharCodes[val] = self.slideActions[action] - - def drawingOptions(self, option, opt_str, value, parser): - action = self.getAction(opt_str) - - valueArray = value.split(",") - - for val in valueArray: - val = val.strip() - - if val in self.keyCodes: - self.drawingKeyCodes[val + "_KEY"] = self.drawingActions[action] - elif len(val) == 1: - self.drawingCharCodes[val] = self.drawingActions[action] - - def indexOptions(self, option, opt_str, value, parser): - action = self.getAction(opt_str) - - valueArray = value.split(",") - - for val in valueArray: - val = val.strip() - - if val in self.keyCodes: - self.indexKeyCodes[val + "_KEY"] = self.indexActions[action] - elif len(val) == 1: - self.indexCharCodes[val] = self.indexActions[action] - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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): - node.getparent().remove(node) - - # Set custom key bindings. - nodeText = "function getCustomKeyBindingsSub()" + "\n" - nodeText += "{" + "\n" - nodeText += " var keyDict = new Object();" + "\n" - nodeText += " keyDict[SLIDE_MODE] = new Object();" + "\n" - nodeText += " keyDict[INDEX_MODE] = new Object();" + "\n" - nodeText += " keyDict[DRAWING_MODE] = new Object();" + "\n" - - for key, value in self.slideKeyCodes.items(): - nodeText += " keyDict[SLIDE_MODE][" + key + "] = function() { " + value + " };" + "\n" - - for key, value in self.drawingKeyCodes.items(): - nodeText += " keyDict[DRAWING_MODE][" + key + "] = function() { " + value + " };" + "\n" - - for key, value in self.indexKeyCodes.items(): - nodeText += " keyDict[INDEX_MODE][" + key + "] = function() { " + value + " };" + "\n" - - nodeText += " return keyDict;" + "\n" - nodeText += "}" + "\n\n" - - # Set custom char bindings. - nodeText += "function getCustomCharBindingsSub()" + "\n" - nodeText += "{" + "\n" - nodeText += " var charDict = new Object();" + "\n" - nodeText += " charDict[SLIDE_MODE] = new Object();" + "\n" - nodeText += " charDict[INDEX_MODE] = new Object();" + "\n" - nodeText += " charDict[DRAWING_MODE] = new Object();" + "\n" - - for key, value in self.slideCharCodes.items(): - nodeText += " charDict[SLIDE_MODE][\"" + key + "\"] = function() { " + value + " };" + "\n" - - for key, value in self.drawingCharCodes.items(): - nodeText += " charDict[DRAWING_MODE][\"" + key + "\"] = function() { " + value + " };" + "\n" - - for key, value in self.indexCharCodes.items(): - nodeText += " charDict[INDEX_MODE][\"" + key + "\"] = function() { " + value + " };" + "\n" - - nodeText += " return charDict;" + "\n" - nodeText += "}" + "\n" - - # Create new script node - scriptElm = inkex.etree.Element(inkex.addNS("script", "svg")) - scriptElm.text = nodeText - groupElm = inkex.etree.Element(inkex.addNS("g", "svg")) - groupElm.set("{" + inkex.NSS["jessyink"] + "}customKeyBindings", "customKeyBindings") - groupElm.set("onload", "this.getCustomCharBindings = function() { return getCustomCharBindingsSub(); }; this.getCustomKeyBindings = function() { return getCustomKeyBindingsSub(); };") - groupElm.append(scriptElm) - self.document.getroot().append(groupElm) - - def getAction(self, varName): - parts = varName.split('_') - - if (len(parts) != 2): - raise StandardException("Error parsing variable name.") - - return parts[1] - -# Create effect instance -effect = JessyInk_CustomKeyBindings() -effect.affect() - diff --git a/share/extensions/jessyInk_masterSlide.inx b/share/extensions/jessyInk_masterSlide.inx deleted file mode 100644 index e9518ba11..000000000 --- a/share/extensions/jessyInk_masterSlide.inx +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Master slide</_name> - <id>jessyink.masterSlide</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_masterSlide.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <param name="layerName" type="string" _gui-text="Name of layer:"></param> - <_param name="info_text" type="description">If no layer name is supplied, the master slide is unset.</_param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to change the master slide JessyInk uses. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>g</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_masterSlide.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_masterSlide.py b/share/extensions/jessyInk_masterSlide.py deleted file mode 100755 index edaf751fa..000000000 --- a/share/extensions/jessyInk_masterSlide.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - -class JessyInk_MasterSlide(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--layerName', action = 'store', type = 'string', dest = 'layerName', default = '') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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): - del node.attrib["{" + inkex.NSS["jessyink"] + "}masterSlide"] - - # Set new master slide. - if self.options.layerName != "": - nodes = self.document.xpath("//*[@inkscape:groupmode='layer' and @inkscape:label='" + self.options.layerName + "']", namespaces=inkex.NSS) - if len(nodes) == 0: - inkex.errormsg(_("Layer not found. Removed current master slide selection.\n")) - elif len(nodes) > 1: - 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") - -# Create effect instance -effect = JessyInk_MasterSlide() -effect.affect() - diff --git a/share/extensions/jessyInk_mouseHandler.inx b/share/extensions/jessyInk_mouseHandler.inx deleted file mode 100644 index 24319b149..000000000 --- a/share/extensions/jessyInk_mouseHandler.inx +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Mouse handler</_name> - <id>jessyink.mouseHandler</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_mouseHandler.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Mouse handler"> - <param name="mouseSetting" type="optiongroup" _gui-text="Mouse settings:"> - <_option value="default">Default</_option> - <_option value="noclick">No-click</_option> - <_option value="draggingZoom">Dragging/zoom</_option> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you customize the mouse handler JessyInk uses. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>g</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_mouseHandler.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_mouseHandler.py b/share/extensions/jessyInk_mouseHandler.py deleted file mode 100755 index 3b64e7658..000000000 --- a/share/extensions/jessyInk_mouseHandler.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -import os - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - - -class JessyInk_CustomMouseHandler(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--mouseSettings', action = 'store', type = 'string', dest = 'mouseSettings', default = 'default') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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): - node.getparent().remove(node) - - if self.options.mouseSettings == "noclick": - # Create new script node. - scriptElm = inkex.etree.Element(inkex.addNS("script", "svg")) - scriptElm.text = open(os.path.join(os.path.dirname(__file__), "jessyInk_core_mouseHandler_noclick.js")).read() - groupElm = inkex.etree.Element(inkex.addNS("mousehandler", "jessyink")) - groupElm.set("{" + inkex.NSS["jessyink"] + "}subtype", "jessyInk_core_mouseHandler_noclick") - groupElm.append(scriptElm) - self.document.getroot().append(groupElm) - elif self.options.mouseSettings == "draggingZoom": - # Create new script node. - scriptElm = inkex.etree.Element(inkex.addNS("script", "svg")) - scriptElm.text = open(os.path.join(os.path.dirname(__file__), "jessyInk_core_mouseHandler_zoomControl.js")).read() - groupElm = inkex.etree.Element(inkex.addNS("mousehandler", "jessyink")) - groupElm.set("{" + inkex.NSS["jessyink"] + "}subtype", "jessyInk_core_mouseHandler_zoomControl") - groupElm.append(scriptElm) - self.document.getroot().append(groupElm) - -# Create effect instance -effect = JessyInk_CustomMouseHandler() -effect.affect() - diff --git a/share/extensions/jessyInk_summary.inx b/share/extensions/jessyInk_summary.inx deleted file mode 100644 index 37bc206fc..000000000 --- a/share/extensions/jessyInk_summary.inx +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Summary</_name> - <id>jessyink.summary</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <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> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_summary.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_summary.py b/share/extensions/jessyInk_summary.py deleted file mode 100755 index c5be47a49..000000000 --- a/share/extensions/jessyInk_summary.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - - -def propStrToList(str): - list = [] - propList = str.split(";") - for prop in propList: - if not (len(prop) == 0): - list.append(prop.strip()) - return list - -def propListToDict(list): - dictio = {} - - for prop in list: - keyValue = prop.split(":") - - if len(keyValue) == 2: - dictio[keyValue[0].strip()] = keyValue[1].strip() - - return dictio - -class JessyInk_Summary(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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): - if node.get("{" + inkex.NSS["jessyink"] + "}version"): - inkex.errormsg(_("JessyInk script version {0} installed.").format(node.get("{" + inkex.NSS["jessyink"] + "}version"))) - else: - inkex.errormsg(_("JessyInk script installed.")) - - slides = [] - masterSlide = None - - for node in self.document.xpath("//svg:g[@inkscape:groupmode='layer']", namespaces=inkex.NSS): - if node.get("{" + inkex.NSS["jessyink"] + "}masterSlide"): - masterSlide = node - else: - slides.append(node) - - if masterSlide is not None: - 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: - 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): - 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)) - - if (transInDict["name"] != "appear") and transInDict.has_key("length"): - 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)) - - if (transOutDict["name"] != "appear") and transOutDict.has_key("length"): - 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): - inkex.errormsg(_("\n{0}Auto-texts:").format(prefix)) - - for atNode in autoTextNodes: - 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 = {} - - for effectNode in node.xpath(".//*[@jessyink:effectIn]", namespaces=inkex.NSS): - dictio = propListToDict(propStrToList(effectNode.get("{" + inkex.NSS["jessyink"] + "}effectIn"))) - dictio["direction"] = "in" - dictio["id"] = effectNode.get("id") - dictio["type"] = "effect" - - if not effects.has_key(dictio["order"]): - effects[dictio["order"]] = [] - - effects[dictio["order"]].append(dictio) - - for effectNode in node.xpath(".//*[@jessyink:effectOut]", namespaces=inkex.NSS): - dictio = propListToDict(propStrToList(effectNode.get("{" + inkex.NSS["jessyink"] + "}effectOut"))) - dictio["direction"] = "out" - dictio["id"] = effectNode.get("id") - dictio["type"] = "effect" - - if not effects.has_key(dictio["order"]): - effects[dictio["order"]] = [] - - effects[dictio["order"]].append(dictio) - - for viewNode in node.xpath(".//*[@jessyink:view]", namespaces=inkex.NSS): - dictio = propListToDict(propStrToList(viewNode.get("{" + inkex.NSS["jessyink"] + "}view"))) - dictio["id"] = viewNode.get("id") - dictio["type"] = "view" - - if not effects.has_key(dictio["order"]): - effects[dictio["order"]] = [] - - effects[dictio["order"]].append(dictio) - - order = sorted(effects.keys()) - orderNumber = 0 - - # Display information about effects. - for orderItem in order: - tmpStr = "" - - if orderNumber == 0: - tmpStr += _("\n{0}Initial effect (order number {1}):").format(prefix, effects[orderItem][0]["order"]) - else: - 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": - tmpStr += _("{0}\tView will be set according to object \"{1}\"").format(prefix, item["id"]) - else: - tmpStr += _("{0}\tObject \"{1}\"").format(prefix, item["id"]) - - if item["direction"] == "in": - tmpStr += _(" will appear") - elif item["direction"] == "out": - tmpStr += _(" will disappear") - - if item["name"] != "appear": - tmpStr += _(" using effect \"{0}\"").format(item["name"]) - - if item.has_key("length"): - tmpStr += _(" in {0!s} s").format(int(item["length"]) / 1000.0) - - inkex.errormsg(tmpStr + ".\n") - - orderNumber += 1 - -# Create effect instance -effect = JessyInk_Summary() -effect.affect() - diff --git a/share/extensions/jessyInk_transitions.inx b/share/extensions/jessyInk_transitions.inx deleted file mode 100644 index 1599d2c20..000000000 --- a/share/extensions/jessyInk_transitions.inx +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Transitions</_name> - <id>jessyink.transitions</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_transitions.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <param name="layerName" type="string" _gui-text="Name of layer:"></param> - <_param name="effectInLabel" type="description">Transition in effect</_param> - <param name="effectInDuration" precision="1" type="float" min="0.1" max="10.0" _gui-text="Duration in seconds:">0.8</param> - <param name="effectIn" type="optiongroup" _gui-text="Type:"> - <_option value="default">Default</_option> - <_option value="appear">Appear</_option> - <_option value="fade">Fade</_option> - <_option value="pop">Pop</_option> - </param> - <_param name="effectOutLabel" type="description">Transition out effect</_param> - <param name="effectOutDuration" precision="1" type="float" min="0.1" max="10.0" _gui-text="Duration in seconds:">0.8</param> - <param name="effectOut" type="optiongroup" _gui-text="Type:"> - <_option value="default">Default</_option> - <_option value="appear">Appear</_option> - <_option value="fade">Fade</_option> - <_option value="pop">Pop</_option> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to change the transition JessyInk uses for the selected layer. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>g</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_transitions.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_transitions.py b/share/extensions/jessyInk_transitions.py deleted file mode 100755 index f463b2fb5..000000000 --- a/share/extensions/jessyInk_transitions.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - - -class JessyInk_Transitions(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--layerName', action = 'store', type = 'string', dest = 'layerName', default = '') - self.OptionParser.add_option('--effectIn', action = 'store', type = 'string', dest = 'effectIn', default = 'default') - self.OptionParser.add_option('--effectInDuration', action = 'store', type = 'float', dest = 'effectInDuration', default = 0.8) - self.OptionParser.add_option('--effectOut', action = 'store', type = 'string', dest = 'effectOut', default = 'default') - self.OptionParser.add_option('--effectOutDuration', action = 'store', type = 'float', dest = 'effectOutDuration', default = 0.8) - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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(unicode("//*[@inkscape:groupmode='layer' and @inkscape:label='" + self.options.layerName + "']", 'utf-8'), namespaces=inkex.NSS) - if len(nodes) == 0: - inkex.errormsg(_("Layer not found.\n")) - elif len(nodes) > 1: - 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"): - del nodes[0].attrib["{" + inkex.NSS["jessyink"] + "}transitionIn"] - else: - nodes[0].set("{" + inkex.NSS["jessyink"] + "}transitionIn","name:" + self.options.effectIn + ";length:" + str(int(self.options.effectInDuration * 1000))) - if self.options.effectOut == "default": - if nodes[0].get("{" + inkex.NSS["jessyink"] + "}transitionOut"): - del nodes[0].attrib["{" + inkex.NSS["jessyink"] + "}transitionOut"] - else: - nodes[0].set("{" + inkex.NSS["jessyink"] + "}transitionOut","name:" + self.options.effectOut + ";length:" + str(int(self.options.effectOutDuration * 1000))) - else: - inkex.errormsg(_("Please enter a layer name.\n")) - -# Create effect instance -effect = JessyInk_Transitions() -effect.affect() - diff --git a/share/extensions/jessyInk_uninstall.inx b/share/extensions/jessyInk_uninstall.inx deleted file mode 100644 index 802b3c394..000000000 --- a/share/extensions/jessyInk_uninstall.inx +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Uninstall/remove</_name> - <id>jessyink.uninstall</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_uninstall.py</dependency> - <param name="tab" type="notebook"> - <page name="options" _gui-text="Options"> - <_param name="label" type="description">Please select the parts of JessyInk you want to uninstall/remove.</_param> - <param name="remove_script" type="boolean" _gui-text="Remove script">true</param> - <param name="remove_effects" type="boolean" _gui-text="Remove effects">true</param> - <param name="remove_masterSlide" type="boolean" _gui-text="Remove master slide assignment">true</param> - <param name="remove_transitions" type="boolean" _gui-text="Remove transitions">true</param> - <param name="remove_autoTexts" type="boolean" _gui-text="Remove auto-texts">true</param> - <param name="remove_views" type="boolean" _gui-text="Remove views">true</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to uninstall the JessyInk script. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_uninstall.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_uninstall.py b/share/extensions/jessyInk_uninstall.py deleted file mode 100755 index c1ade2693..000000000 --- a/share/extensions/jessyInk_uninstall.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - -def propStrToList(str): - list = [] - propList = str.split(";") - for prop in propList: - if not (len(prop) == 0): - list.append(prop.strip()) - return list - -def listToPropStr(list): - str = "" - for prop in list: - str += " " + prop + ";" - return str[1:] - -class JessyInk_Uninstall(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--remove_script', action = 'store', type = 'inkbool', dest = 'remove_script', default = True) - self.OptionParser.add_option('--remove_effects', action = 'store', type = 'inkbool', dest = 'remove_effects', default = True) - self.OptionParser.add_option('--remove_masterSlide', action = 'store', type = 'inkbool', dest = 'remove_masterSlide', default = True) - self.OptionParser.add_option('--remove_transitions', action = 'store', type = 'inkbool', dest = 'remove_transitions', default = True) - self.OptionParser.add_option('--remove_autoTexts', action = 'store', type = 'inkbool', dest = 'remove_autoTexts', default = True) - self.OptionParser.add_option('--remove_views', action = 'store', type = 'inkbool', dest = 'remove_views', default = True) - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Remove script, if so desired. - if self.options.remove_script: - # Find and delete script node. - for node in self.document.xpath("//svg:script[@id='JessyInk']", namespaces=inkex.NSS): - node.getparent().remove(node) - - # Remove "jessyInkInit()" in the "onload" attribute, if present. - if self.document.getroot().get("onload"): - propList = propStrToList(self.document.getroot().get("onload")) - else: - propList = [] - - for prop in propList: - if prop == "jessyInkInit()": - propList.remove("jessyInkInit()") - - if len(propList) > 0: - self.document.getroot().set("onload", listToPropStr(propList)) - else: - if self.document.getroot().get("onload"): - del self.document.getroot().attrib["onload"] - - # Remove effect attributes, if so desired. - if self.options.remove_effects: - for node in self.document.xpath("//*[@jessyink:effectIn]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"] - - for node in self.document.xpath("//*[@jessyink:effectOut]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"] - - # Remove old style attributes as well. - for node in self.document.xpath("//*[@jessyInk_effectIn]", namespaces=inkex.NSS): - del node.attrib["jessyInk_effectIn"] - - for node in self.document.xpath("//*[@jessyInk_effectOut]", namespaces=inkex.NSS): - del node.attrib["jessyInk_effectOut"] - - # Remove master slide assignment, if so desired. - if self.options.remove_masterSlide: - for node in self.document.xpath("//*[@jessyink:masterSlide]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}masterSlide"] - - # Remove old style attributes as well. - for node in self.document.xpath("//*[@jessyInk_masterSlide]", namespaces=inkex.NSS): - del node.attrib["jessyInk_masterSlide"] - - # Remove transitions, if so desired. - if self.options.remove_transitions: - for node in self.document.xpath("//*[@jessyink:transitionIn]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}transitionIn"] - - for node in self.document.xpath("//*[@jessyink:transitionOut]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}transitionOut"] - - # Remove old style attributes as well. - for node in self.document.xpath("//*[@jessyInk_transitionIn]", namespaces=inkex.NSS): - del node.attrib["jessyInk_transitionIn"] - - for node in self.document.xpath("//*[@jessyInk_transitionOut]", namespaces=inkex.NSS): - del node.attrib["jessyInk_transitionOut"] - - # Remove auto texts, if so desired. - if self.options.remove_autoTexts: - for node in self.document.xpath("//*[@jessyink:autoText]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}autoText"] - - # Remove old style attributes as well. - for node in self.document.xpath("//*[@jessyInk_autoText]", namespaces=inkex.NSS): - del node.attrib["jessyInk_autoText"] - - # Remove views, if so desired. - if self.options.remove_views: - for node in self.document.xpath("//*[@jessyink:view]", namespaces=inkex.NSS): - del node.attrib["{" + inkex.NSS["jessyink"] + "}view"] - -# Create effect instance. -effect = JessyInk_Uninstall() -effect.affect() - diff --git a/share/extensions/jessyInk_video.inx b/share/extensions/jessyInk_video.inx deleted file mode 100644 index 59c68114d..000000000 --- a/share/extensions/jessyInk_video.inx +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Video</_name> - <id>jessyink.core.video</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_video.py</dependency> - <param name="tab" type="notebook"> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension puts a JessyInk video element on the current slide (layer). This element allows you to integrate a video into your JessyInk presentation. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_video.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_video.py b/share/extensions/jessyInk_video.py deleted file mode 100755 index bd20d837f..000000000 --- a/share/extensions/jessyInk_video.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex -import os -import re -from lxml import etree -from copy import deepcopy - -class JessyInk_Effects(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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: - 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): - 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') - tmplRoot = etree.fromstring(tmplFile.read()) - tmplFile.close() - - elem = deepcopy(tmplRoot.xpath("//svg:g[@jessyink:element='core.video']", namespaces=inkex.NSS)[0]) - nodeDict = findInternalLinks(elem, tmplRoot) - - deleteIds(elem) - - idSubst = {} - - for key in nodeDict: - idSubst[key] = getNewId("jessyink.core.video", self.document) - deleteIds(nodeDict[key]) - nodeDict[key].attrib['id'] = idSubst[key] - elem.insert(0, nodeDict[key]) - - for ndIter in elem.iter(): - for attrIter in ndIter.attrib: - for entryIter in idSubst: - ndIter.attrib[attrIter] = ndIter.attrib[attrIter].replace("#" + entryIter, "#" + idSubst[entryIter]) - - # Append element. - layer[0].append(elem) - -def findInternalLinks(node, docRoot, nodeDict = {}): - for entry in re.findall("url\(#.*\)", etree.tostring(node)): - linkId = entry[5:len(entry) - 1] - - if not nodeDict.has_key(linkId): - nodeDict[linkId] = deepcopy(docRoot.xpath("//*[@id='" + linkId + "']", namespaces=inkex.NSS)[0]) - nodeDict = findInternalLinks(nodeDict[linkId], docRoot, nodeDict) - - for entry in node.iter(): - if entry.attrib.has_key('{' + inkex.NSS['xlink'] + '}href'): - linkId = entry.attrib['{' + inkex.NSS['xlink'] + '}href'][1:len(entry.attrib['{' + inkex.NSS['xlink'] + '}href'])] - - if not nodeDict.has_key(linkId): - nodeDict[linkId] = deepcopy(docRoot.xpath("//*[@id='" + linkId + "']", namespaces=inkex.NSS)[0]) - nodeDict = findInternalLinks(nodeDict[linkId], docRoot, nodeDict) - - return nodeDict - -def getNewId(prefix, docRoot): - import datetime - - number = datetime.datetime.now().microsecond - - while len(docRoot.xpath("//*[@id='" + prefix + str(number) + "']", namespaces=inkex.NSS)) > 0: - number += 1 - - return prefix + str(number) - -def deleteIds(node): - for entry in node.iter(): - if entry.attrib.has_key('id'): - del entry.attrib['id'] - -# Create effect instance -effect = JessyInk_Effects() -effect.affect() - diff --git a/share/extensions/jessyInk_video.svg b/share/extensions/jessyInk_video.svg deleted file mode 100644 index 1d9e75506..000000000 --- a/share/extensions/jessyInk_video.svg +++ /dev/null @@ -1,596 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:jessyink="https://launchpad.net/jessyink" - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="478.3808" - height="320.73016" - id="svg2" - sodipodi:version="0.32" - inkscape:version="0.47 r22583" - version="1.0" - sodipodi:docname="jessyInk_video.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4"> - <linearGradient - id="linearGradient3654"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop3656" /> - <stop - style="stop-color:#bebebe;stop-opacity:1;" - offset="1" - id="stop3658" /> - </linearGradient> - <linearGradient - id="linearGradient3398"> - <stop - style="stop-color:#d6d6d6;stop-opacity:1;" - offset="0" - id="stop3400" /> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="1" - id="stop3402" /> - </linearGradient> - <linearGradient - id="linearGradient3388"> - <stop - style="stop-color:#dfdfdf;stop-opacity:1;" - offset="0" - id="stop3390" /> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="1" - id="stop3392" /> - </linearGradient> - <linearGradient - id="linearGradient3327"> - <stop - style="stop-color:#859df1;stop-opacity:1;" - offset="0" - id="stop3329" /> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="1" - id="stop3331" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2953" - id="linearGradient2985" - x1="154.24722" - y1="110.70377" - x2="134.85132" - y2="87.365448" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.9962198,-0.08686864,0.08686864,0.9962198,-7.0296853,12.597208)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2953" - id="linearGradient2977" - x1="129.11227" - y1="115.96979" - x2="120.07692" - y2="96.278084" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(0.441989,-0.2209945)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2953" - id="linearGradient2968" - x1="110.75861" - y1="116.03537" - x2="106.21297" - y2="98.169502" - gradientUnits="userSpaceOnUse" /> - <linearGradient - id="linearGradient2953"> - <stop - style="stop-color:#2502ff;stop-opacity:1;" - offset="0" - id="stop2955" /> - <stop - style="stop-color:#a8a5ff;stop-opacity:1;" - offset="1" - id="stop2958" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2953" - id="linearGradient2960" - x1="108.78014" - y1="92.046555" - x2="104.73283" - y2="88.124817" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2913" - id="linearGradient2919" - x1="35.085781" - y1="55.376659" - x2="25.629274" - y2="92.503731" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.8103484,0,0,0.8087248,2.2289552,16.936481)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2913" - id="linearGradient2927" - x1="118.00729" - y1="86.390717" - x2="156.74582" - y2="86.390717" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.8103484,0,0,0.8087248,14.383651,12.295597)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2913" - id="linearGradient2943" - x1="81.277565" - y1="68.547112" - x2="91.105675" - y2="91.024132" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7897017,-0.1817575,0.1813933,0.7881194,-4.8653748,24.856814)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2913" - id="linearGradient2935" - x1="117.19492" - y1="96.566895" - x2="108.4378" - y2="77.16523" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.8103484,0,0,0.8087248,11.876496,9.4552995)" /> - <linearGradient - id="linearGradient2913"> - <stop - style="stop-color:#f1ff1d;stop-opacity:1;" - offset="0" - id="stop2915" /> - <stop - style="stop-color:#fba100;stop-opacity:1" - offset="1" - id="stop2917" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2913" - id="linearGradient2951" - x1="34.869572" - y1="85.162331" - x2="69.447136" - y2="85.162331" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.8103484,0,0,0.8087248,11.67459,15.220437)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2955" - id="linearGradient2970" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.0574713,0,0,1.0581729,53.099639,13.989279)" - x1="22.693371" - y1="28.950274" - x2="108.57735" - y2="84.930939" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2955" - id="linearGradient2966" - gradientUnits="userSpaceOnUse" - x1="22.693371" - y1="28.950274" - x2="108.57735" - y2="84.930939" - gradientTransform="matrix(1.0511003,0,0,1.0517241,27.50652,1.2611923)" /> - <linearGradient - id="linearGradient2955"> - <stop - style="stop-color:#fbfcff;stop-opacity:1;" - offset="0" - id="stop2957" /> - <stop - style="stop-color:#5258ef;stop-opacity:1;" - offset="1" - id="stop2959" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2955" - id="linearGradient2972" - gradientUnits="userSpaceOnUse" - x1="22.693371" - y1="28.950274" - x2="108.57735" - y2="84.930939" - gradientTransform="translate(1.5469614,-10.38674)" /> - <inkscape:perspective - sodipodi:type="inkscape:persp3d" - inkscape:vp_x="0 : 526.18109 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_z="744.09448 : 526.18109 : 1" - inkscape:persp3d-origin="372.04724 : 350.78739 : 1" - id="perspective10" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2955" - id="linearGradient3333" - x1="347.24408" - y1="126.14174" - x2="400.7677" - y2="267.53937" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(8.5039369,12.755905)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3388" - id="radialGradient3433" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.4883686,0.6863398,-0.5578719,-0.3969566,490.07776,437.40628)" - cx="176.60922" - cy="402.68719" - fx="176.60922" - fy="402.68719" - r="30.22246" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3435" - gradientUnits="userSpaceOnUse" - x1="183.88486" - y1="434.88504" - x2="177.69821" - y2="413.2713" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3437" - gradientUnits="userSpaceOnUse" - x1="211.84167" - y1="415.36514" - x2="198.24878" - y2="405.86191" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3447" - x1="323.48425" - y1="440.07874" - x2="308.64169" - y2="331.98819" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.9709646,0,0,0.7586207,2.3456911,80.73853)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3521" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.1652108,0,0,1.3041467,-12.256157,-100.64265)" - x1="323.48425" - y1="440.07874" - x2="308.64169" - y2="331.98819" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3388" - id="radialGradient3523" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.4883686,0.6863398,-0.5578719,-0.3969566,490.07776,437.40628)" - cx="176.60922" - cy="402.68719" - fx="176.60922" - fy="402.68719" - r="30.22246" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3525" - gradientUnits="userSpaceOnUse" - x1="183.88486" - y1="434.88504" - x2="177.69821" - y2="413.2713" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3398" - id="linearGradient3527" - gradientUnits="userSpaceOnUse" - x1="211.84167" - y1="415.36514" - x2="198.24878" - y2="405.86191" /> - <inkscape:perspective - id="perspective2914" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective2885" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <inkscape:perspective - id="perspective4492" - inkscape:persp3d-origin="0.5 : 0.33333333 : 1" - inkscape:vp_z="1 : 0.5 : 1" - inkscape:vp_y="0 : 1000 : 0" - inkscape:vp_x="0 : 0.5 : 1" - sodipodi:type="inkscape:persp3d" /> - <linearGradient - id="linearGradient4061"> - <stop - style="stop-color:#cccccc;stop-opacity:1;" - offset="0" - id="stop4063" /> - <stop - style="stop-color:#686868;stop-opacity:1;" - offset="1" - id="stop4065" /> - </linearGradient> - <linearGradient - id="linearGradient4501"> - <stop - style="stop-color:#cccccc;stop-opacity:1;" - offset="0" - id="stop4503" /> - <stop - style="stop-color:#686868;stop-opacity:1;" - offset="1" - id="stop4505" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient4482" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.0793653,1.1633659,-0.39752037,0.710516,-120.33298,7.3257338)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <linearGradient - id="linearGradient4508"> - <stop - style="stop-color:#cccccc;stop-opacity:1;" - offset="0" - id="stop4510" /> - <stop - style="stop-color:#686868;stop-opacity:1;" - offset="1" - id="stop4512" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3811" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-210.78387,-103.79557)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3813" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-196.85663,-8.8111487)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3815" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-182.92939,86.173254)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3843" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-210.78387,-103.79557)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3845" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-196.85663,-8.8111487)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="radialGradient3847" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.2261425,0.84939356,-0.2902365,0.76066958,-182.92939,86.173254)" - cx="267.89597" - cy="424.69434" - fx="267.89597" - fy="424.69434" - r="50.740894" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3654" - id="linearGradient3660" - x1="255.21498" - y1="420.35464" - x2="322.05756" - y2="475.00314" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3654" - id="linearGradient3668" - x1="252.90028" - y1="515.85352" - x2="319.14331" - y2="564.18585" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3654" - id="linearGradient3676" - x1="254.72079" - y1="615.9538" - x2="317.50601" - y2="661.42786" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - gridtolerance="10000" - guidetolerance="10" - objecttolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:zoom="1.5433534" - inkscape:cx="239.1904" - inkscape:cy="160.36508" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="1268" - inkscape:window-height="746" - inkscape:window-x="0" - inkscape:window-y="25" - showborder="true" - inkscape:showpageshadow="false" - borderlayer="true" - inkscape:window-maximized="0" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-255.05484,-196.27865)"> - <g - id="g2879" - transform="translate(-434.78725,69.112709)" - jessyink:element="core.video"> - <jessyink:video /> - <rect - style="fill:#b3b3b3;fill-opacity:1;stroke:none" - id="rect2961" - width="400" - height="250" - x="767.70032" - y="198.79166" - rx="0" - ry="0" - jessyink:video="rect" - transform="matrix(0.99999932,-0.00116615,0.00116615,0.99999932,0,0)" /> - <rect - style="font-size:20px;fill:#dfdfdf;fill-opacity:1;stroke:#000000;stroke-width:3.48164916;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="rect2927" - width="388.22516" - height="75.056519" - x="737.79498" - y="175.88173" - rx="12" - ry="11.999999" - sodipodi:insensitive="true" /> - <text - xml:space="preserve" - style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" - x="788.77039" - y="234.86638" - id="text2886" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan2888" - x="788.77039" - y="234.86638" - jessyink:video="url"><replace this text with the url of the movie></tspan></text> - <g - transform="matrix(0.35587188,0.26994219,-0.26994219,0.35587188,800.78552,-70.706091)" - id="g4309" - sodipodi:insensitive="true"> - <path - style="fill:#000000;fill-opacity:1;stroke:none" - d="m 209.78125,112.53125 0,290.65625 5.25,0 0,-4.21875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 l 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,4.21875 113,0 0,-4.21875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 l 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,4.21875 5.03125,0 0,-290.65625 -5.03125,0 0,3.34375 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-3.34375 -113,0 0,3.34375 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-3.34375 -5.25,0 z m 8.59375,13.09375 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.3125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.5013 3.3125,3.34375 l 0,6.1875 c 0,1.84245 -1.47005,3.34375 -3.3125,3.34375 l -8.34375,0 c -1.84245,0 -3.34375,-1.5013 -3.34375,-3.34375 l 0,-6.1875 c 0,-1.84245 1.5013,-3.34375 3.34375,-3.34375 z m -128,19.3125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m -128,19.28125 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z m 128,0 8.34375,0 c 1.84245,0 3.3125,1.47005 3.3125,3.3125 l 0,6.21875 c 0,1.84245 -1.47005,3.3125 -3.3125,3.3125 l -8.34375,0 c -1.84245,0 -3.34375,-1.47005 -3.34375,-3.3125 l 0,-6.21875 c 0,-1.84245 1.5013,-3.3125 3.34375,-3.3125 z" - id="path4311" - transform="translate(0,284.36221)" /> - <rect - style="fill:url(#linearGradient3660);fill-opacity:1;stroke:none" - id="rect4313" - width="101.48179" - height="82.622345" - x="235.6795" - y="405.14673" /> - <rect - style="fill:url(#linearGradient3668);fill-opacity:1;stroke:none" - id="rect4315" - width="101.48179" - height="82.622345" - x="235.6795" - y="501.14676" /> - <rect - y="597.14679" - x="235.6795" - height="82.622345" - width="101.48179" - id="rect4317" - style="fill:url(#linearGradient3676);fill-opacity:1;stroke:none" /> - </g> - <text - xml:space="preserve" - style="font-size:20px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" - x="811.12927" - y="205.86632" - id="text3701" - sodipodi:linespacing="125%" - sodipodi:insensitive="true"><tspan - sodipodi:role="line" - id="tspan3703" - x="811.12927" - y="205.86632">JessyInk video element</tspan></text> - </g> - </g> -</svg> diff --git a/share/extensions/jessyInk_view.inx b/share/extensions/jessyInk_view.inx deleted file mode 100644 index 06fc08bc5..000000000 --- a/share/extensions/jessyInk_view.inx +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>View</_name> - <id>jessyink.view</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">jessyInk_view.py</dependency> - <param name="tab" type="notebook"> - <page name="settings" _gui-text="Settings"> - <param name="viewOrder" type="int" min="0" max="100" _gui-text="Order:">1</param> - <param name="viewDuration" precision="1" type="float" min="0.1" max="10.0" _gui-text="Duration in seconds:">0.8</param> - <param name="removeView" type="boolean" _gui-text="Remove view">false</param> - <_param name="help_text" type="description">Choose order number 0 to set the initial view of a slide.</_param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">This extension allows you to set, update and remove views for a JessyInk presentation. Please see code.google.com/p/jessyink for more details.</_param> - </page> - </param> - <effect> - <object-type>rect</object-type> - <effects-menu> - <submenu _name="JessyInk"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">jessyInk_view.py</command> - </script> -</inkscape-extension> - diff --git a/share/extensions/jessyInk_view.py b/share/extensions/jessyInk_view.py deleted file mode 100755 index 37a30758f..000000000 --- a/share/extensions/jessyInk_view.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# Copyright 2008, 2009 Hannes Hochreiner -# 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 3 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, see http://www.gnu.org/licenses/. - -# These lines are only needed if you don't put the script directly into -# the installation directory -import sys -# Unix -sys.path.append('/usr/share/inkscape/extensions') -# OS X -sys.path.append('/Applications/Inkscape.app/Contents/Resources/extensions') -# Windows -sys.path.append('C:\Program Files\Inkscape\share\extensions') - -# We will use the inkex module with the predefined Effect base class. -import inkex - - -def propStrToList(str): - list = [] - propList = str.split(";") - for prop in propList: - if not (len(prop) == 0): - list.append(prop.strip()) - return list - -def propListToDict(list): - dictio = {} - - for prop in list: - keyValue = prop.split(":") - - if len(keyValue) == 2: - dictio[keyValue[0].strip()] = keyValue[1].strip() - - return dictio - -class JessyInk_Effects(inkex.Effect): - def __init__(self): - # Call the base class constructor. - inkex.Effect.__init__(self) - - self.OptionParser.add_option('--tab', action = 'store', type = 'string', dest = 'what') - self.OptionParser.add_option('--viewOrder', action = 'store', type = 'string', dest = 'viewOrder', default = 1) - self.OptionParser.add_option('--viewDuration', action = 'store', type = 'float', dest = 'viewDuration', default = 0.8) - self.OptionParser.add_option('--removeView', action = 'store', type = 'inkbool', dest = 'removeView', default = False) - - inkex.NSS[u"jessyink"] = u"https://launchpad.net/jessyink" - - def effect(self): - # Check version. - scriptNodes = self.document.xpath("//svg:script[@jessyink:version='1.5.5']", namespaces=inkex.NSS) - - if len(scriptNodes) != 1: - 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 - - for id, node in self.selected.items(): - if rect == None: - rect = node - else: - inkex.errormsg(_("More than one object selected. Please select only one object.\n")) - exit() - - if rect == None: - 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: - # Remove the view that currently has the requested order number. - for node in rect.xpath("ancestor::svg:g[@inkscape:groupmode='layer']/descendant::*[@jessyink:view]", namespaces=inkex.NSS): - propDict = propListToDict(propStrToList(node.attrib["{" + inkex.NSS["jessyink"] + "}view"])) - - if propDict["order"] == self.options.viewOrder: - del node.attrib["{" + inkex.NSS["jessyink"] + "}view"] - - # Set the new view. - rect.set("{" + inkex.NSS["jessyink"] + "}view","name:view;order:" + self.options.viewOrder + ";length:" + str(int(self.options.viewDuration * 1000))) - - # Remove possible effect arguments. - if rect.attrib.has_key("{" + inkex.NSS["jessyink"] + "}effectIn"): - del rect.attrib["{" + inkex.NSS["jessyink"] + "}effectIn"] - - if rect.attrib.has_key("{" + inkex.NSS["jessyink"] + "}effectOut"): - del rect.attrib["{" + inkex.NSS["jessyink"] + "}effectOut"] - else: - if node.attrib.has_key("{" + inkex.NSS["jessyink"] + "}view"): - del node.attrib["{" + inkex.NSS["jessyink"] + "}view"] - -# Create effect instance -effect = JessyInk_Effects() -effect.affect() - diff --git a/share/extensions/jitternodes.inx b/share/extensions/jitternodes.inx deleted file mode 100644 index 817fbd276..000000000 --- a/share/extensions/jitternodes.inx +++ /dev/null @@ -1,33 +0,0 @@ -<?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.jitternodes</id> - <dependency type="executable" location="extensions">jitternodes.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="dist" type="enum" _gui-text="Distribution of the displacements:"> - <_item value="Uniform">Uniform</_item> - <_item value="Pareto">Pareto</_item> - <_item value="Gaussian">Gaussian</_item> - <_item value="Lognorm">Log-normal</_item> - </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">jitternodes.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/jitternodes.py b/share/extensions/jitternodes.py deleted file mode 100755 index fbb1d00d6..000000000 --- a/share/extensions/jitternodes.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2012 Juan Pablo Carbajal ajuanpi-dev@gmail.com -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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import random, math, inkex, cubicsuperpath - -def randomize((x, y), rx, ry, dist): - - if dist == "Gaussian": - r1 = random.gauss(0.0,rx) - r2 = random.gauss(0.0,ry) - elif dist == "Pareto": - ''' - sign is used to fake a double sided pareto distribution. - for parameter value between 1 and 2 the distribution has infinite variance - I truncate the distribution to a high value and then normalize it. - The idea is to get spiky distributions, any distribution with long-tails is - good (ideal would be Levy distribution). - ''' - sign = random.uniform(-1.0,1.0) - - r1 = min(random.paretovariate(1.0), 20.0)/20.0 - r2 = min(random.paretovariate(1.0), 20.0)/20.0 - - r1 = rx * math.copysign(r1, sign) - r2 = ry * math.copysign(r2, sign) - elif dist == "Lognorm": - sign = random.uniform(-1.0,1.0) - r1 = rx * math.copysign(random.lognormvariate(0.0,1.0)/3.5,sign) - r2 = ry * math.copysign(random.lognormvariate(0.0,1.0)/3.5,sign) - elif dist == "Uniform": - r1 = random.uniform(-rx,rx) - r2 = random.uniform(-ry,ry) - - x += r1 - y += r2 - - return [x, y] - -class JitterNodes(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--title") - self.OptionParser.add_option("-x", "--radiusx", - action="store", type="float", - dest="radiusx", default=10.0, - help="Randomly move nodes and handles within this radius, X") - self.OptionParser.add_option("-y", "--radiusy", - action="store", type="float", - dest="radiusy", default=10.0, - help="Randomly move nodes and handles within this radius, Y") - self.OptionParser.add_option("-c", "--ctrl", - action="store", type="inkbool", - dest="ctrl", default=True, - help="Randomize control points") - self.OptionParser.add_option("-e", "--end", - action="store", type="inkbool", - dest="end", default=True, - help="Randomize nodes") - self.OptionParser.add_option("-d", "--dist", - action="store", type="string", - dest="dist", default="Uniform", - help="Choose the distribution of the displacements") - 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'): - d = node.get('d') - p = cubicsuperpath.parsePath(d) - for subpath in p: - for csp in subpath: - if self.options.end: - delta=randomize([0,0], self.options.radiusx, self.options.radiusy, self.options.dist) - csp[0][0]+=delta[0] - csp[0][1]+=delta[1] - csp[1][0]+=delta[0] - csp[1][1]+=delta[1] - csp[2][0]+=delta[0] - csp[2][1]+=delta[1] - if self.options.ctrl: - csp[0]=randomize(csp[0], self.options.radiusx, self.options.radiusy, self.options.dist) - csp[2]=randomize(csp[2], self.options.radiusx, self.options.radiusy, self.options.dist) - node.set('d',cubicsuperpath.formatPath(p)) - -if __name__ == '__main__': - e = JitterNodes() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/launch_webbrowser.py b/share/extensions/launch_webbrowser.py deleted file mode 100755 index fb2ccfd87..000000000 --- a/share/extensions/launch_webbrowser.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# standard library -import webbrowser -import threading -from optparse import OptionParser -# local library -import inkex - -class VisitWebSiteWithoutLockingInkscape(threading.Thread): - def __init__(self): - threading.Thread.__init__ (self) - parser = OptionParser() - parser.add_option("-u", "--url", action="store", type="string", - default="https://www.inkscape.org/", - dest="url", help="The URL to open in web browser") - (self.options, args) = parser.parse_args() - - def run(self): - inkex.localize() - webbrowser.open(_(self.options.url)) - -vwswli = VisitWebSiteWithoutLockingInkscape() -vwswli.start() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/layers2svgfont.inx b/share/extensions/layers2svgfont.inx deleted file mode 100644 index 40b0b90db..000000000 --- a/share/extensions/layers2svgfont.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>3 - Convert Glyph Layers to SVG Font</_name> - <id>org.inkscape.typography.layers2svgfont</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">simplepath.py</dependency> - <dependency type="executable" location="extensions">layers2svgfont.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">layers2svgfont.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/layers2svgfont.py b/share/extensions/layers2svgfont.py deleted file mode 100755 index e449ae380..000000000 --- a/share/extensions/layers2svgfont.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches <juca@members.fsf.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import sys -import simplepath - -class Layers2SVGFont(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def guideline_value(self, label, index): - namedview = self.svg.find(inkex.addNS('namedview', 'sodipodi')) - guides = namedview.findall(inkex.addNS('guide', 'sodipodi')) - for guide in guides: - l=guide.get(inkex.addNS('label', 'inkscape')) - if l==label: - return int(guide.get("position").split(",")[index]) - return 0 - - def get_or_create(self, parentnode, nodetype): - node = parentnode.find(nodetype) - if node is None: - node = inkex.etree.SubElement(parentnode, nodetype) - return node - - def get_or_create_glyph(self, font, unicode_char): - glyphs = font.findall(inkex.addNS('glyph', 'svg')) - for glyph in glyphs: - if unicode_char == glyph.get("unicode"): - return glyph - return inkex.etree.SubElement(font, inkex.addNS('glyph', 'svg')) - - def flip_cordinate_system(self, d, emsize, baseline): - pathdata = simplepath.parsePath(d) - simplepath.scalePath(pathdata, 1,-1) - simplepath.translatePath(pathdata, 0, int(emsize) - int(baseline)) - return simplepath.formatPath(pathdata) - - def effect(self): - # Get access to main SVG document element - self.svg = self.document.getroot() - self.defs = self.get_or_create(self.svg, inkex.addNS('defs', 'svg')) - - emsize = int(self.svg.get("width")) - baseline = self.guideline_value("baseline", 1) - ascender = self.guideline_value("ascender", 1) - baseline - caps = self.guideline_value("caps", 1) - baseline - xheight = self.guideline_value("xheight", 1) - baseline - descender = baseline - self.guideline_value("descender", 1) - - font = self.get_or_create(self.defs, inkex.addNS('font', 'svg')) - font.set("horiz-adv-x", str(emsize)) - font.set("horiz-origin-y", str(baseline)) - - fontface = self.get_or_create(font, inkex.addNS('font-face', 'svg')) - fontface.set("font-family", "SVGFont") - fontface.set("units-per-em", str(emsize)) - fontface.set("cap-height", str(caps)) - fontface.set("x-height", str(xheight)) - fontface.set("ascent", str(ascender)) - fontface.set("descent", str(descender)) - - groups = self.svg.findall(inkex.addNS('g', 'svg')) - for group in groups: - label = group.get(inkex.addNS('label', 'inkscape')) - if "GlyphLayer-" in label: - unicode_char = label.split("GlyphLayer-")[1] - glyph = self.get_or_create_glyph(font, unicode_char) - glyph.set("unicode", unicode_char) - - ############################ - #Option 1: - # Using clone (svg:use) as childnode of svg:glyph - - #use = self.get_or_create(glyph, inkex.addNS('use', 'svg')) - #use.set(inkex.addNS('href', 'xlink'), "#"+group.get("id")) - #TODO: This code creates <use> nodes but they do not render on svg fonts dialog. why? - - ############################ - #Option 2: - # Using svg:paths as childnodes of svg:glyph - - #paths = group.findall(inkex.addNS('path', 'svg')) - #for p in paths: - # d = p.get("d") - # d = self.flip_cordinate_system(d, emsize, baseline) - # path = inkex.etree.SubElement(glyph, inkex.addNS('path', 'svg')) - # path.set("d", d) - - ############################ - #Option 3: - # Using curve description in d attribute of svg:glyph - - paths = group.findall(inkex.addNS('path', 'svg')) - d = "" - for p in paths: - d += " " + self.flip_cordinate_system(p.get("d"), emsize, baseline) - glyph.set("d", d) - -if __name__ == '__main__': - e = Layers2SVGFont() - e.affect() - diff --git a/share/extensions/layout_nup.inx b/share/extensions/layout_nup.inx deleted file mode 100644 index 1d4d1ef0f..000000000 --- a/share/extensions/layout_nup.inx +++ /dev/null @@ -1,78 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>N-up layout</_name> - <id>org.greygreen.inkscape.effects.nup</id> - <dependency type="executable" location="extensions">layout_nup.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="tab" type="notebook"> - <page name="pageDims" _gui-text="Page dimensions"> - <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="pgSizeX" type="float" min="0.0" max="9999.0" _gui-text="Size X:">816</param> - <param name="pgSizeY" type="float" min="0.0" max="9999.0" _gui-text="Size Y:">1056</param> - <_param name="pgMargin" type="description" appearance="header">Page margins</_param> - <param name="pgMarginTop" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Top:">0</param> - <param name="pgMarginBottom" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Bottom:">0</param> - <param name="pgMarginLeft" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Left:">0</param> - <param name="pgMarginRight" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Right:">0</param> - </page> - <page name="layoutDims" _gui-text="Layout dimensions"> - <param name="rows" type="int" min="1" max="9999" _gui-text="Rows:">2</param> - <param name="cols" type="int" min="1" max="9999" _gui-text="Cols:">2</param> - <param name="sizeX" type="float" min="1" max="9999" _gui-text="Size X:">100</param> - <param name="sizeY" type="float" min="1" max="9999" _gui-text="Size Y:">200</param> - <param name="calculateSize" type="boolean" _gui-text="Auto calculate layout size">true</param> - <_param name="padding" type="description" appearance="header">Layout padding</_param> - <param name="paddingTop" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Top:">12</param> - <param name="paddingBottom" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Bottom:">12</param> - <param name="paddingLeft" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Left:">12</param> - <param name="paddingRight" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Right:">12</param> - <_param name="margin" type="description" appearance="header">Layout margins</_param> - <param name="marginTop" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Top:">0</param> - <param name="marginBottom" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Bottom:">0</param> - <param name="marginLeft" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Left:">0</param> - <param name="marginRight" type="float" indent="1" min="0.0" max="9999.0" _gui-text="Right:">0</param> - </page> - <page name="marks" _gui-text="Marks"> - <param name="showHolder" type="boolean" _gui-text="Place holder">true</param> - <param name="showCrosses" type="boolean" _gui-text="Cutting marks">true</param> - <param name="showInner" type="boolean" _gui-text="Padding guide">true</param> - <param name="showOuter" type="boolean" _gui-text="Margin guide">false</param> - <param name="showInnerBox" type="boolean" _gui-text="Padding box">false</param> - <param name="showOuterBox" type="boolean" _gui-text="Margin box">0</param> - </page> - <page name="help" _gui-text="Help"> - <_param name="instructions" type="description" xml:space="preserve"> -Parameters: - * Page size: width and height. - * Page margins: extra space around each page. - * Layout rows and cols. - * Layout size: width and height, auto calculated if one is 0. - * Auto calculate layout size: don't use the layout size values. - * Layout margins: white space around each part of the layout. - * Layout padding: inner padding for each part of the layout. - </_param> - </page> - </param> - - <effect needs-live-preview="true"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Layout"/> - </submenu> - </effects-menu> - </effect> - - <script> - <command reldir="extensions" interpreter="python">layout_nup.py</command> - </script> -</inkscape-extension> - - diff --git a/share/extensions/layout_nup.py b/share/extensions/layout_nup.py deleted file mode 100755 index 022aa0d3f..000000000 --- a/share/extensions/layout_nup.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 Terry Brown, terry_n_brown@yahoo.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex -import sys - -try: - import xml.etree.ElementTree as ElementTree -except: - try: - from lxml import etree as ElementTree - except: - try: - from elementtree.ElementTree import ElementTree - except: - sys.stderr.write("""Requires ElementTree module, included -in Python 2.5 or supplied by lxml or elementtree modules. - -""") - -class Nup(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - opts = [('', '--unit', 'string', 'unit', 'px', ''), - ('', '--rows', 'int', 'rows', '2', ''), - ('', '--cols', 'int', 'cols', '2', ''), - ('', '--paddingTop', 'string', 'paddingTop', '', ''), - ('', '--paddingBottom', 'string', 'paddingBottom', '', ''), - ('', '--paddingLeft', 'string', 'paddingLeft', '', ''), - ('', '--paddingRight', 'string', 'paddingRight', '', ''), - ('', '--marginTop', 'string', 'marginTop', '', ''), - ('', '--marginBottom', 'string', 'marginBottom', '', ''), - ('', '--marginLeft', 'string', 'marginLeft', '', ''), - ('', '--marginRight', 'string', 'marginRight', '', ''), - ('', '--pgSizeX', 'string', 'pgSizeX', '', ''), - ('', '--pgSizeY', 'string', 'pgSizeY', '', ''), - ('', '--sizeX', 'string', 'sizeX', '', ''), - ('', '--sizeY', 'string', 'sizeY', '', ''), - ('', '--calculateSize', 'inkbool', 'calculateSize', True, ''), - ('', '--pgMarginTop', 'string', 'pgMarginTop', '', ''), - ('', '--pgMarginBottom', 'string', 'pgMarginBottom', '', ''), - ('', '--pgMarginLeft', 'string', 'pgMarginLeft', '', ''), - ('', '--pgMarginRight', 'string', 'pgMarginRight', '', ''), - ('', '--showHolder', 'inkbool', 'showHolder', True, ''), - ('', '--showCrosses', 'inkbool', 'showCrosses', True, ''), - ('', '--showInner', 'inkbool', 'showInner', True, ''), - ('', '--showOuter', 'inkbool', 'showOuter', False, ''), - ('', '--showInnerBox', 'inkbool', 'showInnerBox', False, ''), - ('', '--showOuterBox', 'inkbool', 'showOuterBox', False, ''), - ('', '--tab', 'string', 'tab', '', ''), - ] - for o in opts: - self.OptionParser.add_option(o[0], o[1], action="store", type=o[2], - dest=o[3], default=o[4], help=o[5]) - - - def effect(self): - showList = [] - for i in ['showHolder','showCrosses','showInner','showOuter', - 'showInnerBox','showOuterBox',]: - if getattr(self.options, i): - showList.append(i.lower().replace('show', '')) - o = self.options - self.pf = self.GenerateNup( - unit=o.unit, - pgSize=(o.pgSizeX,o.pgSizeY), - pgMargin=(o.pgMarginTop,o.pgMarginRight,o.pgMarginBottom,o.pgMarginLeft), - num=(o.rows,o.cols), - calculateSize = o.calculateSize, - size=(o.sizeX,o.sizeY), - margin=(o.marginTop,o.marginRight,o.marginBottom,o.marginLeft), - padding=(o.paddingTop,o.paddingRight,o.paddingBottom,o.paddingLeft), - show=showList, - ) - - def setAttr(self, node, name, value): - attr = node.ownerDocument.createAttribute(name) - attr.value = value - node.attributes.setNamedItem(attr) - - def output(self): - sys.stdout.write(self.pf) - - def expandTuple(self, unit, x, length = 4): - try: - iter(x) - except: - return None - - if len(x) != length: x = x*2 - if len(x) != length: - raise Exception("expandTuple: requires 2 or 4 item tuple") - try: - return tuple(map(lambda ev: (self.unittouu(str(eval(str(ev)))+unit)/self.unittouu('1px')), x)) - except: - return None - - def GenerateNup(self, - unit="px", - pgSize=("8.5*96","11*96"), - pgMargin=(0,0), - pgPadding=(0,0), - num=(2,2), - calculateSize=True, - size=None, - margin=(0,0), - padding=(20,20), - show=['default'], - container='svg', - returnTree = False, - ): - """Generate the SVG. Inputs are run through 'eval(str(x))' so you can use - '8.5*72' instead of 612. Margin / padding dimension tuples can be - (top & bottom, left & right) or (top, right, bottom, left). - - Keyword arguments: - pgSize -- page size, width x height - pgMargin -- extra space around each page - pgPadding -- added to pgMargin - n -- rows x cols - size -- override calculated size, width x height - margin -- white space around each piece - padding -- inner padding for each piece - show -- list of keywords indicating what to show - - 'crosses' - cutting guides - - 'inner' - inner boundary - - 'outer' - outer boundary - container -- 'svg' or 'g' - returnTree -- whether to return the ElementTree or the string - """ - - if 'default' in show: - show = set(show).union(['inner', 'innerbox', 'holder', 'crosses']) - - pgMargin = self.expandTuple(unit, pgMargin) - pgPadding = self.expandTuple(unit, pgPadding) - margin = self.expandTuple(unit, margin) - padding = self.expandTuple(unit, padding) - - pgSize = self.expandTuple(unit, pgSize, length = 2) - # num = tuple(map(lambda ev: eval(str(ev)), num)) - - pgEdge = map(sum,zip(pgMargin, pgPadding)) - - top, right, bottom, left = 0,1,2,3 - width, height = 0,1 - rows, cols = 0,1 - size = self.expandTuple(unit, size, length = 2) - if size == None or calculateSize == True or len(size) < 2 or size[0] == 0 or size[1] == 0: - size = ((pgSize[width] - - pgEdge[left] - pgEdge[right] - - num[cols]*(margin[left] + margin[right])) / num[cols], - (pgSize[height] - - pgEdge[top] - pgEdge[bottom] - - num[rows]*(margin[top] + margin[bottom])) / num[rows] - ) - else: - size = self.expandTuple(unit, size, length = 2) - - # sep is separation between same points on pieces - sep = (size[width]+margin[right]+margin[left], - size[height]+margin[top]+margin[bottom]) - - style = 'stroke:#000000;stroke-opacity:1;fill:none;fill-opacity:1;' - - padbox = 'rect', { - 'x': str(pgEdge[left] + margin[left] + padding[left]), - 'y': str(pgEdge[top] + margin[top] + padding[top]), - 'width': str(size[width] - padding[left] - padding[right]), - 'height': str(size[height] - padding[top] - padding[bottom]), - 'style': style, - } - margbox = 'rect', { - 'x': str(pgEdge[left] + margin[left]), - 'y': str(pgEdge[top] + margin[top]), - 'width': str(size[width]), - 'height': str(size[height]), - 'style': style, - } - - doc = ElementTree.ElementTree(ElementTree.Element(container, - {'xmlns:inkscape':"http://www.inkscape.org/namespaces/inkscape", - 'xmlns:xlink':"http://www.w3.org/1999/xlink", - 'width':str(pgSize[width]), - 'height':str(pgSize[height]), - })) - - sub = ElementTree.SubElement - - root = doc.getroot() - - def makeClones(under, to): - for r in range(0,num[rows]): - for c in range(0,num[cols]): - if r == 0 and c == 0: continue - sub(under, 'use', { - 'xlink:href': '#' + to, - 'transform': 'translate(%f,%f)' % - (c*sep[width], r*sep[height])}) - - # guidelayer ##################################################### - if set(['inner', 'outer']).intersection(show): - layer = sub(root, 'g', {'id':'guidelayer', - 'inkscape:groupmode':'layer'}) - if 'inner' in show: - padbox[1]['id'] = 'innerguide' - padbox[1]['style'] = padbox[1]['style'].replace('stroke:#000000', - 'stroke:#8080ff') - sub(layer, *padbox) - del padbox[1]['id'] - padbox[1]['style'] = padbox[1]['style'].replace('stroke:#8080ff', - 'stroke:#000000') - makeClones(layer, 'innerguide') - if 'outer' in show: - margbox[1]['id'] = 'outerguide' - margbox[1]['style'] = padbox[1]['style'].replace('stroke:#000000', - 'stroke:#8080ff') - sub(layer, *margbox) - del margbox[1]['id'] - margbox[1]['style'] = padbox[1]['style'].replace('stroke:#8080ff', - 'stroke:#000000') - makeClones(layer, 'outerguide') - - # crosslayer ##################################################### - if set(['crosses']).intersection(show): - layer = sub(root, 'g', {'id':'cutlayer', - 'inkscape:groupmode':'layer'}) - - if 'crosses' in show: - crosslen = 12 - group = sub(layer, 'g', id='cross') - x,y = 0,0 - path = 'M%f %f' % (x+pgEdge[left] + margin[left], - y+pgEdge[top] + margin[top]-crosslen) - path += ' L%f %f' % (x+pgEdge[left] + margin[left], - y+pgEdge[top] + margin[top]+crosslen) - path += ' M%f %f' % (x+pgEdge[left] + margin[left]-crosslen, - y+pgEdge[top] + margin[top]) - path += ' L%f %f' % (x+pgEdge[left] + margin[left]+crosslen, - y+pgEdge[top] + margin[top]) - sub(group, 'path', style=style+'stroke-width:0.05', - d = path, id = 'crossmarker') - for r in 0, 1: - for c in 0, 1: - if r or c: - x,y = c*size[width], r*size[height] - sub(group, 'use', { - 'xlink:href': '#crossmarker', - 'transform': 'translate(%f,%f)' % - (x,y)}) - makeClones(layer, 'cross') - - # clonelayer ##################################################### - layer = sub(root, 'g', {'id':'clonelayer', 'inkscape:groupmode':'layer'}) - makeClones(layer, 'main') - - # mainlayer ###################################################### - layer = sub(root, 'g', {'id':'mainlayer', 'inkscape:groupmode':'layer'}) - group = sub(layer, 'g', {'id':'main'}) - - if 'innerbox' in show: - sub(group, *padbox) - if 'outerbox' in show: - sub(group, *margbox) - if 'holder' in show: - x, y = (pgEdge[left] + margin[left] + padding[left], - pgEdge[top] + margin[top] + padding[top]) - w, h = (size[width] - padding[left] - padding[right], - size[height] - padding[top] - padding[bottom]) - path = 'M%f %f' % (x + w/2., y) - path += ' L%f %f' % (x + w, y + h/2.) - path += ' L%f %f' % (x + w/2., y + h) - path += ' L%f %f' % (x, y + h/2.) - path += ' Z' - sub(group, 'path', style=style, d = path) - - if returnTree: - return doc - else: - return ElementTree.tostring(root) - -e = Nup() -e.affect() diff --git a/share/extensions/lindenmayer.inx b/share/extensions/lindenmayer.inx deleted file mode 100644 index 6dba2d5f9..000000000 --- a/share/extensions/lindenmayer.inx +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>L-system</_name> - <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"> -The path is generated by applying the -substitutions of Rules to the Axiom, -Order times. The following commands are -recognized in Axiom and Rules: - -Any of A,B,C,D,E,F: draw forward - -Any of G,H,I,J,K,L: move forward - -+: turn left - --: turn right - -|: turn 180 degrees - -[: remember point - -]: return to remembered point -</_param> - </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> -</inkscape-extension> diff --git a/share/extensions/lindenmayer.py b/share/extensions/lindenmayer.py deleted file mode 100755 index 8e1c4ac22..000000000 --- a/share/extensions/lindenmayer.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplestyle, pturtle, random -from simpletransform import computePointInNode - -def stripme(s): - return s.strip() - -class LSystem(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-o", "--order", - action="store", type="int", - dest="order", default=3, - help="number of iteration") - self.OptionParser.add_option("-l", "--langle", - action="store", type="float", - dest="langle", default=16.0, - help="angle for turning left") - self.OptionParser.add_option("-r", "--rangle", - action="store", type="float", - dest="rangle", default=16.0, - help="angle for turning right") - self.OptionParser.add_option("-s", "--step", - action="store", type="float", - dest="step", default=25.0, - help="step size") - self.OptionParser.add_option("-p", "--randomizestep", - action="store", type="float", - dest="randomizestep", default=0.0, - help="randomize step") - self.OptionParser.add_option("-z", "--randomizeangle", - action="store", type="float", - dest="randomizeangle", default=0.0, - help="randomize angle") - self.OptionParser.add_option("-x", "--axiom", - action="store", type="string", - dest="axiom", default="++F", - help="initial state of system") - self.OptionParser.add_option("-u", "--rules", - action="store", type="string", - dest="rules", default="F=FF-[-F+F+F]+[+F-F-F]", - help="replacement rules") - self.OptionParser.add_option("-t", "--tab", - action="store", type="string", - dest="tab") - self.stack = [] - self.turtle = pturtle.pTurtle() - def iterate(self): - self.rules = dict([map(stripme, i.split("=")) for i in self.options.rules.upper().split(";") if i.count("=")==1]) - string = self.__recurse(self.options.axiom.upper(),0) - self.__compose_path(string) - return self.turtle.getPath() - def __compose_path(self, string): - self.turtle.pu() - self.turtle.setpos(computePointInNode(list(self.view_center), self.current_layer)) - self.turtle.pd() - for c in string: - if c in 'ABCDEF': - self.turtle.pd() - self.turtle.fd(self.options.step * (random.normalvariate(1.0, 0.01 * self.options.randomizestep))) - elif c in 'GHIJKL': - self.turtle.pu() - self.turtle.fd(self.options.step * (random.normalvariate(1.0, 0.01 * self.options.randomizestep))) - elif c == '+': - self.turtle.lt(self.options.langle * (random.normalvariate(1.0, 0.01 * self.options.randomizeangle))) - elif c == '-': - self.turtle.rt(self.options.rangle * (random.normalvariate(1.0, 0.01 * self.options.randomizeangle))) - elif c == '|': - self.turtle.lt(180) - elif c == '[': - self.stack.append([self.turtle.getpos(), self.turtle.getheading()]) - elif c == ']': - self.turtle.pu() - pos,heading = self.stack.pop() - self.turtle.setpos(pos) - self.turtle.setheading(heading) - - def __recurse(self,rule,level): - level_string = '' - for c in rule: - if level < self.options.order: - try: - level_string = level_string + self.__recurse(self.rules[c],level+1) - except KeyError: - level_string = level_string + c - else: - level_string = level_string + c - return level_string - - def effect(self): - self.options.step = self.unittouu(str(self.options.step) + 'px') - s = {'stroke-linejoin': 'miter', 'stroke-width': str(self.unittouu('1px')), - 'stroke-opacity': '1.0', 'fill-opacity': '1.0', - 'stroke': '#000000', 'stroke-linecap': 'butt', - 'fill': 'none'} - attribs = {'style':simplestyle.formatStyle(s),'d':self.iterate()} - inkex.etree.SubElement(self.current_layer,inkex.addNS('path','svg'),attribs) - -if __name__ == '__main__': - e = LSystem() - e.affect() - - -# 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 deleted file mode 100644 index 2833af16c..000000000 --- a/share/extensions/lorem_ipsum.inx +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Lorem ipsum</_name> - <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="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> - <submenu _name="Text"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">lorem_ipsum.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/lorem_ipsum.py b/share/extensions/lorem_ipsum.py deleted file mode 100755 index efb2361ea..000000000 --- a/share/extensions/lorem_ipsum.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jos Hirth, kaioa.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -''' -Example filltext sentences generated over at http://lipsum.com/ -''' - -import inkex -import random - -foo=[ -'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ', -'Duis sem velit, ultrices et, fermentum auctor, rhoncus ut, ligula. ', -'Phasellus at purus sed purus cursus iaculis. ', -'Suspendisse fermentum. ', -'Pellentesque et arcu. ', -'Maecenas viverra. ', -'In consectetuer, lorem eu lobortis egestas, velit odio imperdiet eros, sit amet sagittis nunc mi ac neque. ', -'Sed non ipsum. ', -'Nullam venenatis gravida orci. ', -'Curabitur nunc ante, ullamcorper vel, auctor a, aliquam at, tortor. ', -'Etiam sodales orci nec ligula. ', -'Sed at turpis vitae velit euismod aliquet. ', -'Fusce venenatis ligula in pede. ', -'Pellentesque viverra dolor non nunc. ', -'Donec interdum vestibulum libero. ', -'Morbi volutpat. ', -'Phasellus hendrerit. ', -'Quisque dictum quam vel neque. ', -'Quisque aliquam, nulla ac scelerisque convallis, nisi ligula sagittis risus, at nonummy arcu urna pulvinar nibh. ', -'Nam pharetra. ', -'Nam rhoncus, lectus vel hendrerit congue, nisl lorem feugiat ante, in fermentum erat nulla tristique arcu. ', -'Mauris et dolor. ', -'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec gravida, ante vel ornare lacinia, orci enim porta est, eget sollicitudin lectus lectus eget lacus. ', -'Praesent a lacus vitae turpis consequat semper. ', -'In commodo, dolor quis fermentum ullamcorper, urna massa volutpat massa, vitae mattis purus arcu nec nulla. ', -'In hac habitasse platea dictumst. ', -'Praesent scelerisque. ', -'Nullam sapien mauris, venenatis at, fermentum at, tempus eu, urna. ', -'Vestibulum non arcu a ante feugiat vestibulum. ', -'Nam laoreet dui sed magna. ', -'Proin diam augue, semper vitae, varius et, viverra id, felis. ', -'Pellentesque sit amet dui vel justo gravida auctor. ', -'Aenean scelerisque metus eget sem. ', -'Maecenas rhoncus rhoncus ipsum. ', -'Donec nonummy lacinia leo. ', -'Aenean turpis ipsum, rhoncus vitae, posuere vitae, euismod sed, ligula. ', -'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ', -'Mauris tempus diam. ', -'Maecenas justo. ', -'Sed a lorem ut est tincidunt consectetuer. ', -'Ut eu metus id lectus vestibulum ultrices. ', -'Suspendisse lectus. ', -'Vivamus posuere, ante eu tempor dictum, felis nibh facilisis sem, eu auctor metus nulla non lorem. ', -'Suspendisse potenti. ', -'Integer fringilla. ', -'Morbi urna. ', -'Morbi pulvinar nulla sit amet nisl. ', -'Mauris urna sem, suscipit vitae, dignissim id, ultrices sed, nunc. ', -'Morbi a mauris. ', -'Pellentesque suscipit accumsan massa. ', -'Quisque arcu ante, cursus in, ornare quis, viverra ut, justo. ', -'Quisque facilisis, urna sit amet pulvinar mollis, purus arcu adipiscing velit, non condimentum diam purus eu massa. ', -'Suspendisse potenti. ', -'Phasellus nisi metus, tempus sit amet, ultrices ac, porta nec, felis. ', -'Aliquam metus. ', -'Nam a nunc. ', -'Vivamus feugiat. ', -'Nunc metus. ', -'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eu orci. ', -'Sed elementum, felis quis porttitor sollicitudin, augue nulla sodales sapien, sit amet posuere quam purus at lacus. ', -'Curabitur tincidunt tellus nec purus. ', -'Nam consectetuer mollis dolor. ', -'Sed quis elit. ', -'Aenean luctus vulputate turpis. ', -'Proin lectus orci, venenatis pharetra, egestas id, tincidunt vel, eros. ', -'Nulla facilisi. ', -'Aliquam vel nibh. ', -'Vivamus nisi elit, nonummy id, facilisis non, blandit ac, dolor. ', -'Etiam cursus purus interdum libero. ', -'Nam id neque. ', -'Etiam pede nunc, vestibulum vel, rutrum et, tincidunt eu, enim. ', -'Aenean id purus. ', -'Aenean ultrices turpis. ', -'Mauris et pede. ', -'Suspendisse potenti. ', -'Aliquam velit dui, commodo quis, porttitor eget, convallis et, nisi. ', -'Maecenas convallis dui. ', -'In leo ante, venenatis eu, volutpat ut, imperdiet auctor, enim. ', -'Mauris ac massa vestibulum nisl facilisis viverra. ', -'Phasellus magna sem, vulputate eget, ornare sed, dignissim sit amet, pede. ', -'Aenean justo ipsum, luctus ut, volutpat laoreet, vehicula in, libero. ', -'Praesent semper, neque vel condimentum hendrerit, lectus elit pretium ligula, nec consequat nisl velit at dui. ', -'Proin dolor sapien, adipiscing id, sagittis eu, molestie viverra, mauris. ', -'Aenean ligula. ', -'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse potenti. ', -'Etiam pharetra lacus sed velit imperdiet bibendum. ', -'Nunc in turpis ac lacus eleifend sagittis. ', -'Nam massa turpis, nonummy et, consectetuer id, placerat ac, ante. ', -'In tempus urna. ', -'Quisque vehicula porttitor odio. ', -'Aliquam sed erat. ', -'Vestibulum viverra varius enim. ', -'Donec ut purus. ', -'Pellentesque convallis dolor vel libero. ', -'Integer tempus malesuada pede. ', -'Integer porta. ', -'Donec diam eros, tristique sit amet, pretium vel, pellentesque ut, neque. ', -'Nulla blandit justo a metus. ', -'Curabitur accumsan felis in erat. ', -'Curabitur lorem risus, sagittis vitae, accumsan a, iaculis id, metus. ', -'Nulla sagittis condimentum ligula. ', -'Aliquam imperdiet lobortis metus. ', -'Suspendisse molestie sem. ', -'Ut venenatis. ', -'Pellentesque condimentum felis a sem. ', -'Fusce nonummy commodo dui. ', -'Nullam libero nunc, tristique eget, laoreet eu, sagittis id, ante. ', -'Etiam fermentum. ', -'Phasellus auctor enim eget sem. ', -'Morbi turpis arcu, egestas congue, condimentum quis, tristique cursus, leo. ', -'Sed fringilla. ', -'Nam malesuada sapien eu nibh. ', -'Pellentesque ac turpis. ', -'Nulla sed lacus. ', -'Mauris sed nulla quis nisi interdum tempor. ', -'Quisque pretium rutrum ligula. ', -'Mauris tempor ultrices justo. ', -'In hac habitasse platea dictumst. ', -'Donec sit amet enim. ', -'Suspendisse venenatis. ', -'Nam nisl quam, posuere non, volutpat sed, semper vitae, magna. ', -'Donec ut urna. ', -'Integer risus velit, facilisis eget, viverra et, venenatis id, leo. ', -'Cras facilisis felis sit amet lorem. ', -'Nam molestie nisl at metus. ', -'Suspendisse viverra placerat tortor. ', -'Phasellus lacinia iaculis mi. ', -'Sed dolor. ', -'Quisque malesuada nulla sed pede volutpat pulvinar. ', -'Cras gravida. ', -'Mauris tincidunt aliquam ante. ', -'Fusce consectetuer tellus ut nisl. ', -'Curabitur risus urna, placerat et, luctus pulvinar, auctor vel, orci. ', -'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. ', -'Praesent aliquet, neque pretium congue mattis, ipsum augue dignissim ante, ac pretium nisl lectus at magna. ', -'Vivamus quis mi. ', -'Nam sed nisl nec elit suscipit ullamcorper. ', -'Donec tempus quam quis neque. ', -'Donec rutrum venenatis dui. ', -'Praesent a eros. ', -'Aliquam justo lectus, iaculis a, auctor sed, congue in, nisl. ', -'Etiam non neque ac mi vestibulum placerat. ', -'Donec at diam a tellus dignissim vestibulum. ', -'Integer accumsan. ', -'Cras ac enim vel dui vestibulum suscipit. ', -'Pellentesque tempor. ', -'Praesent lacus. ' -] - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--title") - self.OptionParser.add_option("-n", "--numberofparagraphs", - action="store", type="int", - dest="num", default=5, - help="Number of paragraphs to generate") - self.OptionParser.add_option("-c", "--sentencecount", - action="store", type="int", - dest="sentencecount", default=16, - help="Number of Sentences") - self.OptionParser.add_option("-f", "--fluctuation", - 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): - _min=max(1,self.options.sentencecount-self.options.fluctuation) - _max=max(2,self.options.sentencecount+self.options.fluctuation) - scount=random.randint(_min,_max) - text='' - for i in range(scount): - if self.first_sentence == 1: - text+=foo[0] - self.first_sentence = 0 - else: - text+=foo[random.randint(0,len(foo)-1)] - return text - - def addText(self, node): - for i in range(self.options.num): - para=inkex.etree.SubElement(node,inkex.addNS('flowPara','svg')) - para.text = self.makePara() - inkex.etree.SubElement(node,inkex.addNS('flowPara','svg')) - - def effect(self): - found=0 - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('flowRoot','svg'): - found+=1 - if found==1: - self.addText(node) - if found==0: - #inkex.debug('No "flowRoot" elements selected. Unable to add text.') - svg=self.document.getroot() - gattribs = {inkex.addNS('label','inkscape'):'lorem ipsum',inkex.addNS('groupmode','inkscape'):'layer'} - g=inkex.etree.SubElement(svg,inkex.addNS('g','svg'),gattribs) - flowRoot=inkex.etree.SubElement(g,inkex.addNS('flowRoot','svg'),{inkex.addNS('space','xml'):'preserve'}) - flowRegion=inkex.etree.SubElement(flowRoot,inkex.addNS('flowRegion','svg')) - rattribs = {'x':'0','y':'0','width':svg.get('width'),'height':svg.get('height')} - rect=inkex.etree.SubElement(flowRegion,inkex.addNS('rect','svg'),rattribs) - self.addText(flowRoot) - -if __name__ == '__main__': - e = MyEffect() - e.affect() diff --git a/share/extensions/markers_strokepaint.inx b/share/extensions/markers_strokepaint.inx deleted file mode 100644 index 2422482a7..000000000 --- a/share/extensions/markers_strokepaint.inx +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Color Markers</_name> - <id>org.ekips.filter.markers.strokepaint</id> - <dependency type="executable" location="extensions">markers_strokepaint.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name='tab' type="notebook"> - <page name='object' _gui-text="From object"> - <param name="type" type="enum" _gui-text="Marker type:"> - <_item value="solid">solid</_item> - <_item value="filled">filled</_item> - </param> - <param name="invert" type="boolean" _gui-text="Invert fill and stroke colors">false</param> - <param name="alpha" type="boolean" _gui-text="Assign alpha">true</param> - </page> - <page name='custom' _gui-text="Custom"> - <param name="colortab" type="notebook"> - <page name="fill_page" _gui-text="Fill"> - <param name="assign_fill" type="boolean" _gui-text="Assign fill color">true</param> - <param name="fill_color" gui-text="Fill color" type="color">-1</param> - </page> - <page name="stroke_page" _gui-text="Stroke"> - <param name="assign_stroke" type="boolean" _gui-text="Assign stroke color">true</param> - <param name="stroke_color" gui-text="Stroke color" type="color">255</param> - </page> - </param> - </page> - </param> - - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">markers_strokepaint.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/markers_strokepaint.py b/share/extensions/markers_strokepaint.py deleted file mode 100755 index 2d0d3e44b..000000000 --- a/share/extensions/markers_strokepaint.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Aaron Spike, aaron@ekips.org -Copyright (C) 2010 Nicolas Dufour, nicoduf@yahoo.fr (color options) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import random -import copy -# local library -import inkex -import simplestyle - - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-m", "--modify", - action="store", type="inkbool", - dest="modify", default=False, - help="Do not create a copy, modify the markers") - self.OptionParser.add_option("-t", "--type", - action="store", type="string", - dest="fill_type", default="stroke", - help="Replace the markers' fill with the object stroke or fill color") - self.OptionParser.add_option("-a", "--alpha", - action="store", type="inkbool", - dest="assign_alpha", default=True, - help="Assign the object fill and stroke alpha to the markers") - self.OptionParser.add_option("-i", "--invert", - action="store", type="inkbool", - dest="invert", default=False, - help="Invert fill and stroke colors") - self.OptionParser.add_option("--assign_fill", - action="store", type="inkbool", - dest="assign_fill", default=True, - help="Assign a fill color to the markers") - self.OptionParser.add_option("-f", "--fill_color", - action="store", type="int", - dest="fill_color", default=1364325887, - help="Choose a custom fill color") - self.OptionParser.add_option("--assign_stroke", - action="store", type="inkbool", - dest="assign_stroke", default=True, - help="Assign a stroke color to the markers") - self.OptionParser.add_option("-s", "--stroke_color", - action="store", type="int", - dest="stroke_color", default=1364325887, - help="Choose a custom fill color") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", - help="The selected UI-tab when OK was pressed") - self.OptionParser.add_option("--colortab", - action="store", type="string", - dest="colortab", - help="The selected custom color tab when OK was pressed") - - def effect(self): - defs = self.xpathSingle('/svg:svg//svg:defs') - if defs == None: - defs = inkex.etree.SubElement(self.document.getroot(),inkex.addNS('defs','svg')) - - for id, node in self.selected.iteritems(): - mprops = ['marker','marker-start','marker-mid','marker-end'] - try: - style = simplestyle.parseStyle(node.get('style')) - except: - inkex.errormsg(_("No style attribute found for id: %s") % id) - continue - - # Use object colors - if self.options.tab == '"object"': - temp_stroke = style.get('stroke', '#000000') - temp_fill = style.get('fill', '#000000') - if (self.options.invert): - fill = temp_stroke - stroke = temp_fill - else: - fill = temp_fill - stroke = temp_stroke - if (self.options.assign_alpha): - temp_stroke_opacity = style.get('stroke-opacity', '1') - temp_fill_opacity = style.get('fill-opacity', '1') - if (self.options.invert): - fill_opacity = temp_stroke_opacity - stroke_opacity = temp_fill_opacity - else: - fill_opacity = temp_fill_opacity - stroke_opacity = temp_stroke_opacity - if (self.options.fill_type == "solid"): - fill = stroke - if (self.options.assign_alpha): - fill_opacity = stroke_opacity - # Choose custom colors - elif self.options.tab == '"custom"': - fill_red = ((self.options.fill_color >> 24) & 255) - fill_green = ((self.options.fill_color >> 16) & 255) - fill_blue = ((self.options.fill_color >> 8) & 255) - fill = "rgb(%s,%s,%s)" % (fill_red, fill_green, fill_blue) - fill_opacity = (((self.options.fill_color) & 255) / 255.) - stroke_red = ((self.options.stroke_color >> 24) & 255) - stroke_green = ((self.options.stroke_color >> 16) & 255) - stroke_blue = ((self.options.stroke_color >> 8) & 255) - stroke = "rgb(%s,%s,%s)" % (stroke_red, stroke_green, stroke_blue) - stroke_opacity = (((self.options.stroke_color) & 255) / 255.) - if (not(self.options.assign_fill)): - fill = "none"; - if (not(self.options.assign_stroke)): - stroke = "none"; - - for mprop in mprops: - if style.has_key(mprop) and style[mprop] != 'none'and style[mprop][:5] == 'url(#': - marker_id = style[mprop][5:-1] - - try: - old_mnode = self.xpathSingle('/svg:svg//svg:marker[@id="%s"]' % marker_id) - if not self.options.modify: - mnode = copy.deepcopy(old_mnode) - else: - mnode = old_mnode - except: - inkex.errormsg(_("unable to locate marker: %s") % marker_id) - continue - - new_id = self.uniqueId(marker_id, not self.options.modify) - - style[mprop] = "url(#%s)" % new_id - mnode.set('id', new_id) - mnode.set(inkex.addNS('stockid','inkscape'), new_id) - defs.append(mnode) - - children = mnode.xpath('.//*[@style]', namespaces=inkex.NSS) - for child in children: - cstyle = simplestyle.parseStyle(child.get('style')) - if (not('stroke' in cstyle and self.options.tab == '"object"' and cstyle['stroke'] == 'none' and self.options.fill_type == "filled")): - cstyle['stroke'] = stroke - if 'stroke_opacity' in locals(): - cstyle['stroke-opacity'] = stroke_opacity - if (not('fill' in cstyle and self.options.tab == '"object"' and cstyle['fill'] == 'none' and self.options.fill_type == "solid")): - cstyle['fill'] = fill - if 'fill_opacity' in locals(): - cstyle['fill-opacity'] = fill_opacity - child.set('style',simplestyle.formatStyle(cstyle)) - node.set('style',simplestyle.formatStyle(style)) - -if __name__ == '__main__': - e = MyEffect() - e.affect() - - -# 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 deleted file mode 100644 index 7a6598bc7..000000000 --- a/share/extensions/measure.inx +++ /dev/null @@ -1,79 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Measure Path</_name> - <id>com.njhurst.filter.measure_length</id> - <dependency type="executable" location="extensions">measure.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="measure" _gui-text="Measure"> - <param name="type" type="enum" _gui-text="Measurement Type: "> - <_item value="length">Length</_item> - <_item msgctxt="measure extension" value="area">Area</_item> - <_item msgctxt="measure extension" value="cofm">Center of Mass</_item> - </param> - <param name="format" type="notebook"> - <page name="presets" _gui-text="Text Presets"> - <param name="presetFormat" type="enum" _gui-text="Position:"> - <_item value="default">Default</_item> - <_item value="TaP_start">Text on Path, Start</_item> - <_item value="TaP_middle">Text on Path, Middle</_item> - <_item value="TaP_end">Text on Path, End</_item> - <_item value="FT_start">Fixed Text, Start of Path</_item> - <_item value="FT_bbox">Fixed Text, Center of BBox</_item> - <_item value="FT_mass">Fixed Text, Center of Mass</_item> - </param> - </page> - <page name="textonpath" _gui-text="Text on Path"> - <param name="startOffset" type="string" gui-hidden="true">custom</param> - <param name="startOffsetCustom" type="int" appearance="full" min="0" max="100" _gui-text="Offset (%)">50</param> - <param name="anchor" type="enum" _gui-text="Text anchor:"> - <_item value="start">Left</_item> - <_item value="middle">Center</_item> - <_item value="end">Right</_item> - </param> - </page> - <page name="fixedtext" _gui-text="Fixed Text"> - <param name="position" type="enum" _gui-text="Position:"> - <_item value="start">Start of Path</_item> - <_item value="center">Center of BBox</_item> - <_item value="mass">Center of Mass</_item> - </param> - <param name="angle" type="float" min="-360" max="360" _gui-text="Angle (°):">0</param> - </page> - </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="unit" type="enum" _gui-text="Length Unit:"> - <item value="px">px</item> - <item value="pt">pt</item> - <item value="in">in</item> - <item value="ft">ft</item> - <item value="yd">yd</item> - <item value="mm">mm</item> - <item value="cm">cm</item> - <item value="m">m</item> - <item value="km">km</item> - </param> - </page> - <page name="desc" _gui-text="Help"> - <_param name="measurehelp" type="description" xml:space="preserve">This effect measures the length, area, or center-of-mass of the selected paths. Length and area are added as a text object with the selected units. Center-of-mass is shown as a cross symbol. - - * Text display format can be either Text-On-Path, or stand-alone text at a specified angle. - * The number of significant digits can be controlled by the Precision field. - * The Offset field controls the distance from the text to the path. - * The Scale factor can be used to make measurements in scaled drawings. For example, if 1 cm in the drawing equals 2.5 m in the real world, Scale must be set to 250. - * When calculating area, the result should be precise for polygons and Bezier curves. If a circle is used, the area may be too high by as much as 0.03%.</_param> - </page> - </param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Visualize Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">measure.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/measure.py b/share/extensions/measure.py deleted file mode 100755 index d025f142c..000000000 --- a/share/extensions/measure.py +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/env python -''' -This extension module can measure arbitrary path and object length -It adds text to the selected path containing the length in a given unit. -Area and Center of Mass calculated using Green's Theorem: -http://mathworld.wolfram.com/GreensTheorem.html - -Copyright (C) 2015 ~suv <suv-sf@users.sf.net> -Copyright (C) 2010 Alvin Penner -Copyright (C) 2006 Georg Wiora -Copyright (C) 2006 Nathan Hurst -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -TODO: - * should use the standard attributes for text - * Implement option to keep text orientation upright - 1. Find text direction i.e. path tangent, - 2. check direction >90 or <-90 Degrees - 3. rotate by 180 degrees around text center -''' -# standard library -import locale -import re -# local library -import inkex -import simplestyle -import simpletransform -import cubicsuperpath -import bezmisc - - -# On darwin, fall back to C in cases of -# - incorrect locale IDs (see comments in bug #406662) -# - https://bugs.python.org/issue18378 -try: - locale.setlocale(locale.LC_ALL, '') -except locale.Error: - locale.setlocale(locale.LC_ALL, 'C') - -# Initialize gettext for messages outside an inkex derived class -inkex.localize() - -# third party -try: - import numpy -except: - inkex.errormsg(_("Failed to import the numpy modules. These modules are required by this extension. Please install them and try again. On a Debian-like system this can be done with the command, sudo apt-get install python-numpy.")) - exit() - -mat_area = numpy.matrix([[ 0, 2, 1, -3],[ -2, 0, 1, 1],[ -1, -1, 0, 2],[ 3, -1, -2, 0]]) -mat_cofm_0 = numpy.matrix([[ 0, 35, 10,-45],[-35, 0, 12, 23],[-10,-12, 0, 22],[ 45,-23,-22, 0]]) -mat_cofm_1 = numpy.matrix([[ 0, 15, 3,-18],[-15, 0, 9, 6],[ -3, -9, 0, 12],[ 18, -6,-12, 0]]) -mat_cofm_2 = numpy.matrix([[ 0, 12, 6,-18],[-12, 0, 9, 3],[ -6, -9, 0, 15],[ 18, -3,-15, 0]]) -mat_cofm_3 = numpy.matrix([[ 0, 22, 23,-45],[-22, 0, 12, 10],[-23,-12, 0, 35],[ 45,-10,-35, 0]]) - -def numsegs(csp): - return sum([len(p)-1 for p in csp]) -def interpcoord(v1,v2,p): - return v1+((v2-v1)*p) -def interppoints(p1,p2,p): - return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)] -def pointdistance((x1,y1),(x2,y2)): - return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2)) -def bezlenapprx(sp1, sp2): - return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1]) -def tpoint((x1,y1), (x2,y2), t = 0.5): - return [x1+t*(x2-x1),y1+t*(y2-y1)] -def cspbezsplit(sp1, sp2, t = 0.5): - m1=tpoint(sp1[1],sp1[2],t) - m2=tpoint(sp1[2],sp2[0],t) - m3=tpoint(sp2[0],sp2[1],t) - m4=tpoint(m1,m2,t) - m5=tpoint(m2,m3,t) - m=tpoint(m4,m5,t) - return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]] -def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001): - bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:]) - t = bezmisc.beziertatlength(bez, l, tolerance) - return cspbezsplit(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: - lengths.append([]) - for i in xrange(1,len(sp)): - l = cspseglength(sp[i-1],sp[i]) - lengths[-1].append(l) - total += l - return lengths, total -def csparea(csp): - area = 0.0 - for sp in csp: - if len(sp) < 2: continue - for i in range(len(sp)): # calculate polygon area - area += 0.5*sp[i-1][1][0]*(sp[i][1][1] - sp[i-2][1][1]) - for i in range(1, len(sp)): # add contribution from cubic Bezier - vec_x = numpy.matrix([sp[i-1][1][0], sp[i-1][2][0], sp[i][0][0], sp[i][1][0]]) - vec_y = numpy.matrix([sp[i-1][1][1], sp[i-1][2][1], sp[i][0][1], sp[i][1][1]]) - area += 0.15*(vec_x*mat_area*vec_y.T)[0,0] - return -area # require positive area for CCW -def cspcofm(csp): - area = csparea(csp) - xc = 0.0 - yc = 0.0 - if abs(area) < 1.e-8: - inkex.errormsg(_("Area is zero, cannot calculate Center of Mass")) - return 0, 0 - for sp in csp: - for i in range(len(sp)): # calculate polygon moment - xc += sp[i-1][1][1]*(sp[i-2][1][0] - sp[i][1][0])*(sp[i-2][1][0] + sp[i-1][1][0] + sp[i][1][0])/6 - yc += sp[i-1][1][0]*(sp[i][1][1] - sp[i-2][1][1])*(sp[i-2][1][1] + sp[i-1][1][1] + sp[i][1][1])/6 - for i in range(1, len(sp)): # add contribution from cubic Bezier - vec_x = numpy.matrix([sp[i-1][1][0], sp[i-1][2][0], sp[i][0][0], sp[i][1][0]]) - vec_y = numpy.matrix([sp[i-1][1][1], sp[i-1][2][1], sp[i][0][1], sp[i][1][1]]) - vec_t = numpy.matrix([(vec_x*mat_cofm_0*vec_y.T)[0,0], (vec_x*mat_cofm_1*vec_y.T)[0,0], (vec_x*mat_cofm_2*vec_y.T)[0,0], (vec_x*mat_cofm_3*vec_y.T)[0,0]]) - xc += (vec_x*vec_t.T)[0,0]/280 - yc += (vec_y*vec_t.T)[0,0]/280 - return -xc/area, -yc/area -def appendSuperScript(node, text): - super = inkex.etree.SubElement(node, inkex.addNS('tspan', 'svg'), {'style': 'font-size:65%;baseline-shift:super'}) - super.text = text - -class Length(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--type", - action="store", type="string", - dest="mtype", default="length", - help="Type of measurement") - self.OptionParser.add_option("--format", - action="store", type="string", - dest="mformat", default="textonpath", - help="Text Orientation") - self.OptionParser.add_option("--presetFormat", - action="store", type="string", - dest="presetFormat", default="TaP_start", - help="Preset text layout") - self.OptionParser.add_option("--startOffset", - action="store", type="string", - dest="startOffset", default="custom", - help="Text Offset along Path") - self.OptionParser.add_option("--startOffsetCustom", - action="store", type="int", - dest="startOffsetCustom", default=50, - help="Text Offset along Path") - self.OptionParser.add_option("--anchor", - action="store", type="string", - dest="anchor", default="start", - help="Text Anchor") - self.OptionParser.add_option("--position", - action="store", type="string", - dest="position", default="start", - help="Text Position") - self.OptionParser.add_option("--angle", - action="store", type="float", - dest="angle", default=0, - help="Angle") - self.OptionParser.add_option("-f", "--fontsize", - action="store", type="int", - dest="fontsize", default=20, - help="Size of length lable text in px") - self.OptionParser.add_option("-o", "--offset", - action="store", type="float", - dest="offset", default=-6, - help="The distance above the curve") - self.OptionParser.add_option("-u", "--unit", - action="store", type="string", - dest="unit", default="mm", - help="The unit of the measurement") - self.OptionParser.add_option("-p", "--precision", - action="store", type="int", - dest="precision", default=2, - help="Number of significant digits after decimal point") - self.OptionParser.add_option("-s", "--scale", - action="store", type="float", - dest="scale", default=1, - help="Scale Factor (Drawing:Real Length)") - self.OptionParser.add_option("-r", "--orient", - action="store", type="inkbool", - dest="orient", default=True, - help="Keep orientation of text upright") - 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("--measurehelp", - action="store", type="string", - dest="measurehelp", default="", - help="dummy") - - def effect(self): - if self.options.mformat == '"presets"': - self.setPreset() - # get number of digits - prec = int(self.options.precision) - scale = self.unittouu('1px') # convert to document units - self.options.offset *= scale - factor = 1.0 - doc = self.document.getroot() - if doc.get('viewBox'): - (viewx, viewy, vieww, viewh) = re.sub(' +|, +|,',' ',doc.get('viewBox')).strip().split(' ', 4) - factor = self.unittouu(doc.get('width'))/float(vieww) - if self.unittouu(doc.get('height'))/float(viewh) < factor: - factor = self.unittouu(doc.get('height'))/float(viewh) - factor /= self.unittouu('1px') - self.options.fontsize /= factor - factor *= scale/self.unittouu('1'+self.options.unit) - # loop over all selected paths - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - mat = simpletransform.composeParents(node, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - p = cubicsuperpath.parsePath(node.get('d')) - simpletransform.applyTransformToPath(mat, p) - if self.options.mtype == "length": - slengths, stotal = csplength(p) - self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg')) - elif self.options.mtype == "area": - stotal = abs(csparea(p)*factor*self.options.scale) - self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg')) - else: - xc, yc = cspcofm(p) - self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('path','svg')) - self.group.set('id', 'MassCenter_' + node.get('id')) - self.addCross(self.group, xc, yc, scale) - continue - # Format the length as string - lenstr = locale.format("%(len)25."+str(prec)+"f",{'len':round(stotal*factor*self.options.scale,prec)}).strip() - if self.options.mformat == '"textonpath"': - startOffset = self.options.startOffset - if startOffset == "custom": - startOffset = str(self.options.startOffsetCustom) + '%' - if self.options.mtype == "length": - self.addTextOnPath(self.group, 0, 0, lenstr+' '+self.options.unit, id, self.options.anchor, startOffset, self.options.offset) - else: - self.addTextOnPath(self.group, 0, 0, lenstr+' '+self.options.unit+'^2', id, self.options.anchor, startOffset, self.options.offset) - elif self.options.mformat == '"fixedtext"': - if self.options.position == "mass": - tx, ty = cspcofm(p) - anchor = 'middle' - elif self.options.position == "center": - bbox = simpletransform.computeBBox([node]) - tx = bbox[0] + (bbox[1] - bbox[0])/2.0 - ty = bbox[2] + (bbox[3] - bbox[2])/2.0 - anchor = 'middle' - else: # default - tx = p[0][0][1][0] - ty = p[0][0][1][1] - anchor = 'start' - if self.options.mtype == "length": - self.addTextWithTspan(self.group, tx, ty, lenstr+' '+self.options.unit, id, anchor, -int(self.options.angle), self.options.offset + self.options.fontsize/2) - else: - self.addTextWithTspan(self.group, tx, ty, lenstr+' '+self.options.unit+'^2', id, anchor, -int(self.options.angle), -self.options.offset + self.options.fontsize/2) - else: - # center of mass, no text - pass - - def setPreset(self): - # keep dict in sync with enum in INX file: - preset_dict = { - 'default_length': ['"textonpath"', "50%", "start", None, None], - 'default_area': ['"fixedtext"', None, None, "start", 0.0], - 'default_cofm': [None, None, None, None, None], - 'TaP_start': ['"textonpath"', "0%", "start", None, None], - 'TaP_middle': ['"textonpath"', "50%", "middle", None, None], - 'TaP_end': ['"textonpath"', "100%", "end", None, None], - 'FT_start': ['"fixedtext"', None, None, "start", 0.0], - 'FT_bbox': ['"fixedtext"', None, None, "center", 0.0], - 'FT_mass': ['"fixedtext"', None, None, "mass", 0.0], - } - if self.options.presetFormat == "default": - current_preset = 'default_' + self.options.mtype - else: - current_preset = self.options.presetFormat - self.options.mformat = preset_dict[current_preset][0] - self.options.startOffset = preset_dict[current_preset][1] - self.options.anchor = preset_dict[current_preset][2] - self.options.position = preset_dict[current_preset][3] - self.options.angle = preset_dict[current_preset][4] - - def addCross(self, node, x, y, scale): - l = 3*scale # 3 pixels in document units - node.set('d', 'm %s,%s %s,0 %s,0 m %s,%s 0,%s 0,%s' % (str(x-l), str(y), str(l), str(l), str(-l), str(-l), str(l), str(l))) - node.set('style', 'stroke:#000000;fill:none;stroke-width:%s' % str(0.5*scale)) - - def addTextOnPath(self, node, x, y, text, id, anchor, startOffset, dy = 0): - new = inkex.etree.SubElement(node,inkex.addNS('textPath','svg')) - s = {'text-align': 'center', 'vertical-align': 'bottom', - 'text-anchor': anchor, 'font-size': str(self.options.fontsize), - 'fill-opacity': '1.0', 'stroke': 'none', - 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'} - new.set('style', simplestyle.formatStyle(s)) - new.set(inkex.addNS('href','xlink'), '#'+id) - new.set('startOffset', startOffset) - new.set('dy', str(dy)) # dubious merit - #new.append(tp) - if text[-2:] == "^2": - appendSuperScript(new, "2") - new.text = str(text)[:-2] - else: - new.text = str(text) - #node.set('transform','rotate(180,'+str(-x)+','+str(-y)+')') - node.set('x', str(x)) - node.set('y', str(y)) - - def addTextWithTspan(self, node, x, y, text, id, anchor, angle, dy = 0): - new = inkex.etree.SubElement(node,inkex.addNS('tspan','svg'), {inkex.addNS('role','sodipodi'): 'line'}) - s = {'text-align': 'center', 'vertical-align': 'bottom', - 'text-anchor': anchor, 'font-size': str(self.options.fontsize), - 'fill-opacity': '1.0', 'stroke': 'none', - 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'} - new.set('style', simplestyle.formatStyle(s)) - new.set('dy', str(dy)) - if text[-2:] == "^2": - appendSuperScript(new, "2") - new.text = str(text)[:-2] - else: - new.text = str(text) - node.set('x', str(x)) - node.set('y', str(y)) - node.set('transform', 'rotate(%s, %s, %s)' % (angle, x, y)) - -if __name__ == '__main__': - e = Length() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/merge_styles.inx b/share/extensions/merge_styles.inx deleted file mode 100644 index 02da12221..000000000 --- a/share/extensions/merge_styles.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Merge Styles into CSS</_name> - <id>org.inkscape.stylesheet.merge</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">merge_styles.py</dependency> - - <_param name="introduction" type="description">All selected nodes will be grouped together and their common style attributes will create a new class, this class will replace the existing inline style attributes. Please use a name which best describes the kinds of objects and their common context for best effect.</_param> - - <param name="name" type="string" _gui-text="New Class Name:">class1</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Stylesheet"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">merge_styles.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/merge_styles.py b/share/extensions/merge_styles.py deleted file mode 100755 index cdd7b5ed5..000000000 --- a/share/extensions/merge_styles.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2014 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -""" -Merges styles into class based styles and removes. -""" - -import inkex -import sys - -from collections import defaultdict - -class Style(dict): - """Controls the style/css mechanics for this effect""" - def __init__(self, attr=None): - self.weights = defaultdict(int) - self.total = [] - if attr: - self.parse(attr) - - def parse(self, attr): - for name,value in [ a.split(':',1) for a in attr.split(';') if ':' in a ]: - self[name.strip()] = value.strip() - - def entries(self): - return [ "%s:%s;" % (n,v) for (n,v) in self.iteritems() ] - - def to_str(self, sep="\n "): - return " " + "\n ".join(self.entries()) - - def __str__(self): - return self.to_str() - - def css(self, cls): - return ".%s {\n%s\n}" % (cls, str(self)) - - def remove(self, keys): - for key in keys: - self.pop(key, None) - - def add(self, c, el): - self.total.append( (c, el) ) - for name,value in c.iteritems(): - if not self.has_key(name): - self[name] = value - if self[name] == value: - self.weights[name] += 1 - - def clean(self, threshold): - """Removes any elements that aren't the same using a weighted threshold""" - for attr in self.keys(): - if self.weights[attr] < len(self.total) - threshold: - self.pop(attr) - - def all_matches(self): - """Returns an iter for each added element who's style matches this style""" - for (c, el) in self.total: - if self == c: - yield (c, el) - - def __eq__(self, o): - """Not equals, prefer to overload 'in' but that doesn't seem possible""" - for arg in self.keys(): - if o.has_key(arg) and self[arg] != o[arg]: - return False - return True - - -def get_styles(document): - nodes = [] - for node in document.getroot().iterchildren(): - if node.tag == inkex.addNS('style', 'svg'): - return node - nodes.append(node) - ret = inkex.etree.SubElement(document.getroot(), 'style', {}) - # Reorder to make the style element FIRST - for node in nodes: - document.getroot().append(node) - return ret - - -class MergeStyles(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-n", "--name", - action="store", type="string", - dest="name", default='', - help="Name of selected element's common class") - - def effect(self): - newclass = self.options.name - elements = self.selected.values() - common = Style() - threshold = 1 - - for el in elements: - common.add(Style(el.attrib['style']), el) - common.clean(threshold) - - if not common: - raise KeyError("There are no common styles between these elements.") - - styles = get_styles(self.document) - styles.text = (styles.text or "") + "\n" + common.css( newclass ) - - for (st, el) in common.all_matches(): - st.remove(common.keys()) - el.attrib['style'] = st.to_str("") - - olds = el.attrib.has_key('class') and el.attrib['class'].split() or [] - if newclass not in olds: - olds.append(newclass) - el.attrib['class'] = ' '.join(olds) - - -if __name__ == '__main__': - e = MergeStyles() - e.affect() - diff --git a/share/extensions/motion.inx b/share/extensions/motion.inx deleted file mode 100644 index 8ffeb16ce..000000000 --- a/share/extensions/motion.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Motion</_name> - <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> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Generate from Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">motion.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/motion.py b/share/extensions/motion.py deleted file mode 100755 index 3af80d5c1..000000000 --- a/share/extensions/motion.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import math, inkex, simplestyle, simplepath, bezmisc - -class Motion(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-a", "--angle", - action="store", type="float", - dest="angle", default=45.0, - help="direction of the motion vector") - self.OptionParser.add_option("-m", "--magnitude", - action="store", type="float", - dest="magnitude", default=100.0, - help="magnitude of the motion vector") - - def makeface(self,last,(cmd, params)): - a = [] - a.append(['M',last[:]]) - a.append([cmd, params[:]]) - - #translate path segment along vector - np = params[:] - defs = simplepath.pathdefs[cmd] - for i in range(defs[1]): - if defs[3][i] == 'x': - np[i] += self.vx - elif defs[3][i] == 'y': - np[i] += self.vy - - a.append(['L',[np[-2],np[-1]]]) - - #reverse direction of path segment - np[-2:] = last[0]+self.vx,last[1]+self.vy - if cmd == 'C': - c1 = np[:2], np[2:4] = np[2:4], np[:2] - a.append([cmd,np[:]]) - - a.append(['Z',[]]) - face = inkex.etree.SubElement(self.facegroup,inkex.addNS('path','svg'),{'d':simplepath.formatPath(a)}) - - def effect(self): - self.vx = math.cos(math.radians(self.options.angle))*self.options.magnitude - self.vy = math.sin(math.radians(self.options.angle))*self.options.magnitude - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - group = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg')) - self.facegroup = inkex.etree.SubElement(group, inkex.addNS('g','svg')) - group.append(node) - - t = node.get('transform') - if t: - group.set('transform', t) - node.set('transform','') - - s = node.get('style') - self.facegroup.set('style', s) - - p = simplepath.parsePath(node.get('d')) - for cmd,params in p: - tees = [] - if cmd == 'C': - bez = (last,params[:2],params[2:4],params[-2:]) - tees = [t for t in bezmisc.beziertatslope(bez,(self.vy,self.vx)) if 0<t<1] - tees.sort() - - segments = [] - if len(tees) == 0 and cmd in ['L','C']: - segments.append([cmd,params[:]]) - elif len(tees) == 1: - one,two = bezmisc.beziersplitatt(bez,tees[0]) - segments.append([cmd,list(one[1]+one[2]+one[3])]) - segments.append([cmd,list(two[1]+two[2]+two[3])]) - elif len(tees) == 2: - one,two = bezmisc.beziersplitatt(bez,tees[0]) - two,three = bezmisc.beziersplitatt(two,tees[1]) - segments.append([cmd,list(one[1]+one[2]+one[3])]) - segments.append([cmd,list(two[1]+two[2]+two[3])]) - segments.append([cmd,list(three[1]+three[2]+three[3])]) - - for seg in segments: - self.makeface(last,seg) - last = seg[1][-2:] - - if cmd == 'M': - subPathStart = params[-2:] - if cmd == 'Z': - last = subPathStart - else: - last = params[-2:] - -if __name__ == '__main__': - e = Motion() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/new_glyph_layer.inx b/share/extensions/new_glyph_layer.inx deleted file mode 100644 index 8841ee34a..000000000 --- a/share/extensions/new_glyph_layer.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>2 - Add Glyph Layer</_name> - <id>org.inkscape.typography.newglyphlayer</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">new_glyph_layer.py</dependency> - <param name="unicode" type="string" _gui-text="Unicode character:"></param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">new_glyph_layer.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/new_glyph_layer.py b/share/extensions/new_glyph_layer.py deleted file mode 100755 index d6622cc62..000000000 --- a/share/extensions/new_glyph_layer.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import sys -import locale - - -class NewGlyphLayer(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-u", "--unicodechars", - action="store", type="string", - dest="unicodechars", default='', - help="Unicode chars") - self.encoding = sys.stdin.encoding - if self.encoding == 'cp0' or self.encoding is None: - self.encoding = locale.getpreferredencoding() - - def effect(self): - # Get all the options - unicode_chars = self.options.unicodechars.decode(self.encoding) - - #TODO: remove duplicate chars - - # Get access to main SVG document element - svg = self.document.getroot() - - for char in unicode_chars: - # Create a new layer. - layer = inkex.etree.SubElement(svg, 'g') - layer.set(inkex.addNS('label', 'inkscape'), u'GlyphLayer-'+char) - layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') - layer.set('style', 'display:none') #initially not visible - - #TODO: make it optional ("Use current selection as template glyph") - # Move selection to the newly created layer - for id,node in self.selected.iteritems(): - layer.append(node) - -if __name__ == '__main__': - e = NewGlyphLayer() - e.affect() - diff --git a/share/extensions/next_glyph_layer.inx b/share/extensions/next_glyph_layer.inx deleted file mode 100644 index 7a3b03670..000000000 --- a/share/extensions/next_glyph_layer.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>View Next Glyph</_name> - <id>org.inkscape.typography.nextglyphlayer</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">next_glyph_layer.py</command> - </script> - <options silent="true"></options> -</inkscape-extension> diff --git a/share/extensions/next_glyph_layer.py b/share/extensions/next_glyph_layer.py deleted file mode 100755 index 5f152c71e..000000000 --- a/share/extensions/next_glyph_layer.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex - -class NextLayer(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - - # Get access to main SVG document element - self.svg = self.document.getroot() - - groups = self.svg.findall(inkex.addNS('g', 'svg')) - - count=0 - glyphs=[] - for g in groups: - if "GlyphLayer-" in g.get(inkex.addNS('label', 'inkscape')): - glyphs.append(g) - if g.get("style")=="display:inline": - count+=1 - current = len(glyphs)-1 - - if count!=1 or len(glyphs)<2: - return - #TODO: inform the user? - - glyphs[current].set("style", "display:none") - glyphs[(current+1)%len(glyphs)].set("style", "display:inline") - return - -#TODO: loop - -if __name__ == '__main__': - e = NextLayer() - e.affect() - diff --git a/share/extensions/nicechart.inx b/share/extensions/nicechart.inx deleted file mode 100644 index 0ebcd8fca..000000000 --- a/share/extensions/nicechart.inx +++ /dev/null @@ -1,103 +0,0 @@ -<!-- - nicechart.inx - - Copyright 2011-2016 - - Christoph Sterz - Florian Weber - Maren Hachmann - - 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 3 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., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. ---> - -<inkscape-extension> - <_name>NiceCharts</_name> - <id>org.inkscape.filter.nicechart</id> - <dependency type="executable" location="extensions">nicechart.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="input_sections" type="notebook"> - <page name="data_settings" _gui-text="Data"> - <param name="input_type" type="notebook"> - <page name="file" _gui-text="Data from file"> - <_param name="desc" type="description">Enter the full path to a CSV file:</_param> - <param name="filename" type="string" _gui-text="File:"></param> - <param name="delimiter" type="string" _gui-text="Delimiter:">;</param> - <param name="col_key" type="int" _gui-text="Column that contains the keys:" min="0" max="10000">0</param> - <param name="col_val" type="int" _gui-text="Column that contains the values:" min="0" max="10000">1</param> - <param name="encoding" type="string" _gui-text="File encoding (e.g. utf-8):">utf-8</param> - <param name="headings" type="boolean" _gui-text="First line contains headings">false</param> - </page> - <page name="direct_input" _gui-text="Direct input"> - <_param name="desc" type="description">Type in comma separated values:</_param> - <_param name="desc" type="description">(format like this: apples:3,bananas:5)</_param> - <param name="what" type="string" _gui-text="Data:">apples:3,bananas:5,oranges:10,pears:4</param> - </page> - </param> - </page> - <page name="description_settings" _gui-text="Labels"> - <param type="string" name="font" _gui-text="Font:">sans-serif</param> - <param type="int" name="font-size" _gui-text="Font size:" min="0" max="10000">10</param> - <param type="string" name="font-color" _gui-text="Font color:">#000000</param> - </page> - <page name="chart_settings" _gui-text="Charts"> - <param type="boolean" name="rotate" _gui-text="Draw horizontally">false</param> - <param name="bar-height" type="int" _gui-text="Bar length:" min="0" max="100000">100</param> - <param name="bar-width" type="int" _gui-text="Bar width:" min="0" max="100000">10</param> - <param name="pie-radius" type="int" _gui-text="Pie radius:" min="0" max="100000">100</param> - <param name="bar-offset" type="int" _gui-text="Bar offset:" min="0" max="100000">5</param> - <param name="stroke-width" type="float" min="0.1" max="100000.0" precision="2" _gui-text="Stroke width:">1</param> - <param name="text-offset" type="int" _gui-text="Offset between chart and labels:" min="0" max="100000">5</param> - <param name="heading-offset" type="int" _gui-text="Offset between chart and chart title:" min="-100000" max="100000">50</param> - <param name="segment-overlap" type="boolean" _gui-text="Work around aliasing effects (creates overlapping segments)">false</param> - - <param name="colors" type="enum" _gui-text="Color scheme:"> - <_item value="default">Default</_item> - <_item value="blue">Blue</_item> - <_item value="gray">Gray</_item> - <_item value="contrast">Contrast</_item> - <_item value="sap">SAP</_item> - </param> - - <param type="string" name="colors_override" _gui-text="Custom colors:"></param> - - <param type="boolean" name="reverse_colors" _gui-text="Reverse color scheme">false</param> - <param type="boolean" name="blur" _gui-text="Drop shadow">false</param> - </page> - <page name="value_settings" _gui-text="Values"> - <param type="boolean" name="show_values" _gui-text="Show values">false</param> -<!-- <param type="string" name="font" _gui-text="Font:">sans-serif</param> - <param type="int" name="font-size" _gui-text="Font size:" min="0" max="10000">10</param> - <param type="description" name="desc">Font color:</param> - <param type="string" name="font-color" _gui-text="Font color:">#000000</param> ---> - </page> - </param> - <param name="type" type="enum" _gui-text="Chart type:"> - <_item value="bar">Bar chart</_item> - <_item value="pie">Pie chart</_item> - <_item value="pie_abs">Pie chart (percentage)</_item> - <_item value="stbar">Stacked bar chart</_item> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">nicechart.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/nicechart.py b/share/extensions/nicechart.py deleted file mode 100755 index 3c46a6143..000000000 --- a/share/extensions/nicechart.py +++ /dev/null @@ -1,718 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# nicechart.py -# -# Copyright 2011-2016 -# -# Christoph Sterz -# Florian Weber -# Maren Hachmann -# -# 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 3 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., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# - -# TODO / Ideas: -# allow negative values for bar charts -# show values for stacked bar charts -# don't create a new layer for each chart, but a normal group -# correct bar height for stacked bars (it's only half as high as it should be, double) -# adjust position of heading -# use aliasing workaround for stacked bars (e.g. let the rectangles overlap) - -# Example CSV file contents: -''' -Month;1978;1979;1980;1981 -January;2;1,3;0.1;2.3 -February;6.5;2.4;1.2;6.1 -March;7.4;6.7;7.9;4.7 -April;7.7;6.4;8.2;8.9 -May;10.9;11.7;18.7;11.1 -June;12.6;14.2;14.7;14.7 -July;16.5;15.5;17.5;15.1 -August;15.9;15.4;14.6;16.6 -September;14;14.5;13.2;15.3 -October;11.9;13.9;11.5;9.2 -November;6.7;8.5;7;6.6 -December;6.4;2.2;6.3;3.5 -''' -# The extension creates one chart for a single value column in one go, -# e.g. chart all temperatures for all months of the year 1978 into one chart. -# (for this, select column 0 for labels and column 1 for values). -# "1978" etc. can be used as heading (Need not be numeric. If not used delete the heading line.) -# Month names can be used as labels -# Values can be shown, in addition to labels (doesn't work with stacked bar charts) -# Values can contain commas as decimal separator, as long as delimiter isn't comma -# Negative values are not yet supported. - - -import re -import sys -import math -import inkex - -from simplestyle import * - -#www.sapdesignguild.org/goodies/diagram_guidelines/color_palettes.html#mss -COLOUR_TABLE = { - "red": ["#460101", "#980101", "#d40000", "#f44800", "#fb8b00", "#eec73e", "#d9bb7a", "#fdd99b"], - "blue": ["#000442", "#0F1781", "#252FB7", "#3A45E1", "#656DDE", "#8A91EC"], - "gray": ["#222222", "#444444", "#666666", "#888888", "#aaaaaa", "#cccccc", "#eeeeee"], - "contrast": ["#0000FF", "#FF0000", "#00FF00", "#CF9100", "#FF00FF", "#00FFFF"], - "sap": ["#f8d753", "#5c9746", "#3e75a7", "#7a653e", "#e1662a", "#74796f", "#c4384f", - "#fff8a3", "#a9cc8f", "#b2c8d9", "#bea37a", "#f3aa79", "#b5b5a9", "#e6a5a5"] -} - -def get_color_scheme(name="default"): - return COLOUR_TABLE.get(name.lower(), COLOUR_TABLE['red']) - - -class NiceChart(inkex.Effect): - """ - Inkscape extension that can draw pie charts and bar charts - (stacked, single, horizontally or vertically) - with optional drop shadow, from a csv file or from pasted text - """ - - def __init__(self): - """ - Constructor. - Defines the "--what" option of a script. - """ - # Call the base class constructor. - inkex.Effect.__init__(self) - - # Define string option "--what" with "-w" shortcut and default chart values. - self.OptionParser.add_option('-w', '--what', action='store', - type='string', dest='what', default='22,11,67', - help='Chart Values') - - # Define string option "--type" with "-t" shortcut. - self.OptionParser.add_option("-t", "--type", action="store", - type="string", dest="type", default='', - help="Chart Type") - - # Define bool option "--blur" with "-b" shortcut. - self.OptionParser.add_option("-b", "--blur", action="store", - type="inkbool", dest="blur", default='True', - help="Blur Type") - - # Define string option "--file" with "-f" shortcut. - self.OptionParser.add_option("-f", "--filename", action="store", - type="string", dest="filename", default='', - help="Name of File") - - # Define string option "--input_type" with "-i" shortcut. - self.OptionParser.add_option("-i", "--input_type", action="store", - type="string", dest="input_type", default='file', - help="Chart Type") - - # Define string option "--delimiter" with "-d" shortcut. - self.OptionParser.add_option("-d", "--delimiter", action="store", - type="string", dest="csv_delimiter", default=';', - help="delimiter") - - # Define string option "--colors" with "-c" shortcut. - self.OptionParser.add_option("-c", "--colors", action="store", - type="string", dest="colors", default='default', - help="color-scheme") - - # Define string option "--colors_override" - self.OptionParser.add_option("", "--colors_override", action="store", - type="string", dest="colors_override", default='', - help="color-scheme-override") - - - self.OptionParser.add_option("", "--reverse_colors", action="store", - type="inkbool", dest="reverse_colors", default='False', - help="reverse color-scheme") - - self.OptionParser.add_option("-k", "--col_key", action="store", - type="int", dest="col_key", default='0', - help="column that contains the keys") - - - self.OptionParser.add_option("-v", "--col_val", action="store", - type="int", dest="col_val", default='1', - help="column that contains the values") - - self.OptionParser.add_option("", "--encoding", action="store", - type="string", dest="encoding", default='utf-8', - help="encoding of the CSV file, e.g. utf-8") - - self.OptionParser.add_option("", "--headings", action="store", - type="inkbool", dest="headings", default='False', - help="the first line of the CSV file consists of headings for the columns") - - self.OptionParser.add_option("-r", "--rotate", action="store", - type="inkbool", dest="rotate", default='False', - help="Draw barchart horizontally") - - self.OptionParser.add_option("-W", "--bar-width", action="store", - type="int", dest="bar_width", default='10', - help="width of bars") - - self.OptionParser.add_option("-p", "--pie-radius", action="store", - type="int", dest="pie_radius", default='100', - help="radius of pie-charts") - - self.OptionParser.add_option("-H", "--bar-height", action="store", - type="int", dest="bar_height", default='100', - help="height of bars") - - self.OptionParser.add_option("-O", "--bar-offset", action="store", - type="int", dest="bar_offset", default='5', - help="distance between bars") - - self.OptionParser.add_option("", "--stroke-width", action="store", - type="float", dest="stroke_width", default='1') - - self.OptionParser.add_option("-o", "--text-offset", action="store", - type="int", dest="text_offset", default='5', - help="distance between bar and descriptions") - - self.OptionParser.add_option("", "--heading-offset", action="store", - type="int", dest="heading_offset", default='50', - help="distance between chart and chart title") - - self.OptionParser.add_option("", "--segment-overlap", action="store", - type="inkbool", dest="segment_overlap", default='False', - help="work around aliasing effects by letting pie chart segments overlap") - - self.OptionParser.add_option("-F", "--font", action="store", - type="string", dest="font", default='sans-serif', - help="font of description") - - self.OptionParser.add_option("-S", "--font-size", action="store", - type="int", dest="font_size", default='10', - help="font size of description") - - self.OptionParser.add_option("-C", "--font-color", action="store", - type="string", dest="font_color", default='black', - help="font color of description") - #Dummy: - self.OptionParser.add_option("","--input_sections") - - self.OptionParser.add_option("-V", "--show_values", action="store", - type="inkbool", dest="show_values", default='False', - help="Show values in chart") - - def effect(self): - """ - Effect behaviour. - Overrides base class' method and inserts a nice looking chart into SVG document. - """ - # Get script's "--what" option value and process the data type --- i concess the if term is a little bit of magic - what = self.options.what - keys = [] - values = [] - orig_values = [] - keys_present = True - pie_abs = False - cnt = 0 - csv_file_name = self.options.filename - csv_delimiter = self.options.csv_delimiter - input_type = self.options.input_type - col_key = self.options.col_key - col_val = self.options.col_val - show_values = self.options.show_values - encoding = self.options.encoding.strip() or 'utf-8' - headings = self.options.headings - heading_offset = self.options.heading_offset - - if input_type == "\"file\"": - csv_file = open(csv_file_name, "r") - - for linenum, line in enumerate(csv_file): - value = line.decode(encoding).split(csv_delimiter) - #make sure that there is at least one value (someone may want to use it as description) - if len(value) >= 1: - # allow to parse headings as strings - if linenum == 0 and headings: - heading = value[col_val] - else: - keys.append(value[col_key]) - # replace comma decimal separator from file by colon, - # to avoid file editing for people whose programs output - # values with comma - values.append(float(value[col_val].replace(",","."))) - csv_file.close() - - elif input_type == "\"direct_input\"": - what = re.findall("([A-Z|a-z|0-9]+:[0-9]+\.?[0-9]*)", what) - for value in what: - value = value.split(":") - keys.append(value[0]) - values.append(float(value[1])) - - # warn about negative values (not yet supported) - for value in values: - if value < 0: - inkex.errormsg("Negative values are currently not supported!") - return - - # Get script's "--type" option value. - charttype = self.options.type - - if charttype == "pie_abs": - pie_abs = True - charttype = "pie" - - # Get access to main SVG document element and get its dimensions. - svg = self.document.getroot() - - # Get the page attributes: - width = self.getUnittouu(svg.get('width')) - height = self.getUnittouu(svg.attrib['height']) - - # Create a new layer. - layer = inkex.etree.SubElement(svg, 'g') - layer.set(inkex.addNS('label', 'inkscape'), 'Chart-Layer: %s' % (what)) - layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') - - # Check if a drop shadow should be drawn: - draw_blur = self.options.blur - - if draw_blur: - # Get defs of Document - defs = self.xpathSingle('/svg:svg//svg:defs') - if defs == None: - defs = inkex.etree.SubElement(self.document.getroot(), inkex.addNS('defs', 'svg')) - - # Create new Filter - filt = inkex.etree.SubElement(defs,inkex.addNS('filter', 'svg')) - filtId = self.uniqueId('filter') - self.filtId = 'filter:url(#%s);' % filtId - for k, v in [('id', filtId), ('height', "3"), - ('width', "3"), - ('x', '-0.5'), ('y', '-0.5')]: - filt.set(k, v) - - # Append Gaussian Blur to that Filter - fe = inkex.etree.SubElement(filt, inkex.addNS('feGaussianBlur', 'svg')) - fe.set('stdDeviation', "1.1") - - # Set Default Colors - self.options.colors_override.strip() - if len(self.options.colors_override) > 0: - colors = self.options.colors_override - else: - colors = self.options.colors - - if colors[0].isalpha(): - colors = get_color_scheme(colors) - else: - colors = re.findall("(#[0-9a-fA-F]{6})", colors) - #to be sure we create a fallback: - if len(colors) == 0: - colors = get_color_scheme() - - color_count = len(colors) - - if self.options.reverse_colors: - colors.reverse() - - # Those values should be self-explanatory: - bar_height = self.options.bar_height - bar_width = self.options.bar_width - bar_offset = self.options.bar_offset - # offset of the description in stacked-bar-charts: - # stacked_bar_text_offset=self.options.stacked_bar_text_offset - text_offset = self.options.text_offset - # prevents ugly aliasing effects between pie chart segments by overlapping - segment_overlap = self.options.segment_overlap - - # get font - font = self.options.font - font_size = self.options.font_size - font_color = self.options.font_color - - # get rotation - rotate = self.options.rotate - - pie_radius = self.options.pie_radius - stroke_width = self.options.stroke_width - - if charttype == "bar": - ######### - ###BAR### - ######### - - # iterate all values, use offset to draw the bars in different places - offset = 0 - color = 0 - - # Normalize the bars to the largest value - try: - value_max = max(values) - except ValueError: - value_max = 0.0 - - for x in range(len(values)): - orig_values.append(values[x]) - values[x] = (values[x]/value_max) * bar_height - - # Draw Single bars with their shadows - for value in values: - - # draw drop shadow, if necessary - if draw_blur: - # Create shadow element - shadow = inkex.etree.Element(inkex.addNS("rect", "svg")) - # Set chart position to center of document. Make it horizontal or vertical - if not rotate: - shadow.set('x', str(width/2 + offset + 1)) - shadow.set('y', str(height/2 - int(value) + 1)) - shadow.set("width", str(bar_width)) - shadow.set("height", str(int(value))) - else: - shadow.set('y', str(width/2 + offset + 1)) - shadow.set('x', str(height/2 + 1)) - shadow.set("height", str(bar_width)) - shadow.set("width", str(int(value))) - - # Set shadow blur (connect to filter object in xml path) - shadow.set("style", "filter:url(#filter)") - - # Create rectangle element - rect = inkex.etree.Element(inkex.addNS('rect', 'svg')) - - # Set chart position to center of document. - if not rotate: - rect.set('x', str(width/2 + offset)) - rect.set('y', str(height/2 - int(value))) - rect.set("width", str(bar_width)) - rect.set("height", str(int(value))) - else: - rect.set('y', str(width/2 + offset)) - rect.set('x', str(height/2)) - rect.set("height", str(bar_width)) - rect.set("width", str(int(value))) - - rect.set("style", "fill:" + colors[color % color_count]) - - # If keys are given, create text elements - if keys_present: - text = inkex.etree.Element(inkex.addNS('text', 'svg')) - if not rotate: #=vertical - text.set("transform", "matrix(0,-1,1,0,0,0)") - #y after rotation: - text.set("x", "-" + str(height/2 + text_offset)) - #x after rotation: - text.set("y", str(width/2 + offset + bar_width/2 + font_size/3)) - else: #=horizontal - text.set("y", str(width/2 + offset + bar_width/2 + font_size/3)) - text.set("x", str(height/2 - text_offset)) - - text.set("style", "font-size:" + str(font_size)\ - + "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"\ - + font + ";-inkscape-font-specification:Bitstream Charter;text-align:end;text-anchor:end;fill:"\ - + font_color) - - text.text = keys[cnt] - - # Increase Offset and Color - #offset=offset+bar_width+bar_offset - color = (color + 1) % 8 - # Connect elements together. - if draw_blur: - layer.append(shadow) - layer.append(rect) - if keys_present: - layer.append(text) - - if show_values: - vtext = inkex.etree.Element(inkex.addNS('text', 'svg')) - if not rotate: #=vertical - vtext.set("transform", "matrix(0,-1,1,0,0,0)") - #y after rotation: - vtext.set("x", "-"+str(height/2+text_offset-value-text_offset-text_offset)) - #x after rotation: - vtext.set("y", str(width/2+offset+bar_width/2+font_size/3)) - else: #=horizontal - vtext.set("y", str(width/2+offset+bar_width/2+font_size/3)) - vtext.set("x", str(height/2-text_offset+value+text_offset+text_offset)) - - vtext.set("style", "font-size:"+str(font_size)\ - + "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"\ - + font + ";-inkscape-font-specification:Bitstream Charter;text-align:start;text-anchor:start;fill:"\ - + font_color) - - vtext.text = str(int(orig_values[cnt])) - layer.append(vtext) - - cnt = cnt+1 - offset = offset + bar_width + bar_offset - - # set x position for heading line - if not rotate: - heading_x = width/2 # TODO: adjust - else: - heading_x = width/2 # TODO: adjust - - - elif charttype == "pie": - ######### - ###PIE### - ######### - # Iterate all values to draw the different slices - color = 0 - - # Create the shadow first (if it should be created): - if draw_blur: - shadow = inkex.etree.Element(inkex.addNS("circle", "svg")) - shadow.set('cx', str(width/2)) - shadow.set('cy', str(height/2)) - shadow.set('r', str(pie_radius)) - shadow.set("style", "filter:url(#filter);fill:#000000") - layer.append(shadow) - - - # Add a grey background circle with a light stroke - background = inkex.etree.Element(inkex.addNS("circle", "svg")) - background.set("cx", str(width/2)) - background.set("cy", str(height/2)) - background.set("r", str(pie_radius)) - background.set("style", "stroke:#ececec;fill:#f9f9f9") - layer.append(background) - - #create value sum in order to divide the slices - try: - valuesum = sum(values) - - except ValueError: - valuesum = 0 - - if pie_abs: - valuesum = 100 - - num_values = len(values) - - # Set an offsetangle - offset = 0 - - # Draw single slices - for i in range(num_values): - value = values[i] - # Calculate the PI-angles for start and end - angle = (2*3.141592) / valuesum * float(value) - start = offset - end = offset + angle - - # proper overlapping - if segment_overlap: - if i != num_values-1: - end += 0.09 # add a 5° overlap - if i == 0: - start -= 0.09 # let the first element overlap into the other direction - - #then add the slice - pieslice = inkex.etree.Element(inkex.addNS("path", "svg")) - pieslice.set(inkex.addNS('type', 'sodipodi'), 'arc') - pieslice.set(inkex.addNS('cx', 'sodipodi'), str(width/2)) - pieslice.set(inkex.addNS('cy', 'sodipodi'), str(height/2)) - pieslice.set(inkex.addNS('rx', 'sodipodi'), str(pie_radius)) - pieslice.set(inkex.addNS('ry', 'sodipodi'), str(pie_radius)) - pieslice.set(inkex.addNS('start', 'sodipodi'), str(start)) - pieslice.set(inkex.addNS('end', 'sodipodi'), str(end)) - pieslice.set("style", "fill:"+ colors[color % color_count] + ";stroke:none;fill-opacity:1") - - #If text is given, draw short paths and add the text - if keys_present: - path = inkex.etree.Element(inkex.addNS("path", "svg")) - path.set("d", "m " - + str((width/2) + pie_radius * math.cos(angle/2 + offset)) + "," - + str((height/2) + pie_radius * math.sin(angle/2 + offset)) + " " - + str((text_offset - 2) * math.cos(angle/2 + offset)) + "," - + str((text_offset - 2) * math.sin(angle/2 + offset))) - - path.set("style", "fill:none;stroke:" - + font_color + ";stroke-width:" + str(stroke_width) - + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1") - layer.append(path) - text = inkex.etree.Element(inkex.addNS('text', 'svg')) - text.set("x", str((width/2) + (pie_radius + text_offset) * math.cos(angle/2 + offset))) - text.set("y", str((height/2) + (pie_radius + text_offset) * math.sin(angle/2 + offset) + font_size/3)) - textstyle = "font-size:" + str(font_size) \ - + "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:" \ - + font + ";-inkscape-font-specification:Bitstream Charter;fill:" + font_color - # check if it is right or left of the Pie - if math.cos(angle/2 + offset) > 0: - text.set("style", textstyle) - else: - text.set("style", textstyle + ";text-align:end;text-anchor:end") - text.text = keys[cnt] - if show_values: - text.text = text.text + "(" + str(values[cnt]) - - if pie_abs: - text.text = text.text + " %" - - text.text = text.text + ")" - - cnt = cnt + 1 - layer.append(text) - - # increase the rotation-offset and the colorcycle-position - offset = offset + angle - color = (color + 1) % 8 - - # append the objects to the extension-layer - layer.append(pieslice) - - # set x position for heading line - heading_x = width/2 - pie_radius # TODO: adjust - - elif charttype == "stbar": - ################# - ###STACKED BAR### - ################# - # Iterate over all values to draw the different slices - color = 0 - - #create value sum in order to divide the bars - try: - valuesum = sum(values) - except ValueError: - valuesum = 0.0 - - for value in values: - valuesum = valuesum + float(value) - - # Init offset - offset = 0 - - if draw_blur: - # Create rectangle element - shadow = inkex.etree.Element(inkex.addNS("rect", "svg")) - # Set chart position to center of document. - if not rotate: - shadow.set('x', str(width/2)) - shadow.set('y', str(height/2 - bar_height/2)) - else: - shadow.set('x', str(width/2)) - shadow.set('y', str(height/2)) - # Set rectangle properties - if not rotate: - shadow.set("width", str(bar_width)) - shadow.set("height", str(bar_height/2)) - else: - shadow.set("width",str(bar_height/2)) - shadow.set("height", str(bar_width)) - # Set shadow blur (connect to filter object in xml path) - shadow.set("style", "filter:url(#filter)") - layer.append(shadow) - - i = 0 - # Draw Single bars - for value in values: - - # Calculate the individual heights normalized on 100units - normedvalue = (bar_height / valuesum) * float(value) - - # Create rectangle element - rect = inkex.etree.Element(inkex.addNS('rect', 'svg')) - - # Set chart position to center of document. - if not rotate: - rect.set('x', str(width / 2 )) - rect.set('y', str(height / 2 - offset - normedvalue)) - else: - rect.set('x', str(width / 2 + offset )) - rect.set('y', str(height / 2 )) - # Set rectangle properties - if not rotate: - rect.set("width", str(bar_width)) - rect.set("height", str(normedvalue)) - else: - rect.set("height", str(bar_width)) - rect.set("width", str(normedvalue)) - rect.set("style", "fill:" + colors[color % color_count]) - - #If text is given, draw short paths and add the text - # TODO: apply overlap workaround for visible gaps in between - if keys_present: - if not rotate: - path = inkex.etree.Element(inkex.addNS("path", "svg")) - path.set("d","m " + str((width + bar_width)/2) + "," - + str(height/2 - offset - (normedvalue / 2)) + " " - + str(bar_width/2 + text_offset) + ",0") - path.set("style", "fill:none;stroke:" + font_color - + ";stroke-width:" + str(stroke_width) - + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1") - layer.append(path) - text = inkex.etree.Element(inkex.addNS('text', 'svg')) - text.set("x", str(width/2 + bar_width + text_offset + 1)) - text.set("y", str(height/ 2 - offset + font_size/3 - (normedvalue/2))) - text.set("style", "font-size:" + str(font_size) - + "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:" - + font + ";-inkscape-font-specification:Bitstream Charter;fill:" + font_color) - text.text = keys[cnt] - cnt = cnt + 1 - layer.append(text) - else: - path = inkex.etree.Element(inkex.addNS("path", "svg")) - path.set("d","m " + str((width)/2 + offset + normedvalue/2) + "," - + str(height / 2 + bar_width/2) + " 0," - + str(bar_width/2 + (font_size * i) + text_offset)) #line - path.set("style", "fill:none;stroke:" + font_color - + ";stroke-width:" + str(stroke_width) - + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1") - layer.append(path) - text = inkex.etree.Element(inkex.addNS('text', 'svg')) - text.set("x", str((width)/2 + offset + normedvalue/2 - font_size/3)) - text.set("y", str((height/2) + bar_width + (font_size * (i + 1)) + text_offset)) - text.set("style", "font-size:" + str(font_size) - + "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:" - + font + ";-inkscape-font-specification:Bitstream Charter;fill:" + font_color) - text.text = keys[color] - layer.append(text) - - # Increase Offset and Color - offset = offset + normedvalue - color = (color + 1) % 8 - - # Draw rectangle - layer.append(rect) - i += 1 - - # set x position for heading line - if not rotate: - heading_x = width/2 + offset + normedvalue # TODO: adjust - else: - heading_x = width/2 + offset + normedvalue # TODO: adjust - - if headings and input_type == "\"file\"": - headingtext = inkex.etree.Element(inkex.addNS('text', 'svg')) - headingtext.set("y", str(height/2 + heading_offset)) - headingtext.set("x", str(heading_x)) - headingtext.set("style", "font-size:" + str(font_size + 4)\ - + "px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:"\ - + font + ";-inkscape-font-specification:Bitstream Charter;text-align:end;text-anchor:end;fill:"\ - + font_color) - - headingtext.text = heading - layer.append(headingtext) - - def getUnittouu(self, param): - try: - return inkex.unittouu(param) - except AttributeError: - return self.unittouu(param) - -if __name__ == '__main__': - # Create effect instance and apply it. - effect = NiceChart() - effect.affect() diff --git a/share/extensions/param_curves.inx b/share/extensions/param_curves.inx deleted file mode 100644 index 53d4e1337..000000000 --- a/share/extensions/param_curves.inx +++ /dev/null @@ -1,49 +0,0 @@ -<?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); -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> diff --git a/share/extensions/param_curves.py b/share/extensions/param_curves.py deleted file mode 100755 index 6cd54a691..000000000 --- a/share/extensions/param_curves.py +++ /dev/null @@ -1,252 +0,0 @@ -#!/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 whether 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 deleted file mode 100644 index 49b443c42..000000000 --- a/share/extensions/pathalongpath.inx +++ /dev/null @@ -1,39 +0,0 @@ -<?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="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 scatters or bends a pattern along arbitrary "skeleton" paths. The pattern is the topmost object in the selection. Groups of paths, shapes or 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">pathalongpath.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/pathalongpath.py b/share/extensions/pathalongpath.py deleted file mode 100755 index b8834a940..000000000 --- a/share/extensions/pathalongpath.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -barraud@math.univ-lille1.fr - -Quick description: -This script deforms an object (the pattern) along other paths (skeletons)... -The first selected object is the pattern -the last selected ones are the skeletons. - -Imagine a straight horizontal line L in the middle of the bounding box of the pattern. -Consider the normal bundle of L: the collection of all the vertical lines meeting L. -Consider this as the initial state of the plane; in particular, think of the pattern -as painted on these lines. - -Now move and bend L to make it fit a skeleton, and see what happens to the normals: -they move and rotate, deforming the pattern. -''' -# standard library -import copy -import math -import re -import random -# local library -import inkex -import cubicsuperpath -import bezmisc -import pathmodifier -import simpletransform - - -def flipxy(path): - for pathcomp in path: - for ctl in pathcomp: - for pt in ctl: - tmp=pt[0] - pt[0]=-pt[1] - pt[1]=-tmp - -def offset(pathcomp,dx,dy): - for ctl in pathcomp: - for pt in ctl: - pt[0]+=dx - pt[1]+=dy - -def stretch(pathcomp,xscale,yscale,org): - for ctl in pathcomp: - for pt in ctl: - pt[0]=org[0]+(pt[0]-org[0])*xscale - pt[1]=org[1]+(pt[1]-org[1])*yscale - -def linearize(p,tolerance=0.001): - ''' - This function receives a component of a 'cubicsuperpath' and returns two things: - The path subdivided in many straight segments, and an array containing the length of each segment. - - We could work with bezier path as well, but bezier arc lengths are (re)computed for each point - in the deformed object. For complex paths, this might take a while. - ''' - zero=0.000001 - i=0 - d=0 - lengths=[] - while i<len(p)-1: - box = bezmisc.pointdistance(p[i ][1],p[i ][2]) - box += bezmisc.pointdistance(p[i ][2],p[i+1][0]) - box += bezmisc.pointdistance(p[i+1][0],p[i+1][1]) - chord = bezmisc.pointdistance(p[i][1], p[i+1][1]) - if (box - chord) > tolerance: - b1, b2 = bezmisc.beziersplitatt([p[i][1],p[i][2],p[i+1][0],p[i+1][1]], 0.5) - p[i ][2][0],p[i ][2][1]=b1[1] - p[i+1][0][0],p[i+1][0][1]=b2[2] - p.insert(i+1,[[b1[2][0],b1[2][1]],[b1[3][0],b1[3][1]],[b2[1][0],b2[1][1]]]) - else: - d=(box+chord)/2 - lengths.append(d) - i+=1 - new=[p[i][1] for i in range(0,len(p)-1) if lengths[i]>zero] - new.append(p[-1][1]) - lengths=[l for l in lengths if l>zero] - return(new,lengths) - -class PathAlongPath(pathmodifier.Diffeo): - def __init__(self): - pathmodifier.Diffeo.__init__(self) - self.OptionParser.add_option("--title") - self.OptionParser.add_option("-n", "--noffset", - action="store", type="float", - dest="noffset", default=0.0, help="normal offset") - self.OptionParser.add_option("-t", "--toffset", - action="store", type="float", - dest="toffset", default=0.0, help="tangential offset") - self.OptionParser.add_option("-k", "--kind", - action="store", type="string", - dest="kind", default=True, - help="choose between wave or snake effect") - self.OptionParser.add_option("-c", "--copymode", - action="store", type="string", - dest="copymode", default=True, - help="repeat the path to fit deformer's length") - self.OptionParser.add_option("-p", "--space", - action="store", type="float", - dest="space", default=0.0) - self.OptionParser.add_option("-v", "--vertical", - action="store", type="inkbool", - dest="vertical", default=False, - help="reference path is vertical") - self.OptionParser.add_option("-d", "--duplicate", - 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): - - idList=self.options.ids - idList=pathmodifier.zSort(self.document.getroot(),idList) - id = idList[-1] - self.patterns={id:self.selected[id]} - -## ##first selected->pattern, all but first selected-> skeletons -## id = self.options.ids[-1] -## self.patterns={id:self.selected[id]} - - if self.options.duplicate: - self.patterns=self.duplicateNodes(self.patterns) - self.expandGroupsUnlinkClones(self.patterns, True, True) - self.objectsToPaths(self.patterns) - del self.selected[id] - - self.skeletons=self.selected - self.expandGroupsUnlinkClones(self.skeletons, True, False) - self.objectsToPaths(self.skeletons) - - def lengthtotime(self,l): - ''' - Receives an arc length l, and returns the index of the segment in self.skelcomp - containing the corresponding point, to gether with the position of the point on this segment. - - If the deformer is closed, do computations modulo the toal length. - ''' - if self.skelcompIsClosed: - l=l % sum(self.lengths) - if l<=0: - return 0,l/self.lengths[0] - i=0 - while (i<len(self.lengths)) and (self.lengths[i]<=l): - l-=self.lengths[i] - i+=1 - t=l/self.lengths[min(i,len(self.lengths)-1)] - return i, t - - def applyDiffeo(self,bpt,vects=()): - ''' - The kernel of this stuff: - bpt is a base point and for v in vectors, v'=v-p is a tangent vector at bpt. - ''' - s=bpt[0]-self.skelcomp[0][0] - i,t=self.lengthtotime(s) - if i==len(self.skelcomp)-1: - x,y=bezmisc.tpoint(self.skelcomp[i-1],self.skelcomp[i],1+t) - dx=(self.skelcomp[i][0]-self.skelcomp[i-1][0])/self.lengths[-1] - dy=(self.skelcomp[i][1]-self.skelcomp[i-1][1])/self.lengths[-1] - else: - x,y=bezmisc.tpoint(self.skelcomp[i],self.skelcomp[i+1],t) - dx=(self.skelcomp[i+1][0]-self.skelcomp[i][0])/self.lengths[i] - dy=(self.skelcomp[i+1][1]-self.skelcomp[i][1])/self.lengths[i] - - vx=0 - vy=bpt[1]-self.skelcomp[0][1] - if self.options.wave: - bpt[0]=x+vx*dx - bpt[1]=y+vy+vx*dy - else: - bpt[0]=x+vx*dx-vy*dy - bpt[1]=y+vx*dy+vy*dx - - for v in vects: - vx=v[0]-self.skelcomp[0][0]-s - vy=v[1]-self.skelcomp[0][1] - if self.options.wave: - v[0]=x+vx*dx - v[1]=y+vy+vx*dy - else: - v[0]=x+vx*dx-vy*dy - v[1]=y+vx*dy+vy*dx - - def effect(self): - if len(self.options.ids)<2: - inkex.errormsg(_("This extension requires two selected paths.")) - return - self.prepareSelectionList() - self.options.wave = (self.options.kind=="Ribbon") - if self.options.copymode=="Single": - self.options.repeat =False - self.options.stretch=False - elif self.options.copymode=="Repeated": - self.options.repeat =True - self.options.stretch=False - elif self.options.copymode=="Single, stretched": - self.options.repeat =False - self.options.stretch=True - elif self.options.copymode=="Repeated, stretched": - self.options.repeat =True - self.options.stretch=True - - bbox=simpletransform.computeBBox(self.patterns.values()) - - 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': - d = node.get('d') - p0 = cubicsuperpath.parsePath(d) - if self.options.vertical: - flipxy(p0) - - newp=[] - for skelnode in self.skeletons.itervalues(): - self.curSekeleton=cubicsuperpath.parsePath(skelnode.get('d')) - if self.options.vertical: - flipxy(self.curSekeleton) - for comp in self.curSekeleton: - p=copy.deepcopy(p0) - self.skelcomp,self.lengths=linearize(comp) - #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! - self.skelcompIsClosed = (self.skelcomp[0]==self.skelcomp[-1]) - - length=sum(self.lengths) - xoffset=self.skelcomp[0][0]-bbox[0]+self.options.toffset - yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2-self.options.noffset - - - if self.options.repeat: - NbCopies=max(1,int(round((length+self.options.space)/dx))) - width=dx*NbCopies - if not self.skelcompIsClosed: - width-=self.options.space - bbox=bbox[0],bbox[0]+width, bbox[2],bbox[3] - new=[] - for sub in p: - for i in range(0,NbCopies,1): - new.append(copy.deepcopy(sub)) - offset(sub,dx,0) - p=new - - for sub in p: - offset(sub,xoffset,yoffset) - - if self.options.stretch: - if not width: - exit(_("The 'stretch' option requires that the pattern must have non-zero width :\nPlease edit the pattern width.")) - for sub in p: - stretch(sub,length/width,1,self.skelcomp[0]) - - for sub in p: - for ctlpt in sub: - self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) - - if self.options.vertical: - flipxy(p) - newp+=p - - node.set('d', cubicsuperpath.formatPath(newp)) - -if __name__ == '__main__': - e = PathAlongPath() - e.affect() - - -# 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 deleted file mode 100755 index c31702a0d..000000000 --- a/share/extensions/pathmodifier.py +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -barraud@math.univ-lille1.fr - -This code defines a basic class (PathModifier) of effects whose purpose is -to somehow deform given objects: one common tasks for all such effect is to -convert shapes, groups, clones to paths. The class has several functions to -make this (more or less!) easy. -As an example, a second class (Diffeo) is derived from it, -to implement deformations of the form X=f(x,y), Y=g(x,y)... - -TODO: Several handy functions are defined, that might in fact be of general -interest and that should be shipped out in separate files... -''' -# standard library -import copy -import math -import re -import random -# local library -import inkex -import cubicsuperpath -import bezmisc -import simplestyle -from simpletransform import * - -#################################################################### -##-- zOrder computation... -##-- this should be shipped out in a separate file. inkex.py? - -def zSort(inNode,idList): - sortedList=[] - theid = inNode.get("id") - if theid in idList: - sortedList.append(theid) - for child in inNode: - if len(sortedList)==len(idList): - break - sortedList+=zSort(child,idList) - return sortedList - - -class PathModifier(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - -################################## -#-- Selectionlists manipulation -- -################################## - - def duplicateNodes(self, aList): - clones={} - for id,node in aList.iteritems(): - clone=copy.deepcopy(node) - #!!!--> should it be given an id? - #seems to work without this!?! - myid = node.tag.split('}')[-1] - clone.set("id", self.uniqueId(myid)) - node.getparent().append(clone) - clones[clone.get("id")]=clone - return(clones) - - def uniqueId(self, prefix): - id="%s%04i"%(prefix,random.randint(0,9999)) - while len(self.document.getroot().xpath('//*[@id="%s"]' % id,namespaces=inkex.NSS)): - id="%s%04i"%(prefix,random.randint(0,9999)) - return(id) - - def expandGroups(self,aList,transferTransform=True): - for id, node in aList.items(): - if node.tag == inkex.addNS('g','svg') or node.tag=='g': - mat=parseTransform(node.get("transform")) - for child in node: - if transferTransform: - applyTransformToNode(mat,child) - aList.update(self.expandGroups({child.get('id'):child})) - if transferTransform and node.get("transform"): - del node.attrib["transform"] - del aList[id] - return(aList) - - def expandGroupsUnlinkClones(self,aList,transferTransform=True,doReplace=True): - for id in aList.keys()[:]: - node=aList[id] - if node.tag == inkex.addNS('g','svg') or node.tag=='g': - self.expandGroups(aList,transferTransform) - self.expandGroupsUnlinkClones(aList,transferTransform,doReplace) - #Hum... not very efficient if there are many clones of groups... - - elif node.tag == inkex.addNS('use','svg') or node.tag=='use': - refnode=self.refNode(node) - newnode=self.unlinkClone(node,doReplace) - del aList[id] - - style = simplestyle.parseStyle(node.get('style') or "") - refstyle=simplestyle.parseStyle(refnode.get('style') or "") - style.update(refstyle) - newnode.set('style',simplestyle.formatStyle(style)) - - newid=newnode.get('id') - aList.update(self.expandGroupsUnlinkClones({newid:newnode},transferTransform,doReplace)) - return aList - - def recursNewIds(self,node): - if node.get('id'): - node.set('id',self.uniqueId(node.tag)) - for child in node: - self.recursNewIds(child) - - def refNode(self,node): - if node.get(inkex.addNS('href','xlink')): - refid=node.get(inkex.addNS('href','xlink')) - path = '//*[@id="%s"]' % refid[1:] - newNode = self.document.getroot().xpath(path, namespaces=inkex.NSS)[0] - return newNode - else: - raise AssertionError, "Trying to follow empty xlink.href attribute." - - def unlinkClone(self,node,doReplace): - if node.tag == inkex.addNS('use','svg') or node.tag=='use': - newNode = copy.deepcopy(self.refNode(node)) - self.recursNewIds(newNode) - applyTransformToNode(parseTransform(node.get('transform')),newNode) - - if doReplace: - parent=node.getparent() - parent.insert(parent.index(node),newNode) - parent.remove(node) - - return newNode - else: - raise AssertionError, "Only clones can be unlinked..." - - - -################################ -#-- Object conversion ---------- -################################ - - def rectToPath(self,node,doReplace=True): - if node.tag == inkex.addNS('rect','svg'): - x =float(node.get('x')) - y =float(node.get('y')) - #FIXME: no exception anymore and sometimes just one - try: - rx=float(node.get('rx')) - ry=float(node.get('ry')) - except: - rx=0 - ry=0 - w =float(node.get('width' )) - h =float(node.get('height')) - d ='M %f,%f '%(x+rx,y) - d+='L %f,%f '%(x+w-rx,y) - d+='A %f,%f,%i,%i,%i,%f,%f '%(rx,ry,0,0,1,x+w,y+ry) - d+='L %f,%f '%(x+w,y+h-ry) - d+='A %f,%f,%i,%i,%i,%f,%f '%(rx,ry,0,0,1,x+w-rx,y+h) - d+='L %f,%f '%(x+rx,y+h) - d+='A %f,%f,%i,%i,%i,%f,%f '%(rx,ry,0,0,1,x,y+h-ry) - d+='L %f,%f '%(x,y+ry) - d+='A %f,%f,%i,%i,%i,%f,%f '%(rx,ry,0,0,1,x+rx,y) - - newnode=inkex.etree.Element('path') - newnode.set('d',d) - newnode.set('id', self.uniqueId('path')) - newnode.set('style',node.get('style')) - nnt = node.get('transform') - if nnt: - newnode.set('transform',nnt) - fuseTransform(newnode) - if doReplace: - parent=node.getparent() - parent.insert(parent.index(node),newnode) - parent.remove(node) - return newnode - - def groupToPath(self,node,doReplace=True): - if node.tag == inkex.addNS('g','svg'): - newNode = inkex.etree.SubElement(self.current_layer,inkex.addNS('path','svg')) - - newstyle = simplestyle.parseStyle(node.get('style') or "") - newp = [] - for child in node: - childstyle = simplestyle.parseStyle(child.get('style') or "") - childstyle.update(newstyle) - newstyle.update(childstyle) - childAsPath = self.objectToPath(child,False) - newp += cubicsuperpath.parsePath(childAsPath.get('d')) - newNode.set('d',cubicsuperpath.formatPath(newp)) - newNode.set('style',simplestyle.formatStyle(newstyle)) - - self.current_layer.remove(newNode) - if doReplace: - parent=node.getparent() - parent.insert(parent.index(node),newNode) - parent.remove(node) - - return newNode - else: - raise AssertionError - - def objectToPath(self,node,doReplace=True): - #--TODO: support other object types!!!! - #--TODO: make sure cubicsuperpath supports A and Q commands... - if node.tag == inkex.addNS('rect','svg'): - return(self.rectToPath(node,doReplace)) - if node.tag == inkex.addNS('g','svg'): - return(self.groupToPath(node,doReplace)) - elif node.tag == inkex.addNS('path','svg') or node.tag == 'path': - #remove inkscape attributes, otherwise any modif of 'd' will be discarded! - for attName in node.attrib.keys(): - if ("sodipodi" in attName) or ("inkscape" in attName): - del node.attrib[attName] - fuseTransform(node) - return node - elif node.tag == inkex.addNS('use','svg') or node.tag == 'use': - newNode = self.unlinkClone(node,doReplace) - return self.objectToPath(newNode,doReplace) - else: - inkex.errormsg(_("Please first convert objects to paths! (Got [%s].)") % node.tag) - return None - - def objectsToPaths(self,aList,doReplace=True): - newSelection={} - for id,node in aList.items(): - newnode=self.objectToPath(node,doReplace) - del aList[id] - aList[newnode.get('id')]=newnode - - -################################ -#-- Action ---------- -################################ - - #-- overwrite this method in subclasses... - def effect(self): - #self.duplicateNodes(self.selected) - #self.expandGroupsUnlinkClones(self.selected, True) - self.objectsToPaths(self.selected, True) - self.bbox=computeBBox(self.selected.values()) - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - p = cubicsuperpath.parsePath(d) - - #do what ever you want with p! - - node.set('d',cubicsuperpath.formatPath(p)) - - -class Diffeo(PathModifier): - def __init__(self): - inkex.Effect.__init__(self) - - def applyDiffeo(self,bpt,vects=()): - ''' - bpt is a base point and for v in vectors, v'=v-p is a tangent vector at bpt. - Defaults to identity! - ''' - for v in vects: - v[0]-=bpt[0] - v[1]-=bpt[1] - - #-- your transformations go here: - #x,y=bpt - #bpt[0]=f(x,y) - #bpt[1]=g(x,y) - #for v in vects: - # vx,vy=v - # v[0]=df/dx(x,y)*vx+df/dy(x,y)*vy - # v[1]=dg/dx(x,y)*vx+dg/dy(x,y)*vy - # - #-- !caution! y-axis is pointing downward! - - for v in vects: - v[0]+=bpt[0] - v[1]+=bpt[1] - - - def effect(self): - #self.duplicateNodes(self.selected) - self.expandGroupsUnlinkClones(self.selected, True) - self.expandGroups(self.selected, True) - self.objectsToPaths(self.selected, True) - self.bbox=computeBBox(self.selected.values()) - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg') or node.tag=='path': - d = node.get('d') - p = cubicsuperpath.parsePath(d) - - for sub in p: - for ctlpt in sub: - self.applyDiffeo(ctlpt[1],(ctlpt[0],ctlpt[2])) - - node.set('d',cubicsuperpath.formatPath(p)) - -#e = Diffeo() -#e.affect() - - -# 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 deleted file mode 100644 index 02d00a3ca..000000000 --- a/share/extensions/pathscatter.inx +++ /dev/null @@ -1,41 +0,0 @@ -<?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="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 deleted file mode 100755 index a56ab8ac2..000000000 --- a/share/extensions/pathscatter.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -barraud@math.univ-lille1.fr - -Quick description: -This script deforms an object (the pattern) along other paths (skeletons)... -The first selected object is the pattern -the last selected ones are the skeletons. - -Imagine a straight horizontal line L in the middle of the bounding box of the pattern. -Consider the normal bundle of L: the collection of all the vertical lines meeting L. -Consider this as the initial state of the plane; in particular, think of the pattern -as painted on these lines. - -Now move and bend L to make it fit a skeleton, and see what happens to the normals: -they move and rotate, deforming the pattern. -''' -# standard library -import copy -import math -import re -import random -# third party -from lxml import etree -# local library -import inkex -import cubicsuperpath -import bezmisc -import pathmodifier -import simpletransform - -def zSort(inNode,idList): - sortedList=[] - theid = inNode.get("id") - if theid in idList: - sortedList.append(theid) - for child in inNode: - if len(sortedList)==len(idList): - break - sortedList+=zSort(child,idList) - return sortedList - - -def flipxy(path): - for pathcomp in path: - for ctl in pathcomp: - for pt in ctl: - tmp=pt[0] - pt[0]=-pt[1] - pt[1]=-tmp - -def offset(pathcomp,dx,dy): - for ctl in pathcomp: - for pt in ctl: - pt[0]+=dx - pt[1]+=dy - -def stretch(pathcomp,xscale,yscale,org): - for ctl in pathcomp: - for pt in ctl: - pt[0]=org[0]+(pt[0]-org[0])*xscale - pt[1]=org[1]+(pt[1]-org[1])*yscale - -def linearize(p,tolerance=0.001): - ''' - This function receives a component of a 'cubicsuperpath' and returns two things: - The path subdivided in many straight segments, and an array containing the length of each segment. - - We could work with bezier path as well, but bezier arc lengths are (re)computed for each point - in the deformed object. For complex paths, this might take a while. - ''' - zero=0.000001 - i=0 - d=0 - lengths=[] - while i<len(p)-1: - box = bezmisc.pointdistance(p[i ][1],p[i ][2]) - box += bezmisc.pointdistance(p[i ][2],p[i+1][0]) - box += bezmisc.pointdistance(p[i+1][0],p[i+1][1]) - chord = bezmisc.pointdistance(p[i][1], p[i+1][1]) - if (box - chord) > tolerance: - b1, b2 = bezmisc.beziersplitatt([p[i][1],p[i][2],p[i+1][0],p[i+1][1]], 0.5) - p[i ][2][0],p[i ][2][1]=b1[1] - p[i+1][0][0],p[i+1][0][1]=b2[2] - p.insert(i+1,[[b1[2][0],b1[2][1]],[b1[3][0],b1[3][1]],[b2[1][0],b2[1][1]]]) - else: - d=(box+chord)/2 - lengths.append(d) - i+=1 - new=[p[i][1] for i in range(0,len(p)-1) if lengths[i]>zero] - new.append(p[-1][1]) - lengths=[l for l in lengths if l>zero] - return(new,lengths) - -class PathScatter(pathmodifier.Diffeo): - def __init__(self): - pathmodifier.Diffeo.__init__(self) - self.OptionParser.add_option("--title") - self.OptionParser.add_option("-n", "--noffset", - action="store", type="float", - dest="noffset", default=0.0, help="normal offset") - 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, - help="choose between wave or snake effect") - self.OptionParser.add_option("-s", "--stretch", - action="store", type="inkbool", - dest="stretch", default=True, - help="repeat the path to fit deformer's length") - self.OptionParser.add_option("-p", "--space", - action="store", type="float", - dest="space", default=0.0) - self.OptionParser.add_option("-v", "--vertical", - action="store", type="inkbool", - dest="vertical", default=False, - help="reference path is vertical") - self.OptionParser.add_option("-d", "--duplicate", - action="store", type="inkbool", - dest="duplicate", default=False, - help="duplicate pattern before deformation") - self.OptionParser.add_option("-c", "--copymode", - 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): - - idList=self.options.ids - idList=zSort(self.document.getroot(),idList) - - ##first selected->pattern, all but first selected-> skeletons - #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) - - if self.options.copymode=="copy": - duplist=self.duplicateNodes({id:self.patternNode}) - self.patternNode = duplist.values()[0] - - #TODO: allow 4th option: duplicate the first copy and clone the next ones. - if "%s"%self.options.copymode=="clone": - self.patternNode = etree.Element('{http://www.w3.org/2000/svg}use') - self.patternNode.set('{http://www.w3.org/1999/xlink}href',"#%s"%id) - self.gNode.append(self.patternNode) - - self.skeletons=self.selected - del self.skeletons[id] - self.expandGroupsUnlinkClones(self.skeletons, True, False) - self.objectsToPaths(self.skeletons,False) - - def lengthtotime(self,l): - ''' - Receives an arc length l, and returns the index of the segment in self.skelcomp - containing the corresponding point, to gether with the position of the point on this segment. - - If the deformer is closed, do computations modulo the total length. - ''' - if self.skelcompIsClosed: - l=l % sum(self.lengths) - if l<=0: - return 0,l/self.lengths[0] - i=0 - while (i<len(self.lengths)) and (self.lengths[i]<=l): - l-=self.lengths[i] - i+=1 - t=l/self.lengths[min(i,len(self.lengths)-1)] - return i, t - - def localTransformAt(self,s,follow=True): - ''' - receives a length, and returns the corresponding point and tangent of self.skelcomp - if follow is set to false, returns only the translation - ''' - i,t=self.lengthtotime(s) - if i==len(self.skelcomp)-1: - x,y=bezmisc.tpoint(self.skelcomp[i-1],self.skelcomp[i],1+t) - dx=(self.skelcomp[i][0]-self.skelcomp[i-1][0])/self.lengths[-1] - dy=(self.skelcomp[i][1]-self.skelcomp[i-1][1])/self.lengths[-1] - else: - x,y=bezmisc.tpoint(self.skelcomp[i],self.skelcomp[i+1],t) - dx=(self.skelcomp[i+1][0]-self.skelcomp[i][0])/self.lengths[i] - dy=(self.skelcomp[i+1][1]-self.skelcomp[i][1])/self.lengths[i] - if follow: - mat=[[dx,-dy,x],[dy,dx,y]] - else: - mat=[[1,0,x],[0,1,y]] - return mat - - - def effect(self): - - if len(self.options.ids)<2: - 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]] - if self.options.vertical: - bbox=[-bbox[3],-bbox[2],bbox[0],bbox[1]] - mat=simpletransform.composeTransform([[0,-1,0],[1,0,0]],mat) - mat[1][2] += self.options.noffset - simpletransform.applyTransformToNode(mat,self.patternNode) - - 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: - self.skelcomp,self.lengths=linearize(comp) - #!!!!>----> TODO: really test if path is closed! end point==start point is not enough! - self.skelcompIsClosed = (self.skelcomp[0]==self.skelcomp[-1]) - - length=sum(self.lengths) - if self.options.stretch: - dx=width+self.options.space - n=int((length-self.options.toffset+self.options.space)/dx) - if n>0: - dx=(length-self.options.toffset)/n - - - xoffset=self.skelcomp[0][0]-bbox[0]+self.options.toffset - yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2-self.options.noffset - - 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)]) - - 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 = patternList[random.randint(0, len(patternList)-1)].tag.split('}')[-1] - clone.set("id", self.uniqueId(myid)) - self.gNode.append(clone) - - simpletransform.applyTransformToNode(mat,clone) - - s+=dx - self.patternNode.getparent().remove(self.patternNode) - -if __name__ == '__main__': - e = PathScatter() - e.affect() - - -# 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 deleted file mode 100644 index 20285e2a6..000000000 --- a/share/extensions/perfectboundcover.inx +++ /dev/null @@ -1,43 +0,0 @@ -<?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" appearance="header">Book Properties</_param> - <param name="width" precision="3" type="float" indent="1" min="0.0" max="100.000" _gui-text="Book Width (inches):">6</param> - <param name="height" precision="3" type="float" indent="1" min="0.0" max="100.000" _gui-text="Book Height (inches):">9</param> - <param name="pages" type="int" indent="1" min="4" max="6000" _gui-text="Number of Pages:">64</param> - <param name="removeguides" type="boolean" indent="1" _gui-text="Remove existing guides">true</param> - <_param name="paper" type="description" appearance="header">Interior Pages</_param> - <param name="paperthicknessmeasurement" _gui-text="Paper Thickness Measurement:" type="enum" indent="1"> - <_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" indent="1" min="0.000" max="1000.000" _gui-text="Value:">0</param> - <_param name="cover" type="description" appearance="header">Cover</_param> - <param name="coverthicknessmeasurement" _gui-text="Cover Thickness Measurement:" type="enum" indent="1"> - <_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" indent="1" min="0.000" max="1000.000" _gui-text="Value:">0</param> - <param precision="3" name="bleed" type="float" indent="1" min="0.000" max="1.000" _gui-text="Bleed (in):">.25</param> - <_param name="warning" type="description" indent="1">Note: Bond Weight # calculations are a best-guess estimate.</_param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Layout"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">perfectboundcover.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/perfectboundcover.py b/share/extensions/perfectboundcover.py deleted file mode 100755 index e69bcf4c2..000000000 --- a/share/extensions/perfectboundcover.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Bintz, jcoswell@cosellproductions.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import sys, inkex - -def caliper_to_ppi(caliper): - return 2 / caliper - -def bond_weight_to_ppi(bond_weight): - return caliper_to_ppi(bond_weight * .0002) - -def points_to_ppi(points): - return caliper_to_ppi(points / 1000.0) - -class PerfectBoundCover(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--width", - action="store", type="float", - dest="width", default=6.0, - help="cover width (in)") - self.OptionParser.add_option("--height", - action="store", type="float", - dest="height", default=9.0, - help="cover height (in)") - self.OptionParser.add_option("--pages", - action="store", type="int", - dest="pages", default=64, - help="number of pages") - self.OptionParser.add_option("--paperthicknessmeasurement", - action="store", type="string", - dest="paperthicknessmeasurement", default=100.0, - help="paper thickness measurement") - self.OptionParser.add_option("--paperthickness", - action="store", type="float", - dest="paperthickness", default=0.0, - help="paper thickness") - self.OptionParser.add_option("--coverthicknessmeasurement", - action="store", type="string", - dest="coverthicknessmeasurement", default=100.0, - help="cover thickness measurement") - self.OptionParser.add_option("--coverthickness", - action="store", type="float", - dest="coverthickness", default=0.0, - help="cover thickness") - self.OptionParser.add_option("--bleed", - action="store", type="float", - dest="bleed", default=0.25, - help="cover bleed (in)") - self.OptionParser.add_option("--removeguides", - action="store", type="inkbool", - dest="removeguides", default=False, - help="remove guides") - self.OptionParser.add_option("--book", - action="store", type="string", - dest="book", default=False, - help="dummy") - self.OptionParser.add_option("--cover", - action="store", type="string", - dest="cover", default=False, - help="dummy") - self.OptionParser.add_option("--paper", - action="store", type="string", - dest="paper", default=False, - help="dummy") - self.OptionParser.add_option("--warning", - action="store", type="string", - dest="warning", default=False, - help="dummy") - def effect(self): - switch = { - "ppi": lambda x: x, - "caliper": lambda x: caliper_to_ppi(x), - "bond_weight": lambda x: bond_weight_to_ppi(x), - "points": lambda x: points_to_ppi(x), - "width": lambda x: x - } - - if self.options.paperthickness > 0: - if self.options.paperthicknessmeasurement == "width": - paper_spine = self.options.paperthickness - else: - paper_spine = self.options.pages / switch[self.options.paperthicknessmeasurement](self.options.paperthickness) - else: - paper_spine = 0 - - if self.options.coverthickness > 0: - if self.options.coverthicknessmeasurement == "width": - cover_spine = self.options.coverthickness - else: - cover_spine = 4.0 / switch[self.options.coverthicknessmeasurement](self.options.coverthickness) - else: - cover_spine = 0 - - spine_width = paper_spine + cover_spine - - document_width = (self.options.bleed + self.options.width * 2) + spine_width - document_height = self.options.bleed * 2 + self.options.height - - root = self.document.getroot() - - root.set("width", "%sin" % document_width) - root.set("height", "%sin" % document_height) - - guides = [] - - guides.append(["horizontal", self.options.bleed]) - guides.append(["horizontal", document_height - self.options.bleed]) - guides.append(["vertical", self.options.bleed]) - guides.append(["vertical", document_width - self.options.bleed]) - guides.append(["vertical", (document_width / 2) - (spine_width / 2)]) - guides.append(["vertical", (document_width / 2) + (spine_width / 2)]) - - namedview = self.document.xpath('/svg:svg/sodipodi:namedview', namespaces=inkex.NSS) - if namedview: - if self.options.removeguides == True: - for node in self.document.xpath('/svg:svg/sodipodi:namedview/sodipodi:guide', namespaces=inkex.NSS): - parent = node.getparent() - parent.remove(node) - for guide in guides: - newguide = inkex.etree.Element(inkex.addNS('guide','sodipodi')) - newguide.set("orientation", guide[0]) - newguide.set("position", "%f" % (guide[1] * 96)) - namedview[0].append(newguide) - - ''' - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path','svg'): - p = cubicsuperpath.parsePath(node.get('d')) - - #lens, total = csplength(p) - #avg = total/numlengths(lens) - #inkex.debug("average segment length: %s" % avg) - - new = [] - for sub in p: - new.append([sub[0][:]]) - i = 1 - while i <= len(sub)-1: - length = cspseglength(new[-1][-1], sub[i]) - if length > self.options.max: - splits = math.ceil(length/self.options.max) - for s in xrange(int(splits),1,-1): - new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s) - new[-1].append(next[:]) - new[-1].append(sub[i]) - i+=1 - - node.set('d',cubicsuperpath.formatPath(new)) - ''' - -if __name__ == '__main__': - e = PerfectBoundCover() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/perspective.inx b/share/extensions/perspective.inx deleted file mode 100644 index 418d3f8cb..000000000 --- a/share/extensions/perspective.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Perspective</_name> - <id>org.ekips.filter.perspective</id> - <dependency type="executable" location="extensions">perspective.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">perspective.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/perspective.py b/share/extensions/perspective.py deleted file mode 100755 index f7d5be606..000000000 --- a/share/extensions/perspective.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python -""" -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -Perspective approach & math by Dmitry Platonov, shadowjack@mail.ru, 2006 -""" -# standard library -import sys -import os -import re -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False -# local library -import inkex -import simplepath -import cubicsuperpath -import simpletransform -from ffgeom import * - -# third party -try: - from numpy import * - from numpy.linalg import * -except: - # Initialize gettext for messages outside an inkex derived class - inkex.localize() - inkex.errormsg(_("Failed to import the numpy or numpy.linalg modules. These modules are required by this extension. Please install them and try again. On a Debian-like system this can be done with the command, sudo apt-get install python-numpy.")) - exit() - -class Project(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - def effect(self): - if len(self.options.ids) < 2: - inkex.errormsg(_("This extension requires two selected paths.")) - exit() - - #obj is selected second - scale = self.unittouu('1px') # convert to document units - doc = self.document.getroot() - h = self.unittouu(doc.xpath('@height', namespaces=inkex.NSS)[0]) - # process viewBox height attribute to correct page scaling - viewBox = doc.get('viewBox') - if viewBox: - viewBox2 = viewBox.split(',') - if len(viewBox2) < 4: - viewBox2 = viewBox.split(' ') - scale *= self.unittouu(self.addDocumentUnit(viewBox2[3])) / h - obj = self.selected[self.options.ids[0]] - envelope = self.selected[self.options.ids[1]] - if obj.get(inkex.addNS('type','sodipodi')): - inkex.errormsg(_("The first selected object is of type '%s'.\nTry using the procedure Path->Object to Path." % obj.get(inkex.addNS('type','sodipodi')))) - exit() - if obj.tag == inkex.addNS('path','svg') or obj.tag == inkex.addNS('g','svg'): - if envelope.tag == inkex.addNS('path','svg'): - mat = simpletransform.composeParents(envelope, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - path = cubicsuperpath.parsePath(envelope.get('d')) - if len(path) < 1 or len(path[0]) < 4: - inkex.errormsg(_("This extension requires that the second selected path be four nodes long.")) - exit() - simpletransform.applyTransformToPath(mat, path) - dp = zeros((4,2), dtype=float64) - for i in range(4): - dp[i][0] = path[0][i][1][0] - dp[i][1] = path[0][i][1][1] - - #query inkscape about the bounding box of obj - q = {'x':0,'y':0,'width':0,'height':0} - file = self.args[-1] - id = self.options.ids[0] - for query in q.keys(): - if bsubprocess: - p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query,id,file), shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - q[query] = scale*float(p.stdout.read()) - err = p.stderr.read() - else: - f,err = os.popen3('inkscape --query-%s --query-id=%s "%s"' % (query,id,file))[1:] - q[query] = scale*float(f.read()) - f.close() - err.close() - sp = array([[q['x'], q['y']+q['height']],[q['x'], q['y']],[q['x']+q['width'], q['y']],[q['x']+q['width'], q['y']+q['height']]], dtype=float64) - else: - if envelope.tag == inkex.addNS('g','svg'): - inkex.errormsg(_("The second selected object is a group, not a path.\nTry using the procedure Object->Ungroup.")) - else: - inkex.errormsg(_("The second selected object is not a path.\nTry using the procedure Path->Object to Path.")) - exit() - else: - inkex.errormsg(_("The first selected object is not a path.\nTry using the procedure Path->Object to Path.")) - exit() - - solmatrix = zeros((8,8), dtype=float64) - free_term = zeros((8), dtype=float64) - for i in (0,1,2,3): - solmatrix[i][0] = sp[i][0] - solmatrix[i][1] = sp[i][1] - solmatrix[i][2] = 1 - solmatrix[i][6] = -dp[i][0]*sp[i][0] - solmatrix[i][7] = -dp[i][0]*sp[i][1] - solmatrix[i+4][3] = sp[i][0] - solmatrix[i+4][4] = sp[i][1] - solmatrix[i+4][5] = 1 - solmatrix[i+4][6] = -dp[i][1]*sp[i][0] - solmatrix[i+4][7] = -dp[i][1]*sp[i][1] - free_term[i] = dp[i][0] - free_term[i+4] = dp[i][1] - - res = solve(solmatrix, free_term) - projmatrix = array([[res[0],res[1],res[2]],[res[3],res[4],res[5]],[res[6],res[7],1.0]],dtype=float64) - if obj.tag == inkex.addNS("path",'svg'): - self.process_path(obj,projmatrix) - if obj.tag == inkex.addNS("g",'svg'): - self.process_group(obj,projmatrix) - - def process_group(self,group,m): - for node in group: - if node.tag == inkex.addNS('path','svg'): - self.process_path(node,m) - if node.tag == inkex.addNS('g','svg'): - self.process_group(node,m) - - def process_path(self,path,m): - mat = simpletransform.composeParents(path, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - d = path.get('d') - p = cubicsuperpath.parsePath(d) - simpletransform.applyTransformToPath(mat, p) - for subs in p: - for csp in subs: - csp[0] = self.project_point(csp[0],m) - csp[1] = self.project_point(csp[1],m) - csp[2] = self.project_point(csp[2],m) - mat = simpletransform.invertTransform(mat) - simpletransform.applyTransformToPath(mat, p) - path.set('d',cubicsuperpath.formatPath(p)) - - def project_point(self,p,m): - x = p[0] - y = p[1] - return [(x*m[0][0] + y*m[0][1] + m[0][2])/(x*m[2][0]+y*m[2][1]+m[2][2]),(x*m[1][0] + y*m[1][1] + m[1][2])/(x*m[2][0]+y*m[2][1]+m[2][2])] - -if __name__ == '__main__': - e = Project() - e.affect() - - -# 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 deleted file mode 100644 index 65ce401be..000000000 --- a/share/extensions/pixelsnap.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_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> - <effect> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">pixelsnap.py</command> - </script> -</inkscape-extension> - - - diff --git a/share/extensions/pixelsnap.py b/share/extensions/pixelsnap.py deleted file mode 100755 index 440cc873e..000000000 --- a/share/extensions/pixelsnap.py +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/env python - -""" -TODO: This only snaps selected elements, and if those elements are part of a - group or layer that has it's own transform, that won't be taken into - account, unless you snap the group or layer as a whole. This can account - for unexpected results in some cases (eg where you've got a non-integer - translation on the layer you're working in, the elements in that layer - won't snap properly). The workaround for now is to snap the whole - group/layer, or remove the transform on the group/layer. - - I could fix it in the code by traversing the parent elements up to the - document root & calculating the cumulative parent_transform. This could - be done at the top of the pixel_snap method if parent_transform==None, - or before calling it for the first time. - -TODO: Transforming points isn't quite perfect, to say the least. In particular, - when translating a point bezier curve, we translate the handles by the same amount. - BUT, some handles that are attached to a particular point are conceptually - handles of the prev/next node. - Best way to fix it would be to keep a list of the fractional_offsets[] of - each point, without transforming anything. Then go through each point and - transform the appropriate handle according to the relevant fraction_offset - in the list. - - i.e. calculate first, then modify. - - In fact, that might be a simpler algorithm anyway -- it avoids having - to keep track of all the first_xy/next_xy guff. - -TODO: make elem_offset return [x_offset, y_offset] so we can handle non-symetric scaling - ------------- - -Note: This doesn't work very well on paths which have both straight segments - and curved segments. - The biggest three problems are: - a) we don't take handles into account (segments where the nodes are - aligned are always treated as straight segments, even where the - handles make it curve) - b) when we snap a straight segment right before/after a curve, it - doesn't make any attempt to keep the transition from the straight - segment to the curve smooth. - c) no attempt is made to keep equal widths equal. (or nearly-equal - widths nearly-equal). For example, font strokes. - - I guess that amounts to the problyem that font hinting solves for fonts. - I wonder if I could find an automatic font-hinting algorithm and munge - it to my purposes? - - Some good autohinting concepts that may help: - http://freetype.sourceforge.net/autohinting/archive/10Mar2000/hinter.html - -Note: Paths that have curves & arcs on some sides of the bounding box won't - be snapped correctly on that side of the bounding box, and nor will they - be translated/resized correctly before the path is modified. Doesn't affect - most applications of this extension, but it highlights the fact that we - take a geometrically simplistic approach to inspecting & modifying the path. -""" - -from __future__ import division - -import sys -# *** numpy causes issue #4 on Mac OS 10.6.2. I use it for -# matrix inverse -- my linear algebra's a bit rusty, but I could implement my -# own matrix inverse function if necessary, I guess. -from numpy import matrix -import simplestyle, simpletransform, simplepath - -# INKEX MODULE -# If you get the "No module named inkex" error, uncomment the relevant line -# below by removing the '#' at the start of the line. -# -#sys.path += ['/usr/share/inkscape/extensions'] # If you're using a standard Linux installation -#sys.path += ['/usr/local/share/inkscape/extensions'] # If you're using a custom Linux installation -#sys.path += ['C:\\Program Files\\Inkscape\\share\\extensions'] # If you're using a standard Windows installation - -try: - import inkex -except ImportError: - raise ImportError("No module named inkex.\nPlease edit the file %s and see the section titled 'INKEX MODULE'" % __file__) - -Precision = 5 # number of digits of precision for comparing float numbers - -MaxGradient = 1/200 # lines that are almost-but-not-quite straight will be snapped, too. - -class TransformError(Exception): pass - -def elemtype(elem, matches): - if not isinstance(matches, (list, tuple)): matches = [matches] - for m in matches: - if elem.tag == inkex.addNS(m, 'svg'): return True - return False - -def invert_transform(transform): - transform = transform[:] # duplicate list to avoid modifying it - transform += [[0, 0, 1]] - inverse = matrix(transform).I.tolist() - inverse.pop() - return inverse - -def transform_point(transform, pt, inverse=False): - """ Better than simpletransform.applyTransformToPoint, - a) coz it's a simpler name - b) coz it returns the new xy, rather than modifying the input - """ - if inverse: - transform = invert_transform(transform) - - x = transform[0][0]*pt[0] + transform[0][1]*pt[1] + transform[0][2] - y = transform[1][0]*pt[0] + transform[1][1]*pt[1] + transform[1][2] - return x,y - -def transform_dimensions(transform, width=None, height=None, inverse=False): - """ Dimensions don't get translated. I'm not sure how much diff rotate/skew - makes in this context, but we currently ignore anything besides scale. - """ - if inverse: transform = invert_transform(transform) - - if width is not None: width *= transform[0][0] - if height is not None: height *= transform[1][1] - - if width is not None and height is not None: return width, height - if width is not None: return width - if height is not None: return height - - -def vertical(pt1, pt2): - hlen = abs(pt1[0] - pt2[0]) - vlen = abs(pt1[1] - pt2[1]) - if vlen==0 and hlen==0: - return True - elif vlen==0: - return False - return (hlen / vlen) < MaxGradient - -def horizontal(pt1, pt2): - hlen = round(abs(pt1[0] - pt2[0]), Precision) - vlen = round(abs(pt1[1] - pt2[1]), Precision) - if hlen==0 and vlen==0: - return True - elif hlen==0: - return False - return (vlen / hlen) < MaxGradient - -class PixelSnapEffect(inkex.Effect): - def elem_offset(self, elem, parent_transform=None): - """ Returns a value which is the amount the - bounding-box is offset due to the stroke-width. - Transform is taken into account. - """ - stroke_width = self.stroke_width(elem) - if stroke_width == 0: return 0 # if there's no stroke, no need to worry about the transform - - transform = self.transform(elem, parent_transform=parent_transform) - if abs(abs(transform[0][0]) - abs(transform[1][1])) > (10**-Precision): - raise TransformError("Selection contains non-symetric scaling") # *** wouldn't be hard to get around this by calculating vertical_offset & horizontal_offset separately, maybe 2 functions, or maybe returning a tuple - - stroke_width = transform_dimensions(transform, width=stroke_width) - - return (stroke_width/2) - - def stroke_width(self, elem, setval=None): - """ Return stroke-width in pixels, untransformed - """ - style = simplestyle.parseStyle(elem.attrib.get('style', '')) - stroke = style.get('stroke', None) - if stroke == 'none': stroke = None - - stroke_width = 0 - if stroke and setval is None: - stroke_width = self.unittouu(style.get('stroke-width', '').strip()) - - if setval: - style['stroke-width'] = str(setval) - elem.attrib['style'] = simplestyle.formatStyle(style) - else: - return stroke_width - - def snap_stroke(self, elem, parent_transform=None): - transform = self.transform(elem, parent_transform=parent_transform) - - stroke_width = self.stroke_width(elem) - if (stroke_width == 0): return # no point raising a TransformError if there's no stroke to snap - - if abs(abs(transform[0][0]) - abs(transform[1][1])) > (10**-Precision): - raise TransformError("Selection contains non-symetric scaling, can't snap stroke width") - - if stroke_width: - stroke_width = transform_dimensions(transform, width=stroke_width) - stroke_width = round(stroke_width) - stroke_width = transform_dimensions(transform, width=stroke_width, inverse=True) - self.stroke_width(elem, stroke_width) - - def transform(self, elem, setval=None, parent_transform=None): - """ Gets this element's transform. Use setval=matrix to - set this element's transform. - You can only specify parent_transform when getting. - """ - transform = elem.attrib.get('transform', '').strip() - - if transform: - transform = simpletransform.parseTransform(transform) - else: - transform = [[1,0,0], [0,1,0], [0,0,1]] - if parent_transform: - transform = simpletransform.composeTransform(parent_transform, transform) - - if setval: - elem.attrib['transform'] = simpletransform.formatTransform(setval) - else: - return transform - - def snap_transform(self, elem): - # Only snaps the x/y translation of the transform, nothing else. - # Scale transforms are handled only in snap_rect() - # Doesn't take any parent_transform into account -- assumes - # that the parent's transform has already been snapped. - transform = self.transform(elem) - if transform[0][1] or transform[1][0]: return # if we've got any skew/rotation, get outta here - - transform[0][2] = round(transform[0][2]) - transform[1][2] = round(transform[1][2]) - - self.transform(elem, transform) - - def transform_path_node(self, transform, path, i): - """ Modifies a segment so that every point is transformed, including handles - """ - segtype = path[i][0].lower() - - if segtype == 'z': return - elif segtype == 'h': - path[i][1][0] = transform_point(transform, [path[i][1][0], 0])[0] - elif segtype == 'v': - path[i][1][0] = transform_point(transform, [0, path[i][1][0]])[1] - else: - first_coordinate = 0 - if (segtype == 'a'): first_coordinate = 5 # for elliptical arcs, skip the radius x/y, rotation, large-arc, and sweep - for j in range(first_coordinate, len(path[i][1]), 2): - x, y = path[i][1][j], path[i][1][j+1] - x, y = transform_point(transform, (x, y)) - path[i][1][j] = x - path[i][1][j+1] = y - - - def pathxy(self, path, i, setval=None): - """ Return the endpoint of the given path segment. - Inspects the segment type to know which elements are the endpoints. - """ - segtype = path[i][0].lower() - x = y = 0 - - if segtype == 'z': i = 0 - - if segtype == 'h': - if setval: path[i][1][0] = setval[0] - else: x = path[i][1][0] - - elif segtype == 'v': - if setval: path[i][1][0] = setval[1] - else: y = path[i][1][0] - else: - if setval and segtype != 'z': - path[i][1][-2] = setval[0] - path[i][1][-1] = setval[1] - else: - x = path[i][1][-2] - y = path[i][1][-1] - - if setval is None: return [x, y] - - def path_bounding_box(self, elem, parent_transform=None): - """ Returns [min_x, min_y], [max_x, max_y] of the transformed - element. (It doesn't make any sense to return the untransformed - bounding box, with the intent of transforming it later, because - the min/max points will be completely different points) - - The returned bounding box includes stroke-width offset. - - This function uses a simplistic algorithm & doesn't take curves - or arcs into account, just node positions. - """ - # If we have a Live Path Effect, modify original-d. If anyone clamours - # for it, we could make an option to ignore paths with Live Path Effects - original_d = '{%s}original-d' % inkex.NSS['inkscape'] - path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d'])) - - transform = self.transform(elem, parent_transform=parent_transform) - offset = self.elem_offset(elem, parent_transform) - - min_x = min_y = max_x = max_y = 0 - for i in range(len(path)): - x, y = self.pathxy(path, i) - x, y = transform_point(transform, (x, y)) - - if i == 0: - min_x = max_x = x - min_y = max_y = y - else: - min_x = min(x, min_x) - min_y = min(y, min_y) - max_x = max(x, max_x) - max_y = max(y, max_y) - - return (min_x-offset, min_y-offset), (max_x+offset, max_y+offset) - - - def snap_path_scale(self, elem, parent_transform=None): - # If we have a Live Path Effect, modify original-d. If anyone clamours - # for it, we could make an option to ignore paths with Live Path Effects - original_d = '{%s}original-d' % inkex.NSS['inkscape'] - path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d'])) - transform = self.transform(elem, parent_transform=parent_transform) - min_xy, max_xy = self.path_bounding_box(elem, parent_transform) - - width = max_xy[0] - min_xy[0] - height = max_xy[1] - min_xy[1] - - # In case somebody tries to snap a 0-high element, - # or a curve/arc with all nodes in a line, and of course - # because we should always check for divide-by-zero! - if (width==0 or height==0): return - - rescale = round(width)/width, round(height)/height - - min_xy = transform_point(transform, min_xy, inverse=True) - max_xy = transform_point(transform, max_xy, inverse=True) - - for i in range(len(path)): - self.transform_path_node([[1, 0, -min_xy[0]], [0, 1, -min_xy[1]]], path, i) # center transform - self.transform_path_node([[rescale[0], 0, 0], - [0, rescale[1], 0]], - path, i) - self.transform_path_node([[1, 0, +min_xy[0]], [0, 1, +min_xy[1]]], path, i) # uncenter transform - - path = simplepath.formatPath(path) - if original_d in elem.attrib: elem.attrib[original_d] = path - else: elem.attrib['d'] = path - - def snap_path_pos(self, elem, parent_transform=None): - # If we have a Live Path Effect, modify original-d. If anyone clamours - # for it, we could make an option to ignore paths with Live Path Effects - original_d = '{%s}original-d' % inkex.NSS['inkscape'] - path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d'])) - transform = self.transform(elem, parent_transform=parent_transform) - min_xy, max_xy = self.path_bounding_box(elem, parent_transform) - - fractional_offset = min_xy[0]-round(min_xy[0]), min_xy[1]-round(min_xy[1])-self.document_offset - fractional_offset = transform_dimensions(transform, fractional_offset[0], fractional_offset[1], inverse=True) - - for i in range(len(path)): - self.transform_path_node([[1, 0, -fractional_offset[0]], - [0, 1, -fractional_offset[1]]], - path, i) - - path = simplepath.formatPath(path) - if original_d in elem.attrib: elem.attrib[original_d] = path - else: elem.attrib['d'] = path - - def snap_path(self, elem, parent_transform=None): - # If we have a Live Path Effect, modify original-d. If anyone clamours - # for it, we could make an option to ignore paths with Live Path Effects - original_d = '{%s}original-d' % inkex.NSS['inkscape'] - path = simplepath.parsePath(elem.attrib.get(original_d, elem.attrib['d'])) - - transform = self.transform(elem, parent_transform=parent_transform) - - if transform[0][1] or transform[1][0]: # if we've got any skew/rotation, get outta here - raise TransformError("Selection contains transformations with skew/rotation") - - offset = self.elem_offset(elem, parent_transform) % 1 - - prev_xy = self.pathxy(path, -1) - first_xy = self.pathxy(path, 0) - for i in range(len(path)): - segtype = path[i][0].lower() - xy = self.pathxy(path, i) - if segtype == 'z': - xy = first_xy - if (i == len(path)-1) or \ - ((i == len(path)-2) and path[-1][0].lower() == 'z'): - next_xy = first_xy - else: - next_xy = self.pathxy(path, i+1) - - if not (xy and prev_xy and next_xy): - prev_xy = xy - continue - - xy_untransformed = tuple(xy) - xy = list(transform_point(transform, xy)) - prev_xy = transform_point(transform, prev_xy) - next_xy = transform_point(transform, next_xy) - - on_vertical = on_horizontal = False - - if horizontal(xy, prev_xy): - if len(path) > 2 or i==0: # on 2-point paths, first.next==first.prev==last and last.next==last.prev==first - xy[1] = prev_xy[1] # make the almost-equal values equal, so they round in the same direction - on_horizontal = True - if horizontal(xy, next_xy): - on_horizontal = True - - if vertical(xy, prev_xy): # as above - if len(path) > 2 or i==0: - xy[0] = prev_xy[0] - on_vertical = True - if vertical(xy, next_xy): - on_vertical = True - - prev_xy = tuple(xy_untransformed) - - fractional_offset = [0,0] - if on_vertical: - fractional_offset[0] = xy[0] - (round(xy[0]-offset) + offset) - if on_horizontal: - fractional_offset[1] = xy[1] - (round(xy[1]-offset) + offset) - self.document_offset - - fractional_offset = transform_dimensions(transform, fractional_offset[0], fractional_offset[1], inverse=True) - self.transform_path_node([[1, 0, -fractional_offset[0]], - [0, 1, -fractional_offset[1]]], - path, i) - - - path = simplepath.formatPath(path) - if original_d in elem.attrib: elem.attrib[original_d] = path - else: elem.attrib['d'] = path - - def snap_rect(self, elem, parent_transform=None): - transform = self.transform(elem, parent_transform=parent_transform) - - if transform[0][1] or transform[1][0]: # if we've got any skew/rotation, get outta here - raise TransformError("Selection contains transformations with skew/rotation") - - offset = self.elem_offset(elem, parent_transform) % 1 - - width = self.unittouu(elem.attrib['width']) - height = self.unittouu(elem.attrib['height']) - x = self.unittouu(elem.attrib['x']) - y = self.unittouu(elem.attrib['y']) - - width, height = transform_dimensions(transform, width, height) - x, y = transform_point(transform, [x, y]) - - # Snap to the nearest pixel - height = round(height) - width = round(width) - x = round(x - offset) + offset # If there's a stroke of non-even width, it's shifted by half a pixel - y = round(y - offset) + offset - - width, height = transform_dimensions(transform, width, height, inverse=True) - x, y = transform_point(transform, [x, y], inverse=True) - - y += self.document_offset/transform[1][1] - - # Position the elem at the newly calculate values - elem.attrib['width'] = str(width) - elem.attrib['height'] = str(height) - elem.attrib['x'] = str(x) - elem.attrib['y'] = str(y) - - def snap_image(self, elem, parent_transform=None): - self.snap_rect(elem, parent_transform) - - def pixel_snap(self, elem, parent_transform=None): - if elemtype(elem, 'g'): - self.snap_transform(elem) - transform = self.transform(elem, parent_transform=parent_transform) - for e in elem: - try: - self.pixel_snap(e, transform) - except TransformError, e: - print >>sys.stderr, e - return - - if not elemtype(elem, ('path', 'rect', 'image')): - return - - self.snap_transform(elem) - try: - self.snap_stroke(elem, parent_transform) - except TransformError, e: - print >>sys.stderr, e - - if elemtype(elem, 'path'): - self.snap_path_scale(elem, parent_transform) - self.snap_path_pos(elem, parent_transform) - self.snap_path(elem, parent_transform) # would be quite useful to make this an option, as scale/pos alone doesn't mess with the path itself, and works well for sans-serif text - elif elemtype(elem, 'rect'): self.snap_rect(elem, parent_transform) - elif elemtype(elem, 'image'): self.snap_image(elem, parent_transform) - - def effect(self): - svg = self.document.getroot() - - self.document_offset = self.unittouu(svg.attrib['height']) % 1 # although SVG units are absolute, the elements are positioned relative to the top of the page, rather than zero - - for id, elem in self.selected.iteritems(): - try: - self.pixel_snap(elem) - except TransformError, e: - print >>sys.stderr, e - - -if __name__ == '__main__': - effect = PixelSnapEffect() - effect.affect() - diff --git a/share/extensions/plotter.inx b/share/extensions/plotter.inx deleted file mode 100644 index a318d5eb8..000000000 --- a/share/extensions/plotter.inx +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Plot</_name> - <id>org.ekips.filter.plot</id> - <dependency type="executable" location="extensions">plotter.py</dependency> - <dependency type="executable" location="extensions">hpgl_decoder.py</dependency> - <dependency type="executable" location="extensions">hpgl_encoder.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="introduction" type="description">Please make sure that all objects you want to plot are converted to paths.</_param> - <param name="tab" type="notebook"> - <page name="misc" _gui-text="Connection Settings "> - <param name="portType" type="optiongroup" _gui-text="Port type:"> - <_option value="serial">Serial</_option> - <_option value="parallel">Parallel</_option> - </param> - <param name="parallelPort" type="string" _gui-text="Parallel port:" _gui-description="The port of your parallel connection, on Windows not currently supported, on Linux something like: '/dev/usb/lp2' (Default: /dev/usb/lp2)">/dev/usb/lp2</param> - <param name="serialPort" type="string" _gui-text="Serial port:" _gui-description="The port of your serial connection, on Windows something like 'COM1', on Linux something like: '/dev/ttyUSB0' (Default: COM1)">COM1</param> - <param name="serialBaudRate" type="enum" _gui-text="Serial baud rate:" _gui-description="The Baud rate of your serial connection (Default: 9600)"> - <item value="9600">9600</item> - <item value="110">110</item> - <item value="300">300</item> - <item value="600">600</item> - <item value="1200">1200</item> - <item value="2400">2400</item> - <item value="4800">4800</item> - <item value="9600">9600</item> - <item value="14400">14400</item> - <item value="19200">19200</item> - <item value="28800">28800</item> - <item value="38400">38400</item> - <item value="56000">56000</item> - <item value="57600">57600</item> - <item value="115200">115200</item> - </param> - <param name="serialByteSize" type="enum" _gui-text="Serial byte size:" _gui-description="The Byte size of your serial connection, 99% of all plotters use the default setting (Default: 8 Bits)"> - <item value="eight">8 Bits</item> - <item value="seven">7 Bits</item> - <item value="six">6 Bits</item> - <item value="five">5 Bits</item> - </param> - <param name="serialStopBits" type="enum" _gui-text="Serial stop bits:" _gui-description="The Stop bits of your serial connection, 99% of all plotters use the default setting (Default: 1 Bit)"> - <item value="one">1 Bit</item> - <item value="onePointFive">1.5 Bits</item> - <item value="two">2 Bits</item> - </param> - <param name="serialParity" type="enum" _gui-text="Serial parity:" _gui-description="The Parity of your serial connection, 99% of all plotters use the default setting (Default: None)"> - <item value="none">None</item> - <item value="even">Even</item> - <item value="odd">Odd</item> - <item value="mark">Mark</item> - <item value="space">Space</item> - </param> - <param name="serialFlowControl" type="enum" _gui-text="Serial flow control:" _gui-description="The Software / Hardware flow control of your serial connection (Default: Software)"> - <_item value="xonxoff">Software (XON/XOFF)</_item> - <_item value="rtscts">Hardware (RTS/CTS)</_item> - <_item value="dsrdtrrtscts">Hardware (DSR/DTR + RTS/CTS)</_item> - <_item value="none">None</_item> - </param> - <param name="commandLanguage" type="enum" _gui-text="Command language:" _gui-description="The command language to use (Default: HPGL)"> - <_item value="HPGL">HPGL</_item> - <_item value="DMPL">DMPL</_item> - <_item value="KNK">KNK Plotter (HPGL variant)</_item> - </param> - <param name="space" type="description"> </param> - <_param name="freezeHelp" type="description">Using wrong settings can under certain circumstances cause Inkscape to freeze. Always save your work before plotting!</_param> - <_param name="serialHelp" type="description">This can be a physical serial connection or a USB-to-Serial bridge. Ask your plotter manufacturer for drivers if needed.</_param> - <_param name="parallelHelp" type="description">Parallel (LPT) connections are not supported.</_param> - </page> - <page name="plotter" _gui-text="Plotter Settings "> - <param name="resolutionX" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution X (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the X axis (Default: 1016.0)">1016.0</param> - <param name="resolutionY" type="float" min="1.0" max="4096.0" precision="1" _gui-text="Resolution Y (dpi):" _gui-description="The amount of steps the plotter moves if it moves for 1 inch on the Y axis (Default: 1016.0)">1016.0</param> - <param name="pen" type="int" min="0" max="99" _gui-text="Pen number:" _gui-description="The number of the pen (tool) to use (Standard: '1')">1</param> - <param name="force" type="int" min="0" max="1000" _gui-text="Pen force (g):" _gui-description="The amount of force pushing down the pen in grams, set to 0 to omit command; most plotters ignore this command (Default: 0)">0</param> - <param name="speed" type="int" min="0" max="10000" _gui-text="Pen speed (cm/s or mm/s):" _gui-description="The speed the pen will move with in centimeters or millimeters per second (depending on your plotter model), set to 0 to omit command. Most plotters ignore this command. (Default: 0)">0</param> - <param name="orientation" type="enum" _gui-text="Rotation (°, clockwise):" _gui-description="Rotation of the drawing (Default: 0°)"> - <item value="0">0</item> - <item value="90">90</item> - <item value="180">180</item> - <item value="270">270</item> - </param> - <param name="mirrorX" type="boolean" _gui-text="Mirror X axis" _gui-description="Check this to mirror the X axis (Default: Unchecked)">false</param> - <param name="mirrorY" type="boolean" _gui-text="Mirror Y axis" _gui-description="Check this to mirror the Y axis (Default: Unchecked)">false</param> - <param name="center" type="boolean" _gui-text="Center zero point" _gui-description="Check this if your plotter uses a centered zero point (Default: Unchecked)">false</param> - <param name="space" type="description"> </param> - <_param name="multiplePensHelp" type="description">If you want to use multiple pens on your pen plotter create one layer for each pen, name the layers "Pen 1", "Pen 2", etc., and put your drawings in the corresponding layers. This overrules the pen number option above.</_param> - </page> - <page name="misc" _gui-text="Plot Features "> - <param name="overcut" type="float" min="0.0" max="100.0" precision="2" _gui-text="Overcut (mm):" _gui-description="The distance in mm that will be cut over the starting point of the path to prevent open paths, set to 0.0 to omit command (Default: 1.00)">1.00</param> - <param name="toolOffset" type="float" min="0.0" max="20.0" precision="2" _gui-text="Tool (Knife) offset correction (mm):" _gui-description="The offset from the tool tip to the tool axis in mm, set to 0.0 to omit command (Default: 0.25)">0.25</param> - <param name="precut" type="boolean" _gui-text="Precut" _gui-description="Check this to cut a small line before the real drawing starts to correctly align the tool orientation. (Default: Checked)">true</param> - <param name="flat" type="float" min="0.1" max="10.0" precision="1" _gui-text="Curve flatness:" _gui-description="Curves are divided into lines, this number controls how fine the curves will be reproduced, the smaller the finer (Default: '1.2')">1.2</param> - <param name="autoAlign" type="boolean" _gui-text="Auto align" _gui-description="Check this to auto align the drawing to the zero point (Plus the tool offset if used). If unchecked you have to make sure that all parts of your drawing are within the document border! (Default: Checked)">true</param> - <param name="space" type="description"> </param> - <param name="debug" type="boolean" _gui-text="Show debug information" _gui-description="Check this to get verbose information about the plot without actually sending something to the plotter (A.k.a. data dump) (Default: Unchecked)">false</param> - <param name="convertObjects" type="boolean" _gui-text="Convert objects to paths" _gui-description="Check this to automatically (nondestructively) convert all objects to paths before plotting (Default: Checked)">true</param> - </page> - </param> - <_param name="settingsHelp" type="description">All these settings depend on the plotter you use, for more information please consult the manual or homepage for your plotter.</_param> - <effect needs-live-preview="false" needs-document="true"> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Export"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">plotter.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py deleted file mode 100755 index d092b06d4..000000000 --- a/share/extensions/plotter.py +++ /dev/null @@ -1,286 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -''' -Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -# standard library -import re -import string -import sys -# local libraries -import gettext -import hpgl_decoder -import hpgl_encoder -import inkex - - -class Plot(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option('--tab', action='store', type='string', dest='tab') - self.OptionParser.add_option('--portType', action='store', type='string', dest='portType', default='serial', help='Port type') - self.OptionParser.add_option('--parallelPort', action='store', type='string', dest='parallelPort', default='/dev/usb/lp2', help='Parallel port') - self.OptionParser.add_option('--serialPort', action='store', type='string', dest='serialPort', default='COM1', help='Serial port') - self.OptionParser.add_option('--serialBaudRate', action='store', type='string', dest='serialBaudRate', default='9600', help='Serial Baud rate') - self.OptionParser.add_option('--serialByteSize', action='store', type='string', dest='serialByteSize', default='eight', help='Serial byte size') - self.OptionParser.add_option('--serialStopBits', action='store', type='string', dest='serialStopBits', default='one', help='Serial stop bits') - self.OptionParser.add_option('--serialParity', action='store', type='string', dest='serialParity', default='none', help='Serial parity') - self.OptionParser.add_option('--serialFlowControl', action='store', type='string', dest='serialFlowControl', default='0', help='Flow control') - self.OptionParser.add_option('--commandLanguage', action='store', type='string', dest='commandLanguage', default='hpgl', help='Command Language') - self.OptionParser.add_option('--resolutionX', action='store', type='float', dest='resolutionX', default=1016.0, help='Resolution X (dpi)') - self.OptionParser.add_option('--resolutionY', action='store', type='float', dest='resolutionY', default=1016.0, help='Resolution Y (dpi)') - self.OptionParser.add_option('--pen', action='store', type='int', dest='pen', default=1, help='Pen number') - self.OptionParser.add_option('--force', action='store', type='int', dest='force', default=24, help='Pen force (g)') - self.OptionParser.add_option('--speed', action='store', type='int', dest='speed', default=20, help='Pen speed (cm/s)') - self.OptionParser.add_option('--orientation', action='store', type='string', dest='orientation', default='90', help='Rotation (Clockwise)') - self.OptionParser.add_option('--mirrorX', action='store', type='inkbool', dest='mirrorX', default='FALSE', help='Mirror X axis') - self.OptionParser.add_option('--mirrorY', action='store', type='inkbool', dest='mirrorY', default='FALSE', help='Mirror Y axis') - self.OptionParser.add_option('--center', action='store', type='inkbool', dest='center', default='FALSE', help='Center zero point') - self.OptionParser.add_option('--overcut', action='store', type='float', dest='overcut', default=1.0, help='Overcut (mm)') - self.OptionParser.add_option('--toolOffset', action='store', type='float', dest='toolOffset', default=0.25, help='Tool (Knife) offset correction (mm)') - self.OptionParser.add_option('--precut', action='store', type='inkbool', dest='precut', default='TRUE', help='Use precut') - self.OptionParser.add_option('--flat', action='store', type='float', dest='flat', default=1.2, help='Curve flatness') - self.OptionParser.add_option('--autoAlign', action='store', type='inkbool', dest='autoAlign', default='TRUE', help='Auto align') - self.OptionParser.add_option('--debug', action='store', type='inkbool', dest='debug', default='FALSE', help='Show debug information') - self.OptionParser.add_option('--convertObjects', action='store', type='inkbool', dest='convertObjects', default='TRUE', help='Convert objects to paths') - - def effect(self): - # get hpgl data - myHpglEncoder = hpgl_encoder.hpglEncoder(self) - try: - self.hpgl, debugObject = myHpglEncoder.getHpgl() - except Exception as inst: - if inst.args[0] == 'NO_PATHS': - # issue error if no paths found - inkex.errormsg(_("No paths where found. Please convert all objects you want to plot into paths.")) - return 1 - else: - type, value, traceback = sys.exc_info() - raise ValueError, ('', type, value), traceback - # TODO: Get preview to work. This requires some work on the C++ side to be able to determine if it is - # a preview or a final run. (Remember to set <effect needs-live-preview='false'> to true) - ''' - if MAGIC: - # reparse data for preview - self.options.showMovements = True - self.options.docWidth = self.uutounit(self.unittouu(self.document.getroot().get('width')), "px") - self.options.docHeight = self.uutounit(self.unittouu(self.document.getroot().get('height')), "px") - myHpglDecoder = hpgl_decoder.hpglDecoder(self.hpgl, self.options) - doc, warnings = myHpglDecoder.getSvg() - # deliver document to inkscape - self.document = doc - else: - ''' - # convert to other formats - if self.options.commandLanguage == 'HPGL': - self.convertToHpgl() - if self.options.commandLanguage == 'DMPL': - self.convertToDmpl() - if self.options.commandLanguage == 'KNK': - self.convertToKNK() - # output - if self.options.debug: - self.showDebugInfo(debugObject) - elif self.options.portType == 'parallel': - self.sendHpglToParallel() - elif self.options.portType == 'serial': - self.sendHpglToSerial() - - def convertToHpgl(self): - # convert raw HPGL to HPGL - hpglInit = 'IN' - if self.options.force > 0: - hpglInit += ';FS%d' % self.options.force - if self.options.speed > 0: - hpglInit += ';VS%d' % self.options.speed - self.hpgl = hpglInit + self.hpgl + ';PU0,0;SP0;IN; ' - - def convertToDmpl(self): - # convert HPGL to DMPL - # ;: = Initialise plotter - # H = Home position - # A = Absolute pen positioning - # Ln = Line type - # Pn = Pen select - # Vn = velocity - # ECn = Coordinate addressing, 1: 0.001 inch, 5: 0.005 inch, M: 0.1 mm - # D = Pen down - # U = Pen up - # Z = Reset plotter - # n,n, = Coordinate pair - self.hpgl = self.hpgl.replace(';', ',') - self.hpgl = self.hpgl.replace('SP', 'P') - self.hpgl = self.hpgl.replace('PU', 'U') - self.hpgl = self.hpgl.replace('PD', 'D') - dmplInit = ';:HAL0' - if self.options.speed > 0: - dmplInit += 'V%d' % self.options.speed - dmplInit += 'EC1' - self.hpgl = dmplInit + self.hpgl[1:] + ',U0,0,P0,Z ' - - def convertToKNK(self): - # convert HPGL to KNK Plotter Language - hpglInit = 'ZG' - if self.options.force > 0: - hpglInit += ';FS%d' % self.options.force - if self.options.speed > 0: - hpglInit += ';VS%d' % self.options.speed - self.hpgl = hpglInit + self.hpgl + ';PU0,0;SP0;@ ' - - def sendHpglToParallel(self): - port = open(self.options.parallelPort, "w") - port.write(self.hpgl) - port.close() - - def sendHpglToSerial(self): - # gracefully exit script when pySerial is missing - try: - import serial - except ImportError, e: - inkex.errormsg(_("pySerial is not installed. Please follow these steps:") - + "\n\n" + _("1. Download and extract (unzip) this file to your local harddisk:") - + "\n" + " https://pypi.python.org/packages/source/p/pyserial/pyserial-2.7.tar.gz" - + "\n" + _("2. Copy the \"serial\" folder (Can be found inside the just extracted folder)") - + "\n" + _(" into the following Inkscape folder: C:\\[Program files]\\inkscape\\python\\Lib\\") - + "\n" + _("3. Close and restart Inkscape.")) - return - # init serial framework - mySerial = serial.Serial() - # set serial port - mySerial.port = self.options.serialPort - # set baudrate - mySerial.baudrate = self.options.serialBaudRate - # set bytesize - if self.options.serialByteSize == 'five': - mySerial.bytesize = serial.FIVEBITS - if self.options.serialByteSize == 'six': - mySerial.bytesize = serial.SIXBITS - if self.options.serialByteSize == 'seven': - mySerial.bytesize = serial.SEVENBITS - if self.options.serialByteSize == 'eight': - mySerial.bytesize = serial.EIGHTBITS - # set stopbits - if self.options.serialStopBits == 'one': - mySerial.stopbits = serial.STOPBITS_ONE - if self.options.serialStopBits == 'onePointFive': - mySerial.stopbits = serial.STOPBITS_ONE_POINT_FIVE - if self.options.serialStopBits == 'two': - mySerial.stopbits = serial.STOPBITS_TWO - # set parity - if self.options.serialParity == 'none': - mySerial.parity = serial.PARITY_NONE - if self.options.serialParity == 'even': - mySerial.parity = serial.PARITY_EVEN - if self.options.serialParity == 'odd': - mySerial.parity = serial.PARITY_ODD - if self.options.serialParity == 'mark': - mySerial.parity = serial.PARITY_MARK - if self.options.serialParity == 'space': - mySerial.parity = serial.PARITY_SPACE - # set short timeout to avoid locked up interface - mySerial.timeout = 0.1 - # set flow control - if self.options.serialFlowControl == 'xonxoff': - mySerial.xonxoff = True - if self.options.serialFlowControl == 'rtscts' or self.options.serialFlowControl == 'dsrdtrrtscts': - mySerial.rtscts = True - if self.options.serialFlowControl == 'dsrdtrrtscts': - mySerial.dsrdtr = True - # try to establish connection - try: - mySerial.open() - except Exception as inst: - if inst.strerror is not None and 'ould not open port' in inst.strerror: - inkex.errormsg(_("Could not open port. Please check that your plotter is running, connected and the settings are correct.")) - return - else: - type, value, traceback = sys.exc_info() - raise ValueError, ('', type, value), traceback - # send data to plotter - mySerial.write(self.hpgl) - mySerial.read(2) - mySerial.close() - - def showDebugInfo(self, debugObject): - # show debug information - inkex.errormsg("---------------------------------\nDebug information\n---------------------------------\n\nSettings:\n") - inkex.errormsg(' Port type: ' + self.options.portType) - if self.options.portType == 'parallel': - inkex.errormsg(' Parallel Port: ' + self.options.parallelPort) - elif self.options.portType == 'serial': - inkex.errormsg(' Serial Port: ' + self.options.serialPort) - inkex.errormsg(' Serial baud rate: ' + self.options.serialBaudRate) - inkex.errormsg(' Serial byte size: ' + self.options.serialByteSize + ' Bits') - inkex.errormsg(' Serial stop bits: ' + self.options.serialStopBits + ' Bits') - inkex.errormsg(' Serial parity: ' + self.options.serialParity) - inkex.errormsg(' Serial Flow control: ' + self.options.serialFlowControl) - inkex.errormsg(' Command language: ' + self.options.commandLanguage) - else: - inkex.errormsg(' Unknown port type!') - inkex.errormsg(' Resolution X (dpi): ' + str(self.options.resolutionX)) - inkex.errormsg(' Resolution Y (dpi): ' + str(self.options.resolutionY)) - inkex.errormsg(' Pen number: ' + str(self.options.pen)) - inkex.errormsg(' Pen force (g): ' + str(self.options.force)) - inkex.errormsg(' Pen speed (cm/s): ' + str(self.options.speed)) - inkex.errormsg(' Rotation (Clockwise): ' + self.options.orientation) - inkex.errormsg(' Mirror X axis: ' + str(self.options.mirrorX)) - inkex.errormsg(' Mirror Y axis: ' + str(self.options.mirrorY)) - inkex.errormsg(' Center zero point: ' + str(self.options.center)) - inkex.errormsg(' Overcut (mm): ' + str(self.options.overcut)) - inkex.errormsg(' Tool offset (mm): ' + str(self.options.toolOffset)) - inkex.errormsg(' Use precut: ' + str(self.options.precut)) - inkex.errormsg(' Curve flatness: ' + str(self.options.flat)) - inkex.errormsg(' Auto align: ' + str(self.options.autoAlign)) - inkex.errormsg(' Show debug information: ' + str(self.options.debug)) - inkex.errormsg("\nDocument properties:\n") - version = self.document.getroot().xpath('//@inkscape:version', namespaces=inkex.NSS) - if version: - inkex.errormsg(' Inkscape version: ' + version[0]) - fileName = self.document.getroot().xpath('//@sodipodi:docname', namespaces=inkex.NSS) - if fileName: - inkex.errormsg(' Filename: ' + fileName[0]) - inkex.errormsg(' Document unit: ' + self.getDocumentUnit()) - inkex.errormsg(' Width: ' + str(debugObject.debugValues['docWidth']) + ' ' + self.getDocumentUnit()) - inkex.errormsg(' Height: ' + str(debugObject.debugValues['docHeight']) + ' ' + self.getDocumentUnit()) - if debugObject.debugValues['viewBoxWidth'] == "-": - inkex.errormsg(' Viewbox Width: -') - inkex.errormsg(' Viewbox Height: -') - else: - inkex.errormsg(' Viewbox Width: ' + str(self.unittouu(self.addDocumentUnit(debugObject.debugValues['viewBoxWidth']))) + ' ' + self.getDocumentUnit()) - inkex.errormsg(' Viewbox Height: ' + str(self.unittouu(self.addDocumentUnit(debugObject.debugValues['viewBoxHeight']))) + ' ' + self.getDocumentUnit()) - inkex.errormsg("\n" + self.options.commandLanguage + " properties:\n") - inkex.errormsg(' Drawing width: ' + str(self.unittouu(self.addDocumentUnit(str(debugObject.debugValues['drawingWidthUU'])))) + ' ' + self.getDocumentUnit()) - inkex.errormsg(' Drawing height: ' + str(self.unittouu(self.addDocumentUnit(str(debugObject.debugValues['drawingHeightUU'])))) + ' ' + self.getDocumentUnit()) - inkex.errormsg(' Drawing width: ' + str(debugObject.debugValues['drawingWidth']) + ' plotter steps') - inkex.errormsg(' Drawing height: ' + str(debugObject.debugValues['drawingHeight']) + ' plotter steps') - inkex.errormsg(' Offset X: ' + str(debugObject.offsetX) + ' plotter steps') - inkex.errormsg(' Offset Y: ' + str(debugObject.offsetX) + ' plotter steps') - inkex.errormsg(' Overcut: ' + str(debugObject.overcut) + ' plotter steps') - inkex.errormsg(' Tool offset: ' + str(debugObject.toolOffset) + ' plotter steps') - inkex.errormsg(' Flatness: ' + str(debugObject.flat) + ' plotter steps') - inkex.errormsg(' Tool offset flatness: ' + str(debugObject.toolOffsetFlat) + ' plotter steps') - inkex.errormsg("\n" + self.options.commandLanguage + " data:\n") - inkex.errormsg(self.hpgl) - -if __name__ == '__main__': - # start extension - e = Plot() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/plt_input.inx b/share/extensions/plt_input.inx deleted file mode 100644 index 743754469..000000000 --- a/share/extensions/plt_input.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>AutoCAD Plot Input</_name> - <id>org.inkscape.input.plt</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.plt</extension> - <mimetype>image/x-plt</mimetype> - <_filetypename>HP Graphics Language Plot file [AutoCAD] (UC) (*.plt)</_filetypename> - <_filetypetooltip>Open HPGL plotter files</_filetypetooltip> - <output_extension>org.inkscape.output.plt</output_extension> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/plt_output.inx b/share/extensions/plt_output.inx deleted file mode 100644 index 8bbbaa1b8..000000000 --- a/share/extensions/plt_output.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>AutoCAD Plot Output</_name> - <id>org.inkscape.output.plt</id> - <dependency type="executable" location="extensions">plt_output.py</dependency> - <output> - <extension>.plt</extension> - <mimetype>image/x-plt</mimetype> - <_filetypename>HP Graphics Language Plot file [AutoCAD] (UC) (*.plt)</_filetypename> - <_filetypetooltip>Save a file for plotters</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">plt_output.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/plt_output.py b/share/extensions/plt_output.py deleted file mode 100755 index 49ac1f604..000000000 --- a/share/extensions/plt_output.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -plt_output.py -Module for running UniConverter sk1 exporting commands in Inkscape extensions - -Copyright (C) 2009 Nicolas Dufour (jazzynico) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import sys -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 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 deleted file mode 100644 index 0ded2848d..000000000 --- a/share/extensions/polyhedron_3d.inx +++ /dev/null @@ -1,99 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>3D Polyhedron</_name> - <id>math.polyhedron.3d</id> - <dependency type="executable" location="extensions">polyhedron_3d.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="common" _gui-text="Model file"> - <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="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"> - <param name="r1_ax" type="optiongroup" appearance="minimal" _gui-text="Rotate around:"> - <_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 (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 (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 (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 (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 (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 (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="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="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> - </effect> - <script> - <command reldir="extensions" interpreter="python">polyhedron_3d.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/polyhedron_3d.py b/share/extensions/polyhedron_3d.py deleted file mode 100755 index cc2e0722f..000000000 --- a/share/extensions/polyhedron_3d.py +++ /dev/null @@ -1,534 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Beard john.j.beard@gmail.com - -##This extension draws 3d objects from a Wavefront .obj 3D file stored in a local folder -##Many settings for appearance, lighting, rotation, etc are available. - -# ^y -# | -# __--``| |_--``| __-- -# __--`` | __--``| |_--`` -# | z | | |_--``| -# | <----|--------|-----_0-----|---------------- -# | | |_--`` | | -# | __--`` <-``| |_--`` -# |__--`` x |__--``| -# IMAGE PLANE SCENE| -# | - -#Vertices are given as "v" followed by three numbers (x,y,z). -#All files need a vertex list -#v x.xxx y.yyy z.zzz - -#Faces are given by a list of vertices -#(vertex 1 is the first in the list above, 2 the second, etc): -#f 1 2 3 - -#Edges are given by a list of vertices. These will be broken down -#into adjacent pairs automatically. -#l 1 2 3 - -#Faces are rendered according to the painter's algorithm and perhaps -#back-face culling, if selected. The parameter to sort the faces by -#is user-selectable between max, min and average z-value of the vertices - -######LICENCE####### -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import sys -import re -from math import * -# local library -import inkex -import simplestyle -from simpletransform import computePointInNode - -# Initialize gettext for messages outside an inkex derived class -inkex.localize() - -# third party -try: - from numpy import * -except: - inkex.errormsg(_("Failed to import the numpy module. This module is required by this extension. Please install it and try again. On a Debian-like system this can be done with the command 'sudo apt-get install python-numpy'.")) - sys.exit() - -#FILE IO ROUTINES -def get_filename(self_options): - if self_options.obj == 'from_file': - file = self_options.spec_file - else: - file = self_options.obj + '.obj' - - return file - -def objfile(name): - import os.path - if __name__ == '__main__': - filename = sys.argv[0] - else: - filename = __file__ - path = os.path.abspath(os.path.dirname(filename)) - path = os.path.join(path, 'Poly3DObjects', name) - return path - -def get_obj_data(obj, name): - infile = open(objfile(name)) - - #regular expressions - getname = '(.[nN]ame:\\s*)(.*)' - floating = '([\-\+\\d*\.e]*)' #a possibly non-integer number, with +/- and exponent. - getvertex = '(v\\s+)'+floating+'\\s+'+floating+'\\s+'+floating - getedgeline = '(l\\s+)(.*)' - getfaceline = '(f\\s+)(.*)' - getnextint = '(\\d+)([/\\d]*)(.*)'#we need to deal with 123\343\123 or 123\\456 as equivalent to 123 (we are ignoring the other options in the obj file) - - for line in infile: - if line[0]=='#': #we have a comment line - m = re.search(getname, line) #check to see if this line contains a name - if m: - obj.name = m.group(2) #if it does, set the property - elif line[0] == 'v': #we have a vertex (maybe) - m = re.search(getvertex, line) #check to see if this line contains a valid vertex - if m: #we have a valid vertex - obj.vtx.append( [float(m.group(2)), float(m.group(3)), float(m.group(4)) ] ) - elif line[0] == 'l': #we have a line (maybe) - m = re.search(getedgeline, line) #check to see if this line begins 'l ' - if m: #we have a line beginning 'l ' - vtxlist = [] #buffer - while line: - m2 = re.search(getnextint, line) - if m2: - vtxlist.append( int(m2.group(1)) ) - line = m2.group(3)#remainder - else: - line = None - if len(vtxlist) > 1:#we need at least 2 vertices to make an edge - for i in range (len(vtxlist)-1):#we can have more than one vertex per line - get adjacent pairs - obj.edg.append( ( vtxlist[i], vtxlist[i+1] ) )#get the vertex pair between that vertex and the next - elif line[0] == 'f': #we have a face (maybe) - m = re.search(getfaceline, line) - if m: #we have a line beginning 'f ' - vtxlist = []#buffer - while line: - m2 = re.search(getnextint, line) - if m2: - vtxlist.append( int(m2.group(1)) ) - line = m2.group(3)#remainder - else: - line = None - if len(vtxlist) > 2: #we need at least 3 vertices to make an edge - obj.fce.append(vtxlist) - - if obj.name == '':#no name was found, use filename, without extension (.obj) - obj.name = name[0:-4] - -#RENDERING AND SVG OUTPUT FUNCTIONS - -def draw_SVG_dot((cx, cy), st, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'fill': st.fill, 'stroke-opacity':st.s_opac, 'fill-opacity':st.f_opac} - circ_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'r':str(st.r), - 'cx':str(cx), 'cy':str(-cy)} - inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs ) - -def draw_SVG_line((x1, y1),(x2, y2), st, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'stroke-linecap':st.linecap} - line_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1)+','+str(-y1)+' L '+str(x2)+','+str(-y2)} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -def draw_SVG_poly(pts, face, st, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(st.th), 'stroke-linejoin':st.linejoin, \ - 'stroke-opacity':st.s_opac, 'fill': st.fill, 'fill-opacity':st.f_opac} - for i in range(len(face)): - if i == 0:#for first point - d = 'M'#move to - else: - d = d + 'L'#line to - d = d+ str(pts[face[i]-1][0]) + ',' + str(-pts[face[i]-1][1])#add point - d = d + 'z' #close the polygon - - line_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name,'d': d} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs ) - -def draw_edges( edge_list, pts, st, parent ): - for edge in edge_list:#for every edge - pt_1 = pts[ edge[0]-1 ][0:2] #the point at the start - pt_2 = pts[ edge[1]-1 ][0:2] #the point at the end - name = 'Edge'+str(edge[0])+'-'+str(edge[1]) - draw_SVG_line(pt_1,pt_2,st, name, parent)#plot edges - -def draw_faces( faces_data, pts, obj, shading, fill_col,st, parent): - for face in faces_data:#for every polygon that has been sorted - if shading: - st.fill = get_darkened_colour(fill_col, face[1]/pi)#darken proportionally to angle to lighting vector - else: - st.fill = get_darkened_colour(fill_col, 1)#do not darken colour - - face_no = face[3]#the number of the face to draw - draw_SVG_poly(pts, obj.fce[ face_no ], st, 'Face:'+str(face_no), parent) - -def get_darkened_colour( (r,g,b), factor): -#return a hex triplet of colour, reduced in lightness proportionally to a value between 0 and 1 - return '#' + "%02X" % floor( factor*r ) \ - + "%02X" % floor( factor*g ) \ - + "%02X" % floor( factor*b ) #make the colour string - -def make_rotation_log(options): -#makes a string recording the axes and angles of each rotation, so an object can be repeated - return options.r1_ax+str('%.2f'%options.r1_ang)+':'+\ - options.r2_ax+str('%.2f'%options.r2_ang)+':'+\ - options.r3_ax+str('%.2f'%options.r3_ang)+':'+\ - options.r1_ax+str('%.2f'%options.r4_ang)+':'+\ - options.r2_ax+str('%.2f'%options.r5_ang)+':'+\ - options.r3_ax+str('%.2f'%options.r6_ang) - -#MATHEMATICAL FUNCTIONS -def get_angle( vector1, vector2 ): #returns the angle between two vectors - return acos( dot(vector1, vector2) ) - -def length(vector):#return the pythagorean length of a vector - return sqrt(dot(vector,vector)) - -def normalise(vector):#return the unit vector pointing in the same direction as the argument - return vector / length(vector) - -def get_normal( pts, face): #returns the normal vector for the plane passing though the first three elements of face of pts - #n = pt[0]->pt[1] x pt[0]->pt[3] - a = (array(pts[ face[0]-1 ]) - array(pts[ face[1]-1 ])) - b = (array(pts[ face[0]-1 ]) - array(pts[ face[2]-1 ])) - return cross(a,b).flatten() - -def get_unit_normal(pts, face, cw_wound): #returns the unit normal for the plane passing through the first three points of face, taking account of winding - if cw_wound: - winding = -1 #if it is clockwise wound, reverse the vector direction - else: - winding = 1 #else leave alone - - return winding*normalise(get_normal(pts, face)) - -def rotate( matrix, angle, axis ):#choose the correct rotation matrix to use - if axis == 'x': - matrix = rot_x(matrix, angle) - elif axis == 'y': - matrix = rot_y(matrix, angle) - elif axis == 'z': - matrix = rot_z(matrix, angle) - return matrix - -def rot_z( matrix , a):#rotate around the z-axis by a radians - trans_mat = mat(array( [[ cos(a) , -sin(a) , 0 ], - [ sin(a) , cos(a) , 0 ], - [ 0 , 0 , 1 ]])) - return trans_mat*matrix - -def rot_y( matrix , a):#rotate around the y-axis by a radians - trans_mat = mat(array( [[ cos(a) , 0 , sin(a) ], - [ 0 , 1 , 0 ], - [-sin(a) , 0 , cos(a) ]])) - return trans_mat*matrix - -def rot_x( matrix , a):#rotate around the x-axis by a radians - trans_mat = mat(array( [[ 1 , 0 , 0 ], - [ 0 , cos(a) ,-sin(a) ], - [ 0 , sin(a) , cos(a) ]])) - return trans_mat*matrix - -def get_transformed_pts( vtx_list, trans_mat):#translate the points according to the matrix - transformed_pts = [] - for vtx in vtx_list: - transformed_pts.append((trans_mat * mat(vtx).T).T.tolist()[0] )#transform the points at add to the list - return transformed_pts - -def get_max_z(pts, face): #returns the largest z_value of any point in the face - max_z = pts[ face[0]-1 ][2] - for i in range(1, len(face)): - if pts[ face[0]-1 ][2] >= max_z: - max_z = pts[ face[0]-1 ][2] - return max_z - -def get_min_z(pts, face): #returns the smallest z_value of any point in the face - min_z = pts[ face[0]-1 ][2] - for i in range(1, len(face)): - if pts[ face[i]-1 ][2] <= min_z: - min_z = pts[ face[i]-1 ][2] - return min_z - -def get_cent_z(pts, face): #returns the centroid z_value of any point in the face - sum = 0 - for i in range(len(face)): - sum += pts[ face[i]-1 ][2] - return sum/len(face) - -def get_z_sort_param(pts, face, method): #returns the z-sorting parameter specified by 'method' ('max', 'min', 'cent') - z_sort_param = '' - if method == 'max': - z_sort_param = get_max_z(pts, face) - elif method == 'min': - z_sort_param = get_min_z(pts, face) - else: - z_sort_param = get_cent_z(pts, face) - return z_sort_param - -#OBJ DATA MANIPULATION -def remove_duplicates(list):#removes the duplicates from a list - list.sort()#sort the list - - last = list[-1] - for i in range(len(list)-2, -1, -1): - if last==list[i]: - del list[i] - else: - last = list[i] - return list - -def make_edge_list(face_list):#make an edge vertex list from an existing face vertex list - edge_list = [] - for i in range(len(face_list)):#for every face - edges = len(face_list[i]) #number of edges around that face - for j in range(edges):#for every vertex in that face - new_edge = [face_list[i][j], face_list[i][(j+1)%edges] ] - new_edge.sort() #put in ascending order of vertices (to ensure we spot duplicates) - edge_list.append( new_edge )#get the vertex pair between that vertex and the next - - return remove_duplicates(edge_list) - -class Style(object): #container for style information - def __init__(self,options): - self.th = options.th - self.fill= '#ff0000' - self.col = '#000000' - self.r = 2 - self.f_opac = str(options.f_opac/100.0) - self.s_opac = str(options.s_opac/100.0) - self.linecap = 'round' - self.linejoin = 'round' - -class Obj(object): #a 3d object defined by the vertices and the faces (eg a polyhedron) -#edges can be generated from this information - def __init__(self): - self.vtx = [] - self.edg = [] - self.fce = [] - self.name='' - - def set_type(self, options): - if options.type == 'face': - if self.fce != []: - self.type = 'face' - else: - inkex.errormsg(_('No face data found in specified file.')) - inkex.errormsg(_('Try selecting "Edge Specified" in the Model File tab.\n')) - self.type = 'error' - else: - if self.edg != []: - self.type = 'edge' - else: - inkex.errormsg(_('No edge data found in specified file.')) - inkex.errormsg(_('Try selecting "Face Specified" in the Model File tab.\n')) - self.type = 'error' - -class Poly_3D(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", default="object") - -#MODEL FILE SETTINGS - self.OptionParser.add_option("--obj", - action="store", type="string", - dest="obj", default='cube') - self.OptionParser.add_option("--spec_file", - action="store", type="string", - dest="spec_file", default='great_rhombicuboct.obj') - self.OptionParser.add_option("--cw_wound", - action="store", type="inkbool", - dest="cw_wound", default='true') - self.OptionParser.add_option("--type", - action="store", type="string", - dest="type", default='face') -#VEIW SETTINGS - self.OptionParser.add_option("--r1_ax", - action="store", type="string", - dest="r1_ax", default="X-Axis") - self.OptionParser.add_option("--r2_ax", - action="store", type="string", - dest="r2_ax", default="X-Axis") - self.OptionParser.add_option("--r3_ax", - action="store", type="string", - dest="r3_ax", default="X-Axis") - self.OptionParser.add_option("--r4_ax", - action="store", type="string", - dest="r4_ax", default="X-Axis") - self.OptionParser.add_option("--r5_ax", - action="store", type="string", - dest="r5_ax", default="X-Axis") - self.OptionParser.add_option("--r6_ax", - action="store", type="string", - dest="r6_ax", default="X-Axis") - self.OptionParser.add_option("--r1_ang", - action="store", type="float", - dest="r1_ang", default=0) - self.OptionParser.add_option("--r2_ang", - action="store", type="float", - dest="r2_ang", default=0) - self.OptionParser.add_option("--r3_ang", - action="store", type="float", - dest="r3_ang", default=0) - self.OptionParser.add_option("--r4_ang", - action="store", type="float", - dest="r4_ang", default=0) - self.OptionParser.add_option("--r5_ang", - action="store", type="float", - dest="r5_ang", default=0) - self.OptionParser.add_option("--r6_ang", - action="store", type="float", - dest="r6_ang", default=0) - self.OptionParser.add_option("--scl", - action="store", type="float", - dest="scl", default=100.0) -#STYLE SETTINGS - self.OptionParser.add_option("--show", - action="store", type="string", - dest="show", default='faces') - self.OptionParser.add_option("--shade", - action="store", type="inkbool", - dest="shade", default='true') - self.OptionParser.add_option("--f_r", - action="store", type="int", - dest="f_r", default=255) - self.OptionParser.add_option("--f_g", - action="store", type="int", - dest="f_g", default=0) - self.OptionParser.add_option("--f_b", - action="store", type="int", - dest="f_b", default=0) - self.OptionParser.add_option("--f_opac", - action="store", type="int", - dest="f_opac", default=100) - self.OptionParser.add_option("--s_opac", - action="store", type="int", - dest="s_opac", default=100) - self.OptionParser.add_option("--th", - action="store", type="float", - dest="th", default=2) - self.OptionParser.add_option("--lv_x", - action="store", type="float", - dest="lv_x", default=1) - self.OptionParser.add_option("--lv_y", - action="store", type="float", - dest="lv_y", default=1) - self.OptionParser.add_option("--lv_z", - action="store", type="float", - dest="lv_z", default=-2) - self.OptionParser.add_option("--back", - action="store", type="inkbool", - dest="back", default='false') - self.OptionParser.add_option("--norm", - action="store", type="inkbool", - dest="norm", default='true') - self.OptionParser.add_option("--z_sort", - action="store", type="string", - dest="z_sort", default='min') - - - def effect(self): - so = self.options#shorthand - - #INITIALISE AND LOAD DATA - - obj = Obj() #create the object - file = get_filename(so)#get the file to load data from - get_obj_data(obj, file)#load data from the obj file - obj.set_type(so)#set the type (face or edge) as per the settings - - scale = self.unittouu('1px') # convert to document units - st = Style(so) #initialise style - fill_col = (so.f_r, so.f_g, so.f_b) #colour tuple for the face fill - lighting = normalise( (so.lv_x,-so.lv_y,so.lv_z) ) #unit light vector - - #INKSCAPE GROUP TO CONTAIN THE POLYHEDRON - - #Put in in the centre of the current view - view_center = computePointInNode(list(self.view_center), self.current_layer) - poly_transform = 'translate(' + str( view_center[0]) + ',' + str( view_center[1]) + ')' - if scale != 1: - poly_transform += ' scale(' + str(scale) + ')' - #we will put all the rotations in the object name, so it can be repeated in - poly_name = obj.name+':'+make_rotation_log(so) - poly_attribs = {inkex.addNS('label','inkscape'):poly_name, - 'transform':poly_transform } - poly = inkex.etree.SubElement(self.current_layer, 'g', poly_attribs)#the group to put everything in - - #TRANSFORMATION OF THE OBJECT (ROTATION, SCALE, ETC) - - trans_mat = mat(identity(3, float)) #init. trans matrix as identity matrix - for i in range(1, 7):#for each rotation - axis = eval('so.r'+str(i)+'_ax') - angle = eval('so.r'+str(i)+'_ang') *pi/180 - trans_mat = rotate(trans_mat, angle, axis) - trans_mat = trans_mat*so.scl #scale by linear factor (do this only after the transforms to reduce round-off) - - transformed_pts = get_transformed_pts(obj.vtx, trans_mat) #the points as projected in the z-axis onto the viewplane - - #RENDERING OF THE OBJECT - - if so.show == 'vtx': - for i in range(len(transformed_pts)): - draw_SVG_dot([transformed_pts[i][0],transformed_pts[i][1]], st, 'Point'+str(i), poly)#plot points using transformed_pts x and y coords - - elif so.show == 'edg': - if obj.type == 'face':#we must generate the edge list from the faces - edge_list = make_edge_list(obj.fce) - else:#we already have an edge list - edge_list = obj.edg - - draw_edges( edge_list, transformed_pts, st, poly) - - elif so.show == 'fce': - if obj.type == 'face':#we have a face list - - z_list = [] - - for i in range(len(obj.fce)): - face = obj.fce[i] #the face we are dealing with - norm = get_unit_normal(transformed_pts, face, so.cw_wound) #get the normal vector to the face - angle = get_angle( norm, lighting )#get the angle between the normal and the lighting vector - z_sort_param = get_z_sort_param(transformed_pts, face, so.z_sort) - - if so.back or norm[2] > 0: # include all polygons or just the front-facing ones as needed - z_list.append((z_sort_param, angle, norm, i))#record the maximum z-value of the face and angle to light, along with the face ID and normal - - z_list.sort(lambda x, y: cmp(x[0],y[0])) #sort by ascending sort parameter of the face - draw_faces( z_list, transformed_pts, obj, so.shade, fill_col, st, poly) - - else:#we cannot generate a list of faces from the edges without a lot of computation - inkex.errormsg(_('Face Data Not Found. Ensure file contains face data, and check the file is imported as "Face-Specified" under the "Model File" tab.\n')) - else: - inkex.errormsg(_('Internal Error. No view type selected\n')) - -if __name__ == '__main__': - e = Poly_3D() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/prepare_file_save_as.inx b/share/extensions/prepare_file_save_as.inx deleted file mode 100644 index 1556713aa..000000000 --- a/share/extensions/prepare_file_save_as.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Pre-Process File Save As...</_name> - <id>com.vaxxine.file.saveas.preprocess</id> - <dependency type="executable" location="extensions">prepare_file_save_as.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Export"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">prepare_file_save_as.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/prepare_file_save_as.py b/share/extensions/prepare_file_save_as.py deleted file mode 100755 index d0c660fcf..000000000 --- a/share/extensions/prepare_file_save_as.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -''' -file: prepare_file_save_as.py - -This extension will pre-process a vector image by applying the operations: -'EditSelectAllInAllLayers' and 'ObjectToPath' -before calling the dialog File->Save As.... - -Copyright (C) 2014 Ryan Lerch (multiple difference) - 2016 Maren Hachmann <marenhachmannATyahoo.com> (refactoring, extend to multibool) - 2017 Alvin Penner <penner@vaxxine.com> (apply to 'File Save As...') - -This code is based on 'inkscape-extension-multiple-difference' by Ryan Lerch -see : https://github.com/ryanlerch/inkscape-extension-multiple-difference -also: https://github.com/Moini/inkscape-extensions-multi-bool -It will call up a new instance of Inkscape and process the image there, -so that the original file is left intact. - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -from subprocess import Popen, PIPE -from shutil import copy2 -# local library -import inkex - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - file = self.args[-1] - tempfile = inkex.os.path.splitext(file)[0] + "-prepare.svg" - # tempfile is needed here only because we want to force the extension to be .svg - # so that we can open and close it silently - copy2(file, tempfile) - p = Popen('inkscape --verb=EditSelectAllInAllLayers --verb=EditUnlinkClone --verb=ObjectToPath --verb=FileSaveACopy --verb=FileSave --verb=FileQuit '+tempfile, shell=True, stdout=PIPE, stderr=PIPE) - err = p.stderr - f = p.communicate()[0] - err.close() - -if __name__ == '__main__': - e = MyEffect() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/prepare_print_win32_vector.inx b/share/extensions/prepare_print_win32_vector.inx deleted file mode 100644 index b8d87cec8..000000000 --- a/share/extensions/prepare_print_win32_vector.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Pre-Process Win32 Vector Print</_name> - <id>com.vaxxine.print.win32.preprocess</id> - <dependency type="executable" location="extensions">prepare_print_win32_vector.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Export"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">prepare_print_win32_vector.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/prepare_print_win32_vector.py b/share/extensions/prepare_print_win32_vector.py deleted file mode 100755 index e13670931..000000000 --- a/share/extensions/prepare_print_win32_vector.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -''' -file: prepare_print_win32_vector.py - -This extension will pre-process a vector image by applying the operations: -'EditSelectAllInAllLayers' and 'ObjectToPath' -before applying the extension: 'Win32 Vector Print'. - -Generate vector graphics printout, specifically for Windows GDI32. - -Copyright (C) 2014 Ryan Lerch (multiple difference) - 2016 Maren Hachmann <marenhachmannATyahoo.com> (refactoring, extend to multibool) - 2017 Alvin Penner <penner@vaxxine.com> (apply to 'Win32 Vector Print') - -This code is based on 'inkscape-extension-multiple-difference' by Ryan Lerch -see : https://github.com/ryanlerch/inkscape-extension-multiple-difference -also: https://github.com/Moini/inkscape-extensions-multi-bool -It will call up a new instance of Inkscape and process the image there, -so that the original file is left intact. - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -from subprocess import Popen, PIPE -from shutil import copy2 -# local library -import inkex - -inkex.localize() # Initialize gettext -if not inkex.sys.platform.startswith('win'): - exit(_("sorry, this will run only on Windows, exiting...")) - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - file = self.args[-1] - tempfile = inkex.os.path.splitext(file)[0] + "-prepare.svg" - # tempfile is needed here only because we want to force the extension to be .svg - # so that we can open and close it silently - copy2(file, tempfile) - p = Popen('inkscape --verb=EditSelectAllInAllLayers --verb=EditUnlinkClone --verb=ObjectToPath --verb=com.vaxxine.print.win32 --verb=FileSave --verb=FileQuit '+tempfile, shell=True, stdout=PIPE, stderr=PIPE) - err = p.stderr - f = p.communicate()[0] - err.close() - -if __name__ == '__main__': - e = MyEffect() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/previous_glyph_layer.inx b/share/extensions/previous_glyph_layer.inx deleted file mode 100644 index 928016adc..000000000 --- a/share/extensions/previous_glyph_layer.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>View Previous Glyph</_name> - <id>org.inkscape.typography.previousglyphlayer</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">previous_glyph_layer.py</command> - </script> - <options silent="true"></options> -</inkscape-extension> diff --git a/share/extensions/previous_glyph_layer.py b/share/extensions/previous_glyph_layer.py deleted file mode 100755 index 5e9de1fb8..000000000 --- a/share/extensions/previous_glyph_layer.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex - -class PreviousLayer(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - - # Get access to main SVG document element - self.svg = self.document.getroot() - - groups = self.svg.findall(inkex.addNS('g', 'svg')) - - count=0 - glyphs=[] - for g in groups: - if "GlyphLayer-" in g.get(inkex.addNS('label', 'inkscape')): - glyphs.append(g) - if g.get("style")=="display:inline": - count+=1 - current = len(glyphs)-1 - - if count!=1 or len(glyphs)<2: - return - #TODO: inform the user? - - glyphs[current].set("style", "display:none") - glyphs[current-1].set("style", "display:inline") - return - -#TODO: loop - -if __name__ == '__main__': - e = PreviousLayer() - e.affect() - diff --git a/share/extensions/print_win32_vector.inx b/share/extensions/print_win32_vector.inx deleted file mode 100644 index ab66a4b77..000000000 --- a/share/extensions/print_win32_vector.inx +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Win32 Vector Print</_name> - <id>com.vaxxine.print.win32</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">print_win32_vector.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Export"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">print_win32_vector.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/print_win32_vector.py b/share/extensions/print_win32_vector.py deleted file mode 100755 index 99365fc5e..000000000 --- a/share/extensions/print_win32_vector.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python -''' -print_win32_vector.py -This extension will generate vector graphics printout, specifically for Windows GDI32. - -Copyright (C) 2012 Alvin Penner, penner@vaxxine.com - -This is a modified version of the file dxf_outlines.py by Aaron Spike, aaron@ekips.org -It will write only to the default printer. -The printing preferences dialog will be called. -In order to ensure a pure vector output, use a linewidth < 1 printer pixel - -- see http://www.lessanvaezi.com/changing-printer-settings-using-the-windows-api/ -- get GdiPrintSample.zip at http://archive.msdn.microsoft.com/WindowsPrintSample - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -from ctypes import * -# local library -import inkex -import simplestyle -import simpletransform -import cubicsuperpath - -inkex.localize() # Initialize gettext -if not inkex.sys.platform.startswith('win'): - exit(_("sorry, this will run only on Windows, exiting...")) - -myspool = WinDLL("winspool.drv") -mygdi = WinDLL("gdi32.dll") -LOGBRUSH = c_long*3 -DM_IN_PROMPT = 4 # call printer property sheet -DM_OUT_BUFFER = 2 # write to DEVMODE structure - -class MyEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.visibleLayers = True # print only visible layers - - def process_shape(self, node, mat): - rgb = (0,0,0) # stroke color - fillcolor = None # fill color - stroke = 1 # pen width in printer pixels - # Very NB : If the pen width is greater than 1 then the output will Not be a vector output ! - style = node.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('stroke'): - if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url': - rgb = simplestyle.parseColor(style['stroke']) - if style.has_key('stroke-width'): - stroke = self.unittouu(style['stroke-width'])/self.unittouu('1px') - stroke = int(stroke*self.scale) - if style.has_key('fill'): - if style['fill'] and style['fill'] != 'none' and style['fill'][0:3] != 'url': - fill = simplestyle.parseColor(style['fill']) - fillcolor = fill[0] + 256*fill[1] + 256*256*fill[2] - color = rgb[0] + 256*rgb[1] + 256*256*rgb[2] - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - if not d: - return - p = cubicsuperpath.parsePath(d) - elif node.tag == inkex.addNS('rect','svg'): - x = float(node.get('x')) - y = float(node.get('y')) - width = float(node.get('width')) - height = float(node.get('height')) - p = [[[x, y],[x, y],[x, y]]] - p.append([[x + width, y],[x + width, y],[x + width, y]]) - p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]]) - p.append([[x, y + height],[x, y + height],[x, y + height]]) - p.append([[x, y],[x, y],[x, y]]) - p = [p] - else: - return - trans = node.get('transform') - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - simpletransform.applyTransformToPath(mat, p) - hPen = mygdi.CreatePen(0, stroke, color) - mygdi.SelectObject(self.hDC, hPen) - self.emit_path(p) - if fillcolor is not None: - brush = LOGBRUSH(0, fillcolor, 0) - hBrush = mygdi.CreateBrushIndirect(addressof(brush)) - mygdi.SelectObject(self.hDC, hBrush) - mygdi.BeginPath(self.hDC) - self.emit_path(p) - mygdi.EndPath(self.hDC) - mygdi.FillPath(self.hDC) - return - - def emit_path(self, p): - for sub in p: - mygdi.MoveToEx(self.hDC, int(sub[0][1][0]), int(sub[0][1][1]), None) - POINTS = c_long*(6*(len(sub)-1)) - points = POINTS() - for i in range(len(sub)-1): - points[6*i] = int(sub[i][2][0]) - points[6*i + 1] = int(sub[i][2][1]) - points[6*i + 2] = int(sub[i + 1][0][0]) - points[6*i + 3] = int(sub[i + 1][0][1]) - points[6*i + 4] = int(sub[i + 1][1][0]) - points[6*i + 5] = int(sub[i + 1][1][1]) - mygdi.PolyBezierTo(self.hDC, addressof(points), 3*(len(sub)-1)) - return - - def process_clone(self, node): - trans = node.get('transform') - x = node.get('x') - y = node.get('y') - mat = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - if trans: - mat = simpletransform.composeTransform(mat, simpletransform.parseTransform(trans)) - if x: - mat = simpletransform.composeTransform(mat, [[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]]) - if y: - mat = simpletransform.composeTransform(mat, [[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]]) - # push transform - if trans or x or y: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], mat)) - # get referenced node - refid = node.get(inkex.addNS('href','xlink')) - refnode = self.getElementById(refid[1:]) - if refnode is not None: - if refnode.tag == inkex.addNS('g','svg'): - self.process_group(refnode) - elif refnode.tag == inkex.addNS('use', 'svg'): - self.process_clone(refnode) - else: - self.process_shape(refnode, self.groupmat[-1]) - # pop transform - if trans or x or y: - self.groupmat.pop() - - def process_group(self, group): - if group.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': - style = group.get('style') - if style: - style = simplestyle.parseStyle(style) - if style.has_key('display'): - if style['display'] == 'none' and self.visibleLayers: - return - trans = group.get('transform') - if trans: - self.groupmat.append(simpletransform.composeTransform(self.groupmat[-1], simpletransform.parseTransform(trans))) - for node in group: - if node.tag == inkex.addNS('g','svg'): - self.process_group(node) - elif node.tag == inkex.addNS('use', 'svg'): - self.process_clone(node) - else: - self.process_shape(node, self.groupmat[-1]) - if trans: - self.groupmat.pop() - - def effect(self): - pcchBuffer = c_long() - myspool.GetDefaultPrinterA(None, byref(pcchBuffer)) # get length of printer name - pname = create_string_buffer(pcchBuffer.value) - myspool.GetDefaultPrinterA(pname, byref(pcchBuffer)) # get printer name - hPrinter = c_long() - if myspool.OpenPrinterA(pname.value, byref(hPrinter), None) == 0: - exit(_("Failed to open default printer")) - - # get printer properties dialog - - pcchBuffer = myspool.DocumentPropertiesA(0, hPrinter, pname, None, None, 0) - pDevMode = create_string_buffer(pcchBuffer + 100) # allocate extra just in case - pcchBuffer = myspool.DocumentPropertiesA(0, hPrinter, pname, byref(pDevMode), None, DM_IN_PROMPT + DM_OUT_BUFFER) - myspool.ClosePrinter(hPrinter) - if pcchBuffer != 1: # user clicked Cancel - exit() - - # initiallize print document - - docname = self.document.getroot().xpath('@sodipodi:docname', namespaces=inkex.NSS) - if not docname: - docname = ['New document 1'] - lpszDocName = create_string_buffer('Inkscape ' + docname[0].split('\\')[-1]) - DOCINFO = c_long*5 - docInfo = DOCINFO(20, addressof(lpszDocName), 0, 0, 0) - self.hDC = mygdi.CreateDCA(None, pname, None, byref(pDevMode)) - if mygdi.StartDocA(self.hDC, byref(docInfo)) < 0: - exit() # user clicked Cancel - - self.scale = (ord(pDevMode[58]) + 256.0*ord(pDevMode[59]))/96 # use PrintQuality from DEVMODE - self.scale /= self.unittouu('1px') - h = self.unittouu(self.document.getroot().xpath('@height', namespaces=inkex.NSS)[0]) - doc = self.document.getroot() - # process viewBox height attribute to correct page scaling - viewBox = doc.get('viewBox') - if viewBox: - viewBox2 = viewBox.split(',') - if len(viewBox2) < 4: - viewBox2 = viewBox.split(' ') - self.scale *= h / self.unittouu(self.addDocumentUnit(viewBox2[3])) - self.groupmat = [[[self.scale, 0.0, 0.0], [0.0, self.scale, 0.0]]] - self.process_group(doc) - mygdi.EndDoc(self.hDC) - -if __name__ == '__main__': - e = MyEffect() - e.affect() - -# 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 deleted file mode 100644 index 552741415..000000000 --- a/share/extensions/printing_marks.inx +++ /dev/null @@ -1,51 +0,0 @@ -<?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> - - <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" precision="3" _gui-text="Offset:">5</param> - <_param name="bleed_settings" type="description" appearance="header">Bleed Margin</_param> - <param name="bleed_top" type="float" indent="1" min="0.0" max="9999.0" precision="3" _gui-text="Top:">5</param> - <param name="bleed_bottom" type="float" indent="1" min="0.0" max="9999.0" precision="3" _gui-text="Bottom:">5</param> - <param name="bleed_left" type="float" indent="1" min="0.0" max="9999.0" precision="3" _gui-text="Left:">5</param> - <param name="bleed_right" type="float" indent="1" min="0.0" max="9999.0" precision="3" _gui-text="Right:">5</param> - </page> - </param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Layout"/> - </submenu> - </effects-menu> - </effect> - - <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 deleted file mode 100755 index 4f0158e8c..000000000 --- a/share/extensions/printing_marks.py +++ /dev/null @@ -1,488 +0,0 @@ -#!/usr/bin/env python -''' -This extension allows you to draw crop, registration and other -printing marks in Inkscape. - -Authors: - Nicolas Dufour - Association Inkscape-fr - Aurelio A. Heckert <aurium(a)gmail.com> - -Copyright (C) 2008 Authors - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -from subprocess import Popen, PIPE, STDOUT -import math - -import inkex -import simplestyle - -class Printing_Marks (inkex.Effect): - - # Default parameters - stroke_width = 0.25 - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--where", - action="store", type="string", - dest="where_to_crop", default=True, - help="Apply crop marks to...") - self.OptionParser.add_option("--crop_marks", - action="store", type="inkbool", - dest="crop_marks", default=True, - help="Draw crop Marks?") - self.OptionParser.add_option("--bleed_marks", - action="store", type="inkbool", - dest="bleed_marks", default=False, - help="Draw Bleed Marks?") - self.OptionParser.add_option("--registration_marks", - action="store", type="inkbool", - dest="reg_marks", default=False, - help="Draw Registration Marks?") - self.OptionParser.add_option("--star_target", - action="store", type="inkbool", - dest="star_target", default=False, - help="Draw Star Target?") - self.OptionParser.add_option("--colour_bars", - action="store", type="inkbool", - dest="colour_bars", default=False, - help="Draw Colour Bars?") - self.OptionParser.add_option("--page_info", - action="store", type="inkbool", - dest="page_info", default=False, - help="Draw Page Information?") - self.OptionParser.add_option("--unit", - action="store", type="string", - dest="unit", default="px", - help="Draw measurement") - self.OptionParser.add_option("--crop_offset", - action="store", type="float", - dest="crop_offset", default=0, - help="Offset") - self.OptionParser.add_option("--bleed_top", - action="store", type="float", - dest="bleed_top", default=0, - help="Bleed Top Size") - self.OptionParser.add_option("--bleed_bottom", - action="store", type="float", - dest="bleed_bottom", default=0, - help="Bleed Bottom Size") - self.OptionParser.add_option("--bleed_left", - action="store", type="float", - dest="bleed_left", default=0, - help="Bleed Left Size") - self.OptionParser.add_option("--bleed_right", - 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), - 'fill': 'none'} - line_attribs = {'style': simplestyle.formatStyle(style), - 'id': name, - 'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, 'path', line_attribs) - - def draw_bleed_line(self, x1, y1, x2, y2, name, parent): - style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width), - 'fill': 'none', - 'stroke-miterlimit': '4', 'stroke-dasharray': '4, 2, 1, 2', - 'stroke-dashoffset': '0' } - line_attribs = {'style': simplestyle.formatStyle(style), - 'id': name, - 'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)} - inkex.etree.SubElement(parent, 'path', line_attribs) - - def draw_reg_circles(self, cx, cy, r, name, colours, parent): - for i in range(len(colours)): - style = {'stroke':colours[i], 'stroke-width':str(r / len(colours)), - 'fill':'none'} - circle_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'cx':str(cx), 'cy':str(cy), - 'r':str((r / len(colours)) * (i + 0.5))} - inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), - circle_attribs) - - def draw_reg_marks(self, cx, cy, rotate, name, parent): - colours = ['#000000','#00ffff','#ff00ff','#ffff00','#000000'] - g = inkex.etree.SubElement(parent, 'g', { 'id': name }) - for i in range(len(colours)): - style = {'fill':colours[i], 'fill-opacity':'1', 'stroke':'none'} - r = (self.mark_size/2) - step = r - stroke = r / len(colours) - regoffset = stroke * i - regmark_attribs = {'style': simplestyle.formatStyle(style), - 'd': 'm' +\ - ' '+str(-regoffset)+','+str(r) +\ - ' '+str(-stroke) +',0' +\ - ' '+str(step) +','+str(-r) +\ - ' '+str(-step) +','+str(-r) +\ - ' '+str(stroke) +',0' +\ - ' '+str(step) +','+str(r) +\ - ' '+str(-step) +','+str(r) +\ - ' z', - 'transform': 'translate('+str(cx)+','+str(cy)+ \ - ') rotate('+str(rotate)+')'} - inkex.etree.SubElement(g, 'path', regmark_attribs) - - def draw_star_target(self, cx, cy, name, parent): - r = (self.mark_size/2) - style = {'fill':'#000 device-cmyk(1,1,1,1)', 'fill-opacity':'1', 'stroke':'none'} - d = ' M 0,0' - i = 0 - while i < ( 2 * math.pi ): - i += math.pi / 16 - d += ' L 0,0 ' +\ - ' L '+ str(math.sin(i)*r) +','+ str(math.cos(i)*r) +\ - ' L '+ str(math.sin(i+0.09)*r) +','+ str(math.cos(i+0.09)*r) - regmark_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'transform':'translate('+str(cx)+','+str(cy)+')', - 'd':d} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), - regmark_attribs) - - def draw_coluor_bars(self, cx, cy, rotate, name, parent): - g = inkex.etree.SubElement(parent, 'g', { - 'id':name, - 'transform':'translate('+str(cx)+','+str(cy)+\ - ') rotate('+str(rotate)+')' }) - l = min( self.mark_size / 3, max(self.area_w,self.area_h) / 45 ) - for bar in [{'c':'*', 'stroke':'#000', 'x':0, 'y':-(l+1)}, - {'c':'r', 'stroke':'#0FF', 'x':0, 'y':0}, - {'c':'g', 'stroke':'#F0F', 'x':(l*11)+1, 'y':-(l+1)}, - {'c':'b', 'stroke':'#FF0', 'x':(l*11)+1, 'y':0} - ]: - i = 0 - while i <= 1: - cr = '255' - cg = '255' - cb = '255' - if bar['c'] == 'r' or bar['c'] == '*' : cr = str(255*i) - if bar['c'] == 'g' or bar['c'] == '*' : cg = str(255*i) - if bar['c'] == 'b' or bar['c'] == '*' : cb = str(255*i) - r_att = {'fill':'rgb('+cr+','+cg+','+cb+')', - 'stroke':bar['stroke'], - 'stroke-width':'0.5', - 'x':str((l*i*10)+bar['x']), 'y':str(bar['y']), - 'width':str(l), 'height':str(l)} - r = inkex.etree.SubElement(g, 'rect', r_att) - i += 0.1 - - def get_selection_area(self): - scale = self.unittouu('1px') # convert to document units - sel_area = {} - min_x, min_y, max_x, max_y = False, False, False, False - for id in self.options.ids: - sel_area[id] = {} - for att in [ "x", "y", "width", "height" ]: - args = [ "inkscape", "-I", id, "--query-"+att, self.svg_file ] - sel_area[id][att] = scale* \ - float(Popen(args, stdout=PIPE, stderr=PIPE).communicate()[0]) - current_min_x = sel_area[id]["x"] - current_min_y = sel_area[id]["y"] - current_max_x = sel_area[id]["x"] + \ - sel_area[id]["width"] - current_max_y = sel_area[id]["y"] + \ - sel_area[id]["height"] - if not min_x: min_x = current_min_x - if not min_y: min_y = current_min_y - if not max_x: max_x = current_max_x - if not max_y: max_y = current_max_y - if current_min_x < min_x: min_x = current_min_x - if current_min_y < min_y: min_y = current_min_y - if current_max_x > max_x: max_x = current_max_x - if current_max_y > max_y: max_y = current_max_y - #inkex.errormsg( '>> '+ id + - # ' min_x:'+ str(min_x) + - # ' min_y:'+ str(min_y) + - # ' max_x:'+ str(max_x) + - # ' max_y:'+ str(max_y) ) - self.area_x1 = min_x - self.area_y1 = min_y - self.area_x2 = max_x - self.area_y2 = max_y - self.area_w = max_x - min_x - self.area_h = max_y - min_y - - def effect(self): - self.mark_size = self.unittouu('1cm') - self.min_mark_margin = self.unittouu('3mm') - - if self.options.where_to_crop == 'selection' : - self.get_selection_area() - #inkex.errormsg('Sory, the crop to selection is a TODO feature') - #exit(1) - else : - svg = self.document.getroot() - self.area_w = self.unittouu(svg.get('width')) - self.area_h = self.unittouu(svg.attrib['height']) - self.area_x1 = 0 - self.area_y1 = 0 - self.area_x2 = self.area_w - self.area_y2 = self.area_h - - # Get SVG document dimensions - # self.width must be replaced by self.area_x2. same to others. - svg = self.document.getroot() - #self.width = width = self.unittouu(svg.get('width')) - #self.height = height = self.unittouu(svg.attrib['height']) - - # Convert parameters to user unit - offset = self.unittouu(str(self.options.crop_offset) + \ - self.options.unit) - bt = self.unittouu(str(self.options.bleed_top) + self.options.unit) - bb = self.unittouu(str(self.options.bleed_bottom) + self.options.unit) - bl = self.unittouu(str(self.options.bleed_left) + self.options.unit) - br = self.unittouu(str(self.options.bleed_right) + self.options.unit) - # Bleed margin - if bt < offset : bmt = 0 - else : bmt = bt - offset - if bb < offset : bmb = 0 - else : bmb = bb - offset - if bl < offset : bml = 0 - else : bml = bl - offset - if br < offset : bmr = 0 - else : bmr = br - offset - - # Define the new document limits - offset_left = self.area_x1 - offset - offset_right = self.area_x2 + offset - offset_top = self.area_y1 - offset - offset_bottom = self.area_y2 + offset - - # Get middle positions - middle_vertical = self.area_y1 + ( self.area_h / 2 ) - middle_horizontal = self.area_x1 + ( self.area_w / 2 ) - - # Test if printing-marks layer existis - layer = self.document.xpath( - '//*[@id="printing-marks" and @inkscape:groupmode="layer"]', - namespaces=inkex.NSS) - if layer: svg.remove(layer[0]) # remove if it existis - # Create a new layer - layer = inkex.etree.SubElement(svg, 'g') - layer.set('id', 'printing-marks') - layer.set(inkex.addNS('label', 'inkscape'), 'Printing Marks') - layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') - layer.set(inkex.addNS('insensitive', 'sodipodi'), 'true') - - # Crop Mark - if self.options.crop_marks == True: - # Create a group for Crop Mark - g_attribs = {inkex.addNS('label','inkscape'):'CropMarks', - 'id':'CropMarks'} - g_crops = inkex.etree.SubElement(layer, 'g', g_attribs) - - # Top left Mark - self.draw_crop_line(self.area_x1, offset_top, - self.area_x1, offset_top - self.mark_size, - 'cropTL1', g_crops) - self.draw_crop_line(offset_left, self.area_y1, - offset_left - self.mark_size, self.area_y1, - 'cropTL2', g_crops) - - # Top right Mark - self.draw_crop_line(self.area_x2, offset_top, - self.area_x2, offset_top - self.mark_size, - 'cropTR1', g_crops) - self.draw_crop_line(offset_right, self.area_y1, - offset_right + self.mark_size, self.area_y1, - 'cropTR2', g_crops) - - # Bottom left Mark - self.draw_crop_line(self.area_x1, offset_bottom, - self.area_x1, offset_bottom + self.mark_size, - 'cropBL1', g_crops) - self.draw_crop_line(offset_left, self.area_y2, - offset_left - self.mark_size, self.area_y2, - 'cropBL2', g_crops) - - # Bottom right Mark - self.draw_crop_line(self.area_x2, offset_bottom, - self.area_x2, offset_bottom + self.mark_size, - 'cropBR1', g_crops) - self.draw_crop_line(offset_right, self.area_y2, - offset_right + self.mark_size, self.area_y2, - 'cropBR2', g_crops) - - # Bleed Mark - if self.options.bleed_marks == True: - # Create a group for Bleed Mark - g_attribs = {inkex.addNS('label','inkscape'):'BleedMarks', - 'id':'BleedMarks'} - g_bleed = inkex.etree.SubElement(layer, 'g', g_attribs) - - # Top left Mark - self.draw_bleed_line(self.area_x1 - bl, offset_top - bmt, - self.area_x1 - bl, offset_top - bmt - self.mark_size, - 'bleedTL1', g_bleed) - self.draw_bleed_line(offset_left - bml, self.area_y1 - bt, - offset_left - bml - self.mark_size, self.area_y1 - bt, - 'bleedTL2', g_bleed) - - # Top right Mark - self.draw_bleed_line(self.area_x2 + br, offset_top - bmt, - self.area_x2 + br, offset_top - bmt - self.mark_size, - 'bleedTR1', g_bleed) - self.draw_bleed_line(offset_right + bmr, self.area_y1 - bt, - offset_right + bmr + self.mark_size, self.area_y1 - bt, - 'bleedTR2', g_bleed) - - # Bottom left Mark - self.draw_bleed_line(self.area_x1 - bl, offset_bottom + bmb, - self.area_x1 - bl, offset_bottom + bmb + self.mark_size, - 'bleedBL1', g_bleed) - self.draw_bleed_line(offset_left - bml, self.area_y2 + bb, - offset_left - bml - self.mark_size, self.area_y2 + bb, - 'bleedBL2', g_bleed) - - # Bottom right Mark - self.draw_bleed_line(self.area_x2 + br, offset_bottom + bmb, - self.area_x2 + br, offset_bottom + bmb + self.mark_size, - 'bleedBR1', g_bleed) - self.draw_bleed_line(offset_right + bmr, self.area_y2 + bb, - offset_right + bmr + self.mark_size, self.area_y2 + bb, - 'bleedBR2', g_bleed) - - # Registration Mark - if self.options.reg_marks == True: - # Create a group for Registration Mark - g_attribs = {inkex.addNS('label','inkscape'):'RegistrationMarks', - 'id':'RegistrationMarks'} - g_center = inkex.etree.SubElement(layer, 'g', g_attribs) - - # Left Mark - cx = max( bml + offset, self.min_mark_margin ) - self.draw_reg_marks(self.area_x1 - cx - (self.mark_size/2), - middle_vertical - self.mark_size*1.5, - '0', 'regMarkL', g_center) - - # Right Mark - cx = max( bmr + offset, self.min_mark_margin ) - self.draw_reg_marks(self.area_x2 + cx + (self.mark_size/2), - middle_vertical - self.mark_size*1.5, - '180', 'regMarkR', g_center) - - # Top Mark - cy = max( bmt + offset, self.min_mark_margin ) - self.draw_reg_marks(middle_horizontal, - self.area_y1 - cy - (self.mark_size/2), - '90', 'regMarkT', g_center) - - # Bottom Mark - cy = max( bmb + offset, self.min_mark_margin ) - self.draw_reg_marks(middle_horizontal, - self.area_y2 + cy + (self.mark_size/2), - '-90', 'regMarkB', g_center) - - # Star Target - if self.options.star_target == True: - # Create a group for Star Target - g_attribs = {inkex.addNS('label','inkscape'):'StarTarget', - 'id':'StarTarget'} - g_center = inkex.etree.SubElement(layer, 'g', g_attribs) - - if self.area_h < self.area_w : - # Left Star - cx = max( bml + offset, self.min_mark_margin ) - self.draw_star_target(self.area_x1 - cx - (self.mark_size/2), - middle_vertical, - 'starTargetL', g_center) - # Right Star - cx = max( bmr + offset, self.min_mark_margin ) - self.draw_star_target(self.area_x2 + cx + (self.mark_size/2), - middle_vertical, - 'starTargetR', g_center) - else : - # Top Star - cy = max( bmt + offset, self.min_mark_margin ) - self.draw_star_target(middle_horizontal - self.mark_size*1.5, - self.area_y1 - cy - (self.mark_size/2), - 'starTargetT', g_center) - # Bottom Star - cy = max( bmb + offset, self.min_mark_margin ) - self.draw_star_target(middle_horizontal - self.mark_size*1.5, - self.area_y2 + cy + (self.mark_size/2), - 'starTargetB', g_center) - - - # Colour Bars - if self.options.colour_bars == True: - # Create a group for Colour Bars - g_attribs = {inkex.addNS('label','inkscape'):'ColourBars', - 'id':'PrintingColourBars'} - g_center = inkex.etree.SubElement(layer, 'g', g_attribs) - - if self.area_h > self.area_w : - # Left Bars - cx = max( bml + offset, self.min_mark_margin ) - self.draw_coluor_bars(self.area_x1 - cx - (self.mark_size/2), - middle_vertical + self.mark_size, - 90, - 'PrintingColourBarsL', g_center) - # Right Bars - cx = max( bmr + offset, self.min_mark_margin ) - self.draw_coluor_bars(self.area_x2 + cx + (self.mark_size/2), - middle_vertical + self.mark_size, - 90, - 'PrintingColourBarsR', g_center) - else : - # Top Bars - cy = max( bmt + offset, self.min_mark_margin ) - self.draw_coluor_bars(middle_horizontal + self.mark_size, - self.area_y1 - cy - (self.mark_size/2), - 0, - 'PrintingColourBarsT', g_center) - # Bottom Bars - cy = max( bmb + offset, self.min_mark_margin ) - self.draw_coluor_bars(middle_horizontal + self.mark_size, - self.area_y2 + cy + (self.mark_size/2), - 0, - 'PrintingColourBarsB', g_center) - - - # Page Information - if self.options.page_info == True: - # Create a group for Page Information - g_attribs = {inkex.addNS('label','inkscape'):'PageInformation', - 'id':'PageInformation'} - g_pag_info = inkex.etree.SubElement(layer, 'g', g_attribs) - y_margin = max( bmb + offset, self.min_mark_margin ) - txt_attribs = { - 'style': 'font-size:12px;font-style:normal;font-weight:normal;fill:#000000;font-family:Bitstream Vera Sans,sans-serif;text-anchor:middle;text-align:center', - 'x': str(middle_horizontal), - 'y': str(self.area_y2+y_margin+self.mark_size+20) - } - txt = inkex.etree.SubElement(g_pag_info, 'text', txt_attribs) - txt.text = 'Page size: ' +\ - str(round(self.uutounit(self.area_w,self.options.unit),2)) +\ - 'x' +\ - str(round(self.uutounit(self.area_h,self.options.unit),2)) +\ - ' ' + self.options.unit - - -if __name__ == '__main__': - e = Printing_Marks() - e.affect() diff --git a/share/extensions/ps2pdf-ext.py b/share/extensions/ps2pdf-ext.py deleted file mode 100755 index 3c699c8ff..000000000 --- a/share/extensions/ps2pdf-ext.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -""" -ps2pdf-ext.py -Python script for running ps2pdf in Inkscape extensions - -Copyright (C) 2008 Stephen Silver - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import sys -from run_command import run - -cmd = 'ps2pdf' -if (sys.argv[1] == "--dEPSCrop=true"): cmd += ' -dEPSCrop ' - -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/ps_input.inx b/share/extensions/ps_input.inx deleted file mode 100644 index c7677ffe2..000000000 --- a/share/extensions/ps_input.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>PostScript Input</_name> - <id>org.inkscape.input.ps</id> - <dependency type="extension">org.inkscape.input.pdf</dependency> - <dependency type="executable" location="path">ps2pdf</dependency> - <dependency type="executable" location="extensions">ps2pdf-ext.py</dependency> - <input> - <extension>.ps</extension> - <mimetype>image/x-postscript</mimetype> - <_filetypename>PostScript (*.ps)</_filetypename> - <_filetypetooltip>PostScript</_filetypetooltip> - <output_extension>org.inkscape.output.ps</output_extension> - </input> - <script> - <command reldir="extensions" interpreter="python">ps2pdf-ext.py</command> - <helper_extension>org.inkscape.input.pdf</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/pturtle.py b/share/extensions/pturtle.py deleted file mode 100755 index a4925bf4c..000000000 --- a/share/extensions/pturtle.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import math -class pTurtle: - '''A Python path turtle''' - def __init__(self, home=(0,0)): - self.__home = [home[0], home[1]] - self.__pos = self.__home[:] - self.__heading = -90 - self.__path = "" - self.__draw = True - self.__new = True - def forward(self,mag): - self.setpos((self.__pos[0] + math.cos(math.radians(self.__heading))*mag, - self.__pos[1] + math.sin(math.radians(self.__heading))*mag)) - def backward(self,mag): - self.setpos((self.__pos[0] - math.cos(math.radians(self.__heading))*mag, - self.__pos[1] - math.sin(math.radians(self.__heading))*mag)) - def right(self,deg): - self.__heading -= deg - def left(self,deg): - self.__heading += deg - def penup(self): - self.__draw = False - self.__new = False - def pendown(self): - if not self.__draw: - self.__new = True - self.__draw = True - def pentoggle(self): - if self.__draw: - self.penup() - else: - self.pendown() - def home(self): - self.setpos(self.__home) - def clean(self): - self.__path = '' - def clear(self): - self.clean() - self.home() - def setpos(self,(x,y)): - if self.__new: - self.__path += "M"+",".join([str(i) for i in self.__pos]) - self.__new = False - self.__pos = [x, y] - if self.__draw: - self.__path += "L"+",".join([str(i) for i in self.__pos]) - def getpos(self): - return self.__pos[:] - def setheading(self,deg): - self.__heading = deg - def getheading(self): - return self.__heading - def sethome(self,(x,y)): - self.__home = [x, y] - def getPath(self): - return self.__path - fd = forward - bk = backward - rt = right - lt = left - pu = penup - pd = pendown - - -# 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 deleted file mode 100644 index 012e50771..000000000 --- a/share/extensions/render_alphabetsoup.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Alphabet Soup</_name> - <id>org.ekips.filter.alphabetsoup</id> - <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="randomize" type="boolean" _gui-text="Randomize">false</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_alphabetsoup.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/render_alphabetsoup.py b/share/extensions/render_alphabetsoup.py deleted file mode 100755 index 4aa6af4c7..000000000 --- a/share/extensions/render_alphabetsoup.py +++ /dev/null @@ -1,544 +0,0 @@ -#!/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import copy -import math -import cmath -import string -import random -import os -import sys -import re -# local library -import inkex -import simplestyle -import render_alphabetsoup_config -import bezmisc -import simplepath -import simpletransform - -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 reverseComponent(c): - nc = [] - last = c.pop() - nc.append(['M', last[1][-2:]]) - while c: - this = c.pop() - cmd = last[0] - if cmd == 'C': - nc.append([last[0], last[1][2:4] + last[1][:2] + this[1][-2:]]) - else: - nc.append([last[0], this[1][-2:]]) - last = this - return nc - -def reversePath(sp): - rp = [] - component = [] - for p in sp: - cmd, params = p - if cmd == 'Z': - rp.extend(reverseComponent(component)) - rp.append(['Z', []]) - component = [] - else: - component.append(p) - return rp - -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) - tbimage = reversePath(tbimage) - stack.pop( 0 ) - - lrimage = tbimage - if ( stack[0] == "|" ): # left-right flip - flipLeftRight(tbimage, width) - lrimage = reversePath(lrimage) - 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(tokens, zoom ): # generate a glyph starting from each token in the input string - imagelist = [] - - for i in range(0,len(tokens)): - char = tokens[i] - #if ( re.match("[a-zA-Z0-9?]", char)): - if ( alphabet.has_key(char)): - if ((i > 0) and (char == tokens[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 - sys.stderr.write('bad character "%s"\n' % char) - return imagelist - -def generate_random_string( tokens, zoom ): # generate a totally random glyph for each glyph in the input string - imagelist = [] - for char in tokens: - if ( char == " "): # add a " " space to the image list - imagelist.append( " " ) - else: - if ( re.match("[a-z]", char )): # generate lowercase letter - stack = generate("lc") - elif ( re.match("[A-Z]", char )): # generate uppercase letter - stack = generate("UC") - else: # this character is not in config.alphabet, skip it - sys.stderr.write('bad character"%s"\n' % char) - stack = generate("start") - imagelist.append( draw_crop_scale( stack, zoom )) - - return imagelist - -def optikern( image, width, zoom ): # optical kerning algorithm - left = [] - right = [] - - resolution = 8 - for i in range( 0, 18 * resolution ): - y = 1.0/resolution * (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 - -def tokenize(text): - """Tokenize the string, looking for LaTeX style, multi-character tokens in the string, like \\yogh.""" - tokens = [] - i = 0 - while i < len(text): - c = text[i] - i += 1 - if c == '\\': # found the beginning of an escape - t = '' - while i < len(text): # gobble up content of the escape - c = text[i] - if c == '\\': # found another escape, stop this one - break - i += 1 - if c == ' ': # a space terminates this escape - break - t += c # stick this character onto the token - if t: - tokens.append(t) - else: - tokens.append(c) - return tokens - -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("-r", "--randomize", - action="store", type="inkbool", - dest="randomize", default=False, - help="Generate random (unreadable) text") - - def effect(self): - zoom = self.unittouu( str(self.options.zoom) + 'px') - - if self.options.randomize: - imagelist = generate_random_string(self.options.text, zoom) - else: - tokens = tokenize(self.options.text) - imagelist = randomize_input_string(tokens, 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) - - # compensate preserved transforms of parent layer - if self.current_layer.getparent() is not None: - mat = simpletransform.composeParents(self.current_layer, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - simpletransform.applyTransformToNode(simpletransform.invertTransform(mat), new) - - -if __name__ == '__main__': - e = AlphabetSoup() - e.affect() - diff --git a/share/extensions/render_alphabetsoup_config.py b/share/extensions/render_alphabetsoup_config.py deleted file mode 100755 index 63f3fe5c1..000000000 --- a/share/extensions/render_alphabetsoup_config.py +++ /dev/null @@ -1,584 +0,0 @@ -#!/usr/bin/env python -# Syntax format: (raise your hand if you know lisp :-) -# -# 'state0': ("file.svg", ( ( ('state1', dx, dy, T-B, L|R),), -# ( ('state2', ...), ('state3', ...),), -# ( ('state4', ...),), -# ) ), -# ) -# -# Translation of the above in CNF: -# state0 -> state1 -# state0 -> state2 state3 -# state0 -> state4 -# -# Semantics at state0: -# Paste subtree image from state1 onto "file.svg". -# Subtree image is translated by (dx, dy) (measured in units, not pixels!). -# Subtree image is flipped top to bottom if v==1. -# Subtree image is flipped left to right if h==1. -# -# Notes: -# Origin (0,0) is at *upper* left corner. -# For optional reflections, add both reflecting and non-reflecting rules -# For 180 degree rotations, set v = 1, h = 1. -# It helps to have an empty "epsilon" image. -# -# Jan. 16 2002 -# Removed zeros from the end of rules, changed the code to reflect this. -# Remember to add trailing ',' at ends of lists, especially singletons. -# -# Jan. 20-26 2002 -# Added uppercase. - -syntax = { - 'start': ("epsilon.svg", ((('lc', 0,0,0,0),),# start state - (('UC', 0,0,0,0),), - )), - # lowercase - 'lc': ("epsilon.svg", ((('barsym', 0,0,0,0),), #(2096714) (26) - (('lc2', 0,0,0,0),), #(830) (19) - )), - # uppercase - 'UC': ("epsilon.svg", ((('UCb', 0,0,0,0),), #(2160) (30) - (('UCu', 0,-5,0,0),), - )), - 'UCb': ("epsilon.svg", ((('Bar', 0,0,0,0),), #(21) Psi T I KK Phi - (('Bar', 0,0,0,1),), # - (('D', 0,0,0,0),), #(39) D O Q C G - (('D', 0,0,0,1),), # - (('E', 0,0,0,0),), #(373) E B PL 3 3r 8 S Theta Eth/Dyet - (('E', 0,0,0,1),), # - (('F', 0,0,0,0),), #(84) F P R - (('F', 0,0,0,1),), # - (('H', 0,0,0,0),), #(8) H Hblock - (('H', 0,0,0,1),), # - (('L', 0,0,0,0),), #(12) L J U - (('L', 0,0,0,1),), # - (('V', 0,0,0,1),), #(6) A V M Delta Forall W - (('X', 0,0,0,0),), #(172) X N M W Sigma NN - (('X', 0,0,0,0),), #(172) X N M W Sigma NN - )), - 'UCu': ("epsilon.svg", ((('UCb', 0,0,1,1),),)), - # for statistical balancing - 'lc2': ("epsilon.svg", ((('osym', 0,0,0,0),), #(40) o, c, e, ou - (('vsym', 0,0,0,0),), #(40) v, w, ^, y - (('dsym', 0,0,0,1),), #(96) x, z, 7, 2, yogh - (('lc3', 0,0,0,0),), #(928) (5) - )), - 'lc3': ("epsilon.svg", ((('3sym', 0,0,0,0),), #(40) epsilon - (('ssym', 0,0,0,0),), #(8) s - (('asym', 0,0,0,0),), #(880) a 6 9 - )), - # symmetry rules - 'barsym':("epsilon.svg", ((('bar', 0,0,0,0),), - (('bar', 0,0,0,1),), - (('bar', 0,0,1,0),), - (('bar', 0,0,1,1),), - )), - '6sym': ("epsilon.svg", ((('6', 0,0,0,0),), - (('6', 0,0,0,1),), - (('6', 0,0,1,0),), - (('6', 0,0,1,1),), - )), - '3sym': ("epsilon.svg", ((('3', 0,0,0,0),), - (('3', 0,0,0,1),), - (('3', 0,0,1,0),), - (('3', 0,0,1,1),), - )), - 'vsym': ("epsilon.svg", ((('v', 0,0,0,0),), - (('v', 0,0,1,1),), - )), - 'osym': ("epsilon.svg", ((('o', 0,0,0,0),), - (('o', 0,0,0,1),), - )), - 'ssym': ("epsilon.svg", ((('s', 0,0,0,0),), - (('s', 0,0,0,1),), - )), - 'dsym': ("epsilon.svg", ((('diag', 0,0,0,0), ('diag', 0,0,1,1),), - (('diag', 0,0,0,1), ('diag', 0,0,1,0),), - (('dstk', 0,0,0,0),), - )), - 'dstk': ("epsilon.svg", ((('stik', 0,4,0,0), ('z', 0,0,1,1),), - (('stik', 0,4,0,0), ('x', 0,0,1,1),), - (('stik', 0,4,0,1), ('z', 0,0,1,0),), - (('stik', 0,4,0,1), ('x', 0,0,1,0),), - )), - 'asym': ("epsilon.svg", ((('abase', 0,0,0,0),), - (('abase', 0,0,0,1),), - (('abase', 0,0,1,0),), - (('abase', 0,0,1,1),), - )), - # epsilon rules - 'diag': ("epsilon.svg", ((('x', 0,0,0,0),), - (('yogh', 0,0,1,1),), - (('z', 0,0,0,0),), - (('7', 0,0,0,0),), - (('2', 0,0,0,0),), - )), - 'bar': ("bar.svg", ((('vert', 0,0,0,0), ('vert', 0,0,1,0),), # f l i t j glot. - (('k', 0,0,0,0), ('vert', 0,0,0,0), ('vert', 0,0,1,0),), # k - (('b', 0,0,0,0), ('vert', 0,0,1,0),), # h heng - (('n', 0,0,0,0), ('vert', 0,0,1,0),), # n m r eng u uu mu - (('b1', 0,0,0,0), ('b0', 0,0,1,0),), # thorn eject. - (('b1', 0,0,0,0), ('n0', 0,0,1,0),), # b p q d - (('n1', 0,0,0,0), ('n0', 0,0,1,0),), # open-a - )), - 'vert': ("epsilon.svg", ((('xtnd', 0,0,0,0),), - (('srf', 0,0,1,0),), - #(('xtnd', 0,0,0,1),), - #(('srf', 0,0,1,1),), - )), - 'srf': ("epsilon.svg", ((('lserif', 0,0,0,0),), - (('lserif', 0,0,0,1),), - (('serif', 0,0,0,0),), - (('tserif', 0,0,0,0),), - (('tserif', 0,0,0,1),), - )), - 'xtnd': ("epsilon.svg", ((('cross', 0,0,0,0),), # this needs to be L-R flippable - (('cross', 0,0,0,1),), - (('l', 0,0,0,0),), - (('?', 0,0,0,0),), - (('?', 0,0,0,1),), - (('idot', 0,0,0,0),), - )), - 'loop': ("epsilon.svg", ((('o0', 5,0,0,1),), # loop-around elts - (('30', 5,0,0,1),), - )), - 'elike': ("epsilon.svg", ((('e', 0,0,0,0), ('crv', 0,0,1,0),), - (('a', 0,0,0,0), ('crv', 0,0,1,0),), - (('crv', 0,0,0,0), ('crv', 0,0,1,0),), - )), - 'loop2': ("epsilon.svg", ((('elike', 0,0,0,0),), - (('loop', 0,0,0,0),), - )), - 'hlike': ("epsilon.svg", ((('h', 0,0,0,0),), # h-like extensions - (('m', 0,0,0,0),), - (('crv', 0,0,0,0),), - )), - 'crv': ("epsilon.svg", ((('r', 0,0,0,0),), # curvy things - (('cserif', 0,0,1,0),), - )), - # image rules - 'abase': ("abase.svg", ((('n0', 0,0,1,0), ('loop2', 0,0,0,0),), - (('n0', 0,0,1,0), ('loop2', 0,0,1,0),), - (('b0', 0,0,1,0), ('loop2', 0,0,0,0),), - (('b0', 0,0,1,0), ('loop2', 0,0,1,0),), - )), - 'v': ("v.svg", ((('vserl', 0,0,0,0), ('vserr', 0,0,0,0),), - (('vserl', 0,0,0,0), ('vserr', 0,0,0,0), ('y0', 0,0,0,0),), - (('vserl', 0,0,0,0), ('w', 6,0,0,0),), - (('vserl', 0,0,0,0), ('w', 6,0,0,0), ('y0', 0,0,0,0),), - )), - 'w': ("v.svg", ((('vserr', 0,0,0,0),), - (('vserr', 0,0,0,0), ('y0', 0,0,0,0),), - )), - 'y0': ("epsilon.svg", ((('y', 0,0,0,1),), - (('y', 0,0,0,0),), - (('gamma', 0,0,0,0),), - )), - 'l': ("l.svg", ((('j', 0,0,0,0),), - (('j', 0,0,0,1),), - (('srf', 0,-4,1,0),), - )), - 'o': ("o.svg", ((('loop2', 0,0,0,0),), - (('loop2', 0,0,1,0),), - )), - 'cross': ("cross.svg", ((('t', 0,0,0,0),), - (('f0', 0,0,0,0),), - )), - 'f': ("f.svg", ((('j', 0, 0,0,0),), - (('j', 0, 0,0,1),), - (('srf', 0,-4,1,0),), - )), - 'f0': ("f.svg", ((('j', 0, 0,0,0),), - (('srf', 0,-4,1,0),), - )), - 'idot': ("idot.svg", ((('serif', 0,0,1,0),), - (('lserif', 0,0,1,0),), - (('lserif', 0,0,1,1),), - )), - 'stik': ("f.svg", ((('srf', 0,-4,1,0),), - #(('srf', 0,-4,1,1),), - )), - '3': ("3.svg", ((('loop2', 0,0,0,0),), - )), - # uppercase - # Bar rules - 'X': ("epsilon.svg", ((('Xtb', 0,0,0,0), ('Xtb', 0,-5,1,1),), - (('Xlr', 0,0,0,0), ('Xlr', 0,-5,1,1),), - (('Xtb', 0,0,0,0), ('Xtb2', 0,-5,1,1),), - (('Xlr', 0,0,0,0), ('Xlr2', 0,-5,1,1),), - (('Xtb2', 0,0,0,0), ('Xtb', 0,-5,1,1),), - (('Xlr2', 0,0,0,0), ('Xlr', 0,-5,1,1),), - )), - - 'Xtb': ("epsilon.svg", ((('Xnw', 0,0,0,0), ('Xne', 0,0,0,0),), - (('Xne', 0,0,0,0), ('Xh', 0,0,0,0), ('Lterm2', 0,0,0,0),), - (('Xnw', 0,0,0,0), ('Xh', 0,0,0,1), ('Lterm2', 0,0,0,1),), - (('Xne', 0,0,0,0), ('Xh', 0,0,0,0), ('Xnw', 0,0,0,0), ('Xh', 0,0,0,1),), - )), - 'Xlr': ("epsilon.svg", ((('Xne', 0,-5,1,1), ('Xnw', 0,0,0,0),), - (('Xne', 0,-5,1,1), ('Xvt', 0,0,0,0), ('Xvb', 0,0,0,0), ('ITSerif', 0.5,0,0,0),), - (('Xnw', 0, 0,0,0), ('Xvt', 0,0,0,0), ('Xvt', 0,-5,1,0), ('IBSerif', 0,0,0,0),), - (('Xne', 0,-5,1,1), ('Xnw', 0,0,0,0), ('Xvt', 0,0,0,0), ('Xvb', 0,0,0,0),), - )), - - 'Xtb2': ("epsilon.svg", ((('Xne', 0,0,0,0),), - (('Xnw', 0,0,0,0),), - )), - 'Xlr2': ("epsilon.svg", ((('Xnw', 0,0,0,0),), - (('Xne', 0,-5,1,1),), - )), - - 'Xne': ("Xne.svg",), - 'Xnw': ("Xnw.svg",), - 'Xh': ("Xh.svg",), - 'Xvt': ("Xvt.svg",), - 'Xvb': ("Xvb.svg",), - - - 'Bar': ("barcap.svg", ((('Bartop', 0,0,0,0), ('Barbot', 0,0,0,0), ('Barmid', 0,0,0,0),), - (('Bartop2', 0,0,0,0), ('Barbot2', 0,0,0,0),), - )), - 'Bartop': ("epsilon.svg", ((('ITSerif', 0.5,0,0,0),), - (('Tt', 0, 0,0,0),), - )), - 'Barbot': ("epsilon.svg", ((('IBSerif', 0,0,0,0),), - (('Tb', 0,0,0,0),), - )), - 'Barbot2': ("epsilon.svg", ((('Barbot', 0,0,0,0),), - (('Psi', 0,0,0,0),), - )), - 'Bartop2': ("epsilon.svg", ((('Bartop', 0, 0,0,0),), - (('Psi', 0,-5,1,0),), - )), - 'Barmid': ("epsilon.svg", ((('Hm', 0,0,0,0), ('Eserif', 0,0,0,0), ('Hm', -7.5,0,0,1), ('Eserif', -7.5,0,0,1),), - (('P', -2.5,3,0,0), ('P', -5, 3,0,1),), - (('P', -5,3,0,1),), #points left - )), - 'Psi': ("epsilon.svg", ((('IBSerif', 0,0,0,0), ('R', -2.5,0,0,0,), ('R', -5,0,0,1,),), - )), - # D / E / F / H / L rules - 'D': ("epsilon.svg", ((('Dterm', 0,0,0,0), ('Dterm', 0,0,0,1),), - (('Dterm', 0,0,0,0), ('Dterm2', 0,0,0,1),), - )), - 'E': ("epsilon.svg", ((('Eterm', 0,0,0,0), ('Eterm', 0,0,0,1),), - (('Eterm', 0,0,0,0), ('Eterm2', 0,0,0,1),), - (('Eterm2', 0,0,0,1), ('Eterm2', 0,-5,1,0),), # for S - )), - 'F': ("epsilon.svg", ((('Fterm', 0,0,0,0), ('Fterm', 0,0,0,1),), - (('Fterm', 0,0,0,0), ('Fterm2', 0,0,0,1),), - )), - 'H': ("epsilon.svg", ((('Hterm', 0,0,0,0), ('Hterm', 0,0,0,1),), - (('Hterm', 0,0,0,0), ('Hterm2', 0,0,0,1),), - )), - 'L': ("epsilon.svg", ((('Lterm', 0,0,0,0), ('Lterm', 0,0,0,1),), - (('Lterm', 0,0,0,0), ('Lterm2', 0,0,0,1),), - )), - 'Dterm': ("epsilon.svg", ((('Barterm', 0,0,0,0), ('Et', 0,0,0,0), ('Eb', 0,0,0,0),), - (('O', 0,0,0,0),), - )), - 'Dterm2':("epsilon.svg", ((('C', 0,0,0,1),), - (('Ltserif', 0,0,0,1), ('Lbserif', 0,0,0,1),), - )), - 'Eterm': ("epsilon.svg", ((('Barterm', 0,0,0,0), ('Et', 0,0,0,0), ('Hm', 0,0,0,0), ('Eb', 0,0,0,0),), - (('B', 0,0,0,1),), - (('O', 0,0,0,0), ('Ocross', 0,0,0,0),), - (('Dterm', 0,0,0,0), ('Eserif', 0,0,0,1),), - (('Dterm2', 0,0,0,0), ('Eserif', 0,0,0,1),), - )), - 'Eterm2':("epsilon.svg", ((('P', 0,0,0,1), ('Lterm2', 0,-5,1,0),), - )), - 'Fterm': ("epsilon.svg", ((('Barterm', 0,0,0,0), ('Et', 0,0,0,0), ('Hm', 0,0,0,0), ('IBSerif', 0,0,0,0),), - (('Lterm', 0,0,0,0), ('Eserif', 0,0,0,1),), - (('P', 0,0,0,1), ('R', 0,0,0,1),), - (('Ltserif', 0,0,0,1), ('R', 0,0,0,1),), - (('Ltserif', 0,0,0,1), ('Rblock', 0,0,0,1),), - (('Uterm', 0,0,0,0), ('Ocross', 0,0,0,0),), - )), - 'Fterm2':("epsilon.svg", ((('P', 0,0,0,1),), - (('Lterm2', 0,0,0,0), ('Eserif', 0,0,0,1),), - )), - 'Hterm': ("epsilon.svg", ((('Barterm', 0,0,0,0), ('Hm', 0,0,0,0), ('ITSerif', 0.5,0,0,0), ('IBSerif', 0,0,0,0),), - (('R', 0,0,0,1), ('R', 0,-5,1,1),), - )), - 'Hterm2':("epsilon.svg", ((('R', 0,0,0,1),), - (('Rblock',0,0,0,1),), - )), - 'Lterm': ("epsilon.svg", ((('Barterm', 0,0,0,0), ('Et', 0,0,0,0), ('IBSerif', 0,0,0,0),), - (('Uterm', 0,0,0,0),), - )), - 'Lterm2':("epsilon.svg", ((('Ltserif', 0,0,0,1),), - (('Cserif', 0,-5,1,1),), - )), - 'B': ("epsilon.svg", ((('P', 0,0,0,0), ('P', 0,6,0,0),),)), - 'C': ("epsilon.svg", ((('Cserif', 0,0,0,0), ('Cserif', 0,-5,1,0),),)), - 'Cserif':("epsilon.svg", (#(('Ctail', 0,0,0,0),), # I just hate the way these look... - (('Cblob', 0,0,0,0),), - (('Chook', 0,-5,1,0),), - (('G', 0,0,0,0),), - ),), - 'O': ("epsilon.svg", ((('Oterm', 0,0,0,0),), - (('Q', 0,0,0,1),), - (('Qu', 0,0,0,1),), - )), - 'Qu': ("epsilon.svg", ((('Q', 0,-5,1,0),),)), - 'Barterm':("barcap.svg",), - 'Ctail': ("Ctail.svg",), - 'Chook': ("Chook.svg",), - 'Cblob': ("Cblob.svg",), - 'G': ("G.svg",), - 'Ltserif':("Lt.svg",), - 'Lbserif':("Lb.svg",), - 'Et': ("Et.svg",), - 'Eb': ("Eb.svg",), - 'Hm': ("hcap.svg",), - 'P': ("P.svg",), - 'Tb': ("Tb.svg",), - 'Tt': ("Tt.svg",), - 'Ocross':("Ocross.svg",), - 'Oterm': ("ocap.svg",), - 'Q': ("Q.svg",), - 'R': ("rcap.svg", ((('IBSerif', -0.5,0,0,1),),)), - 'Rblock':("Rblock.svg", ((('IBSerif', -0.5,0,0,1),),)), - 'Uterm': ("U.svg", ((('IBSerif', -0.5,0,0,0),),)), - 'IBSerif':("IBSerif.svg",), - 'ITSerif':("ITSerif.svg",), - 'Eserif':("Eserif.svg",), - # V rules - 'V': ("vcap.svg", ((('V2', 0,0,0,0),), - (('V2', 0,0,0,0), ('Across', 0,0,0,0)), - )), - 'V2': ("epsilon.svg", ((('M', 0,0,0,0),), - (('Delta', 0,0,0,0),), - (('Vser', 0,0,0,0),), - )), - 'M': ("mcap.svg", ((('IBSerif', -1.5,0,0,0), ('IBSerif', 1.5,0,0,1),),)), - 'Delta': ("Delta.svg",), - 'Vser': ("Vser.svg",), - 'Across':("acap.svg",), - # single daughter rules - 'b': ("b.svg", ((('hlike', 0,0,0,0), ('f', 0,0,0,0),), - #(('hlike', 0,0,0,0), ('f', 0,0,0,1),), - )), - 'b1': ("b.svg", ((('loop', 0,0,0,0), ('f', 0,0,0,0),), - #(('loop', 0,0,0,0), ('f', 0,0,0,1),), - )), - 'b0': ("b.svg", ((('f', 0,0,0,0),), - #(('f', 0,0,0,1),), - )), - 'h': ("h.svg", ((('vert', 5,0,1,0),),)), - 'm': ("m.svg", ((('h', 5,0,0,0), ('vert', 5,0,1,0),),)),# change later to allow 3 humped m - 'n': ("n.svg", ((('hlike', 0,0,0,0),),)), - 'n1': ("n.svg", ((('loop', 0,0,0,0),),)), - 's': ("s.svg", ((('crv', 0,0,0,0), ('crv', 5,0,1,1),),)), - 'j': ("j.svg", ((('crv', 0,-5,0,0),),)), - '?': ("question.svg", ((('crv', -2.5,-5,0,0),),)), - 'yogh': ("yogh.svg",((('crv', -2.5,4,1,0),),)), - #terminal rules - '2': ("2.svg",), - '30': ("3.svg",), - '7': ("7.svg",), - 'a': ("a.svg",), - 'cserif':("cserif.svg",), - 'e': ("e.svg",), - 'k': ("k.svg",), - 'n0': ("n.svg",), - 'o0': ("o.svg",), - 'r': ("r.svg",), - 'serif': ("serif.svg",), - 'tserif':("tserif.svg",), - 'lserif':("lserif.svg",), - 't': ("t.svg",), - 'x': ("x.svg",), - 'z': ("z.svg",), - 'vserl': ("vserl.svg",), - 'vserr': ("vserr.svg",), - 'y': ("y.svg",), - 'gamma': ("gamma.svg",) - } - -alphabet = { - # Uppercase fix Y make 2) - '1': ("start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Bartop.[.ITSerif.].].Barbot2.[.Barbot.[.IBSerif.].].].].].]",), - '33': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.[.C.|.].Eserif.|.].Eterm.[.O.Ocross.].|.].].].]",), - '3': ("start.[.UC.[.UCb.[.E.[.Eterm.[.B.[.P.P.].|.].Eterm.[.Dterm2.[.C.|.].Eserif.|.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.[.C.|.].Eserif.|.].Eterm.[.O.Ocross.].|.].].].]",), - '4': ("start.[.UC.[.UCu.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm2.[.Rblock.[.IBSerif.|.].|.].|.].].-.|.].].]",), - '5': ("start.[.UC.[.UCu.[.UCb.[.E.[.Eterm.[.Dterm2.[.Ltserif.|.Lbserif.|.].Eserif.|.].Eterm2.[.P.|.Lterm2.[.Ltserif.|.].-.].|.].|.].-.|.].].]",), - '6': ("start.[.UC.[.UCu.[.UCb.[.E.[.Eterm.[.Dterm.[.O.].Eserif.|.].Eterm2.[.P.|.Lterm2.-.].|.].|.].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.E.[.Eterm.[.O.Ocross.].Eterm2.[.P.|.Lterm2.-.].|.].|.].-.|.].].]",), - '7': ("start.[.UC.[.UCb.[.X.[.Xtb.[.Xne.Xh.Lterm2.[.Ltserif.|.].].Xtb2.[.Xne.].-.|.].].].]",), - '8': ("start.[.UC.[.UCb.[.E.[.Eterm.[.B.[.P.P.].|.].Eterm.[.B.[.P.P.].|.].|.].].].]",), - '9': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm.[.O.].Eserif.|.].Eterm2.[.P.|.Lterm2.-.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.O.Ocross.].Eterm2.[.P.|.Lterm2.-.].|.].|.].].]",), - '0': ("start.[.UC.[.UCb.[.D.[.Dterm.[.O.].Dterm.[.O.].|.].].].]",), - 'A': ("start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Barterm.Et.Hm.IBSerif.].|.].].].]", # no flip needed - "start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Uterm.[.IBSerif.].Ocross.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Uterm.[.IBSerif.].Ocross.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].Fterm.[.Uterm.[.IBSerif.].Ocross.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm.[.Uterm.[.IBSerif.].Ocross.].|.].].].]", - "start.[.UC.[.UCu.[.UCb.[.V.[.V2.[.Vser.].Across.].|.].-.|.].].]",), - 'B': ("start.[.UC.[.UCb.[.E.[.Eterm.[.B.[.P.P.].|.].Eterm.|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm.Eserif.|.].Eterm.[.B.[.P.P.].|.].|.].].].]",), - 'Be': ("start.[.UC.[.UCu.[.UCb.[.E.[.Eterm.[.Barterm.Et.Hm.Eb.].Eterm2.[.P.|.Lterm2.-.].|.].|.].-.|.].].]", #cyrillic - "start.[.UC.[.UCu.[.UCb.[.E.[.Eterm.[.Dterm.[.Barterm.Et.Eb.].Eserif.|.].Eterm2.[.P.|.Lterm2.-.].|.].|.].-.|.].].]",), - 'C': ("start.[.UC.[.UCb.[.D.[.Dterm.[.O.[.Oterm.].].Dterm2.[.C.|.].|.].].].]",), - 'D': ("start.[.UC.[.UCb.[.D.[.Dterm.Dterm.[.O.[.Oterm.].].|.].].].]", - "start.[.UC.[.UCb.[.D.[.Dterm.[.O.[.Oterm.].].Dterm2.[.Ltserif.|.Lbserif.|.].|.].|.].].].", - "start.[.UC.[.UCb.[.D.[.Dterm.[.Barterm.Et.Eb.].Dterm.[.Barterm.Et.Eb.].|.].].].]",), - 'Delta': ("start.[.UC.[.UCu.[.UCb.[.V.[.V2.[.Delta.].].|.].-.|.].].]",), #Delta - 'De': ("start.[.UC.[.UCu.[.UCb.[.D.[.Dterm.[.Barterm.Et.Eb.].Dterm.[.Barterm.Et.Eb.].|.].].-.|.].].]",), #Cyrillic - 'E': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.Eserif.|.].Eterm.[.Dterm.[.Barterm.Et.Eb.].Eserif.|.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.Eserif.|.].Eterm.[.Dterm.[.O.].Eserif.|.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.Eserif.|.].Eterm.[.B.[.P.P.].|.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.Eserif.|.].Eterm.[.Barterm.Et.Hm.Eb.].|.].|.].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.O.Ocross.].Eterm.[.Dterm2.Eserif.|.].|.].].].]",), - 'Eth': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm.[.O.].Eserif.|.].Eterm.[.Barterm.Et.Hm.Eb.].|.].|.].].]",), - 'F': ("start.[.UC.[.UCb.[.F.[.Fterm.Fterm2.[.Lterm2.Eserif.|.].|.].].].]",), - 'G': ("start.[.UC.[.UCb.[.D.[.Dterm.[.O.].Dterm2.[.C.[.Cserif.[.G.].Cserif.-.].|.].|.].].].]",), - 'Gamma': ("start.[.UC.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm2.|.].].].]",), #Gamma - 'H': ("start.[.UC.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm.[.Barterm.Hm.ITSerif.IBSerif.].|.].].].]", - "start.[.UC.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm2.[.R.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm2.[.Rblock.[.IBSerif.|.].|.].|.].].].]",), - 'Che': ("start.[.UC.[.UCu.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm2.[.Rblock.[.IBSerif.|.].|.].|.].].-.|.].].]", #Cyrillic - "start.[.UC.[.UCu.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm2.[.R.[.IBSerif.|.].|.].|.].].-.|.].].]",), - 'Heng': ("start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Ltserif.|.R.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm.[.Ltserif.|.Rblock.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm.[.Ltserif.|.R.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm.[.Ltserif.|.Rblock.[.IBSerif.|.].|.].|.].].].]",), - 'I': ("start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Bartop.[.ITSerif.].].Barbot2.[.Barbot.[.IBSerif.].].].].].]", - "start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Bartop.[.Tt.].].Barbot2.[.Barbot.[.Tb.].].].].].]",), - 'J': ("start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Uterm.[.IBSerif.].].Lterm2.|.].].-.|.].].]",), - 'K': ("start.[.UC.[.UCu.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xnw.].Xlr.[.Xne.-.|.Xvt.Xvb.ITSerif.].-.|.].].-.|.].].]", - "start.[.UC.[.UCb.[.H.[.Hterm.[.Barterm.Hm.ITSerif.IBSerif.].Hterm.[.R.[.IBSerif.|.].|.R.[.IBSerif.|.].-.|.].|.].].].]",), - 'Zhe': ("start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Psi.[.IBSerif.R.[.IBSerif.|.].R.[.IBSerif.|.].|.].-.].Barbot2.[.Psi.[.IBSerif.R.[.IBSerif.|.].R.[.IBSerif.|.].|.].].].].].]",), # Cyrillic - 'L': ("start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm2.|.].|.].-.|.].].]",), - 'Lambda':("start.[.UC.[.UCu.[.UCb.[.V.[.V2.[.Vser.].].|.].-.|.].].]",),# Lambda - 'M': ("start.[.UC.[.UCu.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xvt.Xvb.ITSerif.].Xlr.[.Xnw.Xvt.Xvt.-.IBSerif.].-.|.].].-.|.].].]", - "start.[.UC.[.UCb.[.V.[.V2.[.M.[.IBSerif.IBSerif.|.].].].|.].].]",), - 'N': ("start.[.UC.[.UCu.[.UCb.[.X.[.Xlr.[.Xnw.Xvt.Xvt.-.IBSerif.].Xlr.[.Xnw.Xvt.Xvt.-.IBSerif.].-.|.].].-.|.].].]", - "start.[.UC.[.UCb.[.L.[.Lterm.[.Uterm.[.IBSerif.].].Lterm.[.Barterm.Et.IBSerif.].|.].|.].].]",), - 'NN': ("start.[.UC.[.UCu.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xvt.Xvb.ITSerif.].Xlr.[.Xne.-.|.Xvt.Xvb.ITSerif.].-.|.].].-.|.].].]",), # Cyrillic I - 'O': ("start.[.UC.[.UCb.[.D.[.Dterm.[.O.].Dterm.[.O.].|.].].].]",), - 'P': ("start.[.UC.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm2.[.P.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Ltserif.|.R.[.IBSerif.|.].|.].Fterm2.[.P.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Ltserif.|.Rblock.[.IBSerif.|.].|.].Fterm2.[.P.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm2.[.P.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].Fterm2.[.P.|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm2.[.P.|.].|.].].].]",), - 'PL': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm.[.Barterm.Et.Eb.].Eserif.|.].Eterm2.[.P.|.Lterm2.-.].|.].].].]", - "start.[.UC.[.UCb.[.E.[.Eterm.[.Barterm.Et.Hm.Eb.].Eterm2.[.P.|.Lterm2.[.Cserif.-.|.].-.].|.].].].]",), - 'Phi': ("start.[.UC.[.UCb.[.Bar.[.Bartop.[.ITSerif.].Barbot.[.IBSerif.].Barmid.[.P.P.|.].].].].]",), - 'Pi': ("start.[.UC.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm.[.Barterm.Et.IBSerif.].|.].].].]",), - 'Psi': ("start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Psi.[.IBSerif.R.[.IBSerif.|.].R.[.IBSerif.|.].|.].-.].Barbot2.[.Barbot.[.IBSerif.].].].].].]",), - 'Soft': ("start.[.UC.[.UCu.[.UCb.[.F.[.Fterm.[.Barterm.Et.Hm.IBSerif.].Fterm2.[.P.|.].|.].|.].-.|.].].]",# Cyrillic Yeru/Soft/Hard - "start.[.UC.[.UCu.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm2.[.P.|.].|.].|.].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.F.[.Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].Fterm2.[.P.|.].|.].|.].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.F.[.Fterm.[.Ltserif.|.Rblock.[.IBSerif.|.].|.].Fterm2.[.P.|.].|.].|.].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm2.[.P.|.].|.].|.].-.|.].].]",), - 'Q': ("start.[.UC.[.UCb.[.D.[.Dterm.[.O.[.Oterm.].].Dterm.[.O.[.Q.|.].].|.].].].]",), - 'R': ("start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.P.|.R.[.IBSerif.|.].|.].Fterm.[.Barterm.Et.Hm.IBSerif.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].].].]",), - 'Ya': ("start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Barterm.Et.IBSerif.].Eserif.|.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Lterm.[.Uterm.[.IBSerif.].].Eserif.|.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].|.].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.P.|.R.[.IBSerif.|.].|.].Fterm.[.Barterm.Et.Hm.IBSerif.].|.].].].]", - "start.[.UC.[.UCb.[.F.[.Fterm.[.Uterm.[.IBSerif.].Ocross.].Fterm.[.P.|.R.[.IBSerif.|.].|.].|.].|.].].]",), - 'S': ("start.[.UC.[.UCb.[.E.[.Eterm2.[.P.|.Lterm2.-.].|.Eterm2.[.P.|.Lterm2.-.].-.].|.].].]",), - 'Sigma': ("start.[.UC.[.UCb.[.X.[.Xtb.[.Xnw.Xh.|.Lterm2.|.].Xtb.[.Xne.Xh.Lterm2.].-.|.].].].]",), - 'T': ("start.[.UC.[.UCb.[.Bar.[.Bartop2.[.Bartop.[.Tt.].].Barbot2.[.Barbot.[.IBSerif.].].].].].]", - "start.[.UC.[.UCb.[.Bar.[.Bartop.[.ITSerif.].Barbot.[.IBSerif.].Barmid.[.Hm.Eserif.Hm.|.Eserif.|.].].].].]",), - 'Theta': ("start.[.UC.[.UCb.[.E.[.Eterm.[.O.Ocross.].Eterm.[.O.Ocross.].|.].].].]",), - 'Thorn': ("start.[.UC.[.UCu.[.UCb.[.Bar.[.Bartop.[.ITSerif.].Barbot.[.IBSerif.].Barmid.[.P.|.].].].-.|.].].]",), - 'U': ("start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm.[.Barterm.Et.IBSerif.].|.].|.].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm.[.Uterm.[.IBSerif.].].|.].].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Uterm.[.IBSerif.].].Lterm.[.Uterm.[.IBSerif.].].|.].].-.|.].].]", - "start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm.[.Barterm.Et.IBSerif.].|.].].-.|.].].]",), - 'Tse': ("start.[.UC.[.UCu.[.UCb.[.L.[.Lterm.[.Barterm.Et.IBSerif.].Lterm.[.Barterm.Et.IBSerif.].|.].].-.|.].].]",),# Cyrillic - 'V': ("start.[.UC.[.UCb.[.V.[.V2.[.Vser.].].|.].].]",), - 'W': ("start.[.UC.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xvt.Xvb.ITSerif.].Xlr.[.Xnw.Xvt.Xvt.-.IBSerif.].-.|.].].].]", - "start.[.UC.[.UCu.[.UCb.[.V.[.V2.[.M.[.IBSerif.IBSerif.|.].].].|.].-.|.].].]",), - 'X': ("start.[.UC.[.UCu.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xnw.].Xlr.[.Xne.-.|.Xnw.].-.|.].].-.|.].].]", - "start.[.UC.[.UCb.[.H.[.Hterm.[.R.|.R.-.|.].Hterm.[.R.|.R.-.|.].|.].].].]",), - 'Xi': ("start.[.UC.[.UCb.[.E.[.Eterm.[.Dterm2.[.Ltserif.|.Lbserif.|.].Eserif.|.].Eterm.[.Dterm2.[.Ltserif.|.Lbserif.|.].Eserif.|.].|.].|.].].]",), - 'Y': ("start.[.UC.[.UCb.[.X.[.Xlr.[.Xne.-.|.Xnw.].Xlr2.[.Xne.-.|.].-.|.].].].]",), - 'Z': ("start.[.UC.[.UCb.[.X.[.Xtb.[.Xne.Xh.Lterm2.].Xtb.[.Xne.Xh.Lterm2.].-.|.].].].]",), - # Lowercase - 'a': ("start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.n0.-.loop2.[.elike.[.a.crv.-.].].-.].|.].].].].]", - "start.[.lc.[.barsym.[.bar.[.n1.[.loop.].n0.-.].-.|.].].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.n0.-.loop2.[.loop.].].|.].].].].]",), - 'carat':("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.vserr.].-.|.].].].]",), - 'b': ("start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.].n0.-.].].].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.].-.loop2.[.loop.].].-.].].].].]", - "start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.|.].n0.-.].].].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.|.].-.loop2.[.loop.].].-.].].].].]",), - 'c': ("start.[.lc.[.lc2.[.osym.[.o.[.loop2.[.elike.[.crv.-.|.crv.|.].|.].].].].].]",), - 'd': ("start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.].n0.-.].].|.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.].-.loop2.[.loop.].].-.].|.].].].]", - "start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.|.].n0.-.].].|.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.|.].-.loop2.[.loop.].].-.].|.].].].]",), - 'e': ("start.[.lc.[.lc2.[.osym.[.o.[.loop2.[.elike.[.e.crv.-.].].].].].].]", - "start.[.lc.[.lc2.[.lc3.[.3sym.[.3.[.loop2.[.elike.[.crv.crv.-.].].].].].].].]",), - 'epsi': ("start.[.lc.[.lc2.[.lc3.[.3sym.[.3.[.loop2.[.elike.[.crv.crv.-.].].].].].].].]",), - 'f': ("start.[.lc.[.barsym.[.bar.[.vert.[.xtnd.[.cross.[.f0.[.j.].].].].vert.-.].].].]",), - 'g': ("start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.[.j.[.crv.].].].n0.-.].-.|.].].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.[.j.].].-.loop2.[.loop.].].-.].-.|.].].].]",), - 'gamma':("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.vserr.y0.[.gamma.].].].].].]",), - 'h': ("start.[.lc.[.barsym.[.bar.[.b.[.hlike.[.h.].f.].vert.-.].].].]", - "start.[.lc.[.barsym.[.bar.[.b.[.hlike.[.h.].f.|.].vert.-.].].].]",), - 'heng': ("start.[.lc.[.barsym.[.bar.[.b.[.hlike.[.h.[.vert.[.xtnd.[.l.[.j.[.crv.].].].|.].-.].].f.[.j.[.crv.].].].vert.[.srf.-.|.].-.].].].]",), - 'i': ("start.[.lc.[.barsym.[.bar.[.vert.vert.[.xtnd.[.idot.].-.].].-.|.].].]", - "start.[.lc.[.barsym.[.bar.[.vert.vert.[.xtnd.[.idot.].-.].|.].-.|.].].]",), - 'j': ("start.[.lc.[.barsym.[.bar.[.vert.[.xtnd.[.idot.].-.].vert.[.xtnd.[.l.[.j.].].].|.].-.].].]",), - 'k': ("start.[.lc.[.barsym.[.bar.[.k.vert.vert.-.].].].]",), - 'l': ("start.[.lc.[.barsym.[.bar.[.vert.vert.[.xtnd.[.l.].-.].|.].-.|.].].]", - "start.[.lc.[.barsym.[.bar.[.vert.vert.[.xtnd.[.l.|.].-.].|.].-.|.].].]",), - 'lambda':("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.vserr.y0.].-.|.].].].]",), - 'm': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.m.[.h.[.vert.-.].vert.-.].].].vert.-.].].].]",), - 'mu': ("start.[.lc.[.barsym.[.bar.[.b.[.hlike.[.h.[.vert.-.].].f.].vert.-.].-.|.].].]",), - 'muu': ("start.[.lc.[.barsym.[.bar.[.b.[.hlike.[.m.[.h.[.vert.-.].vert.-.].].f.].vert.-.|.].-.|.].].]",), - 'n': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.h.[.vert.-.].].].vert.-.].].].]",), - 'ng': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.h.[.vert.[.xtnd.[.l.[.j.].].|.].-.].].].vert.-.].].].]",), - 'o': ("start.[.lc.[.lc2.[.osym.[.o.[.loop2.[.loop.[.o0.|.].].].].].].]",), - 'p': ("start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.].n0.-.].].-.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.].-.loop2.[.loop.].].-.].-.].].].]", - "start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.|.].n0.-.].].-.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.|.].-.loop2.[.loop.].].-.].-.].].].]",), - 'q': ("start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.].n0.-.].].-.|.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.].-.loop2.[.loop.].].-.].-.|.].].].]", - "start.[.lc.[.barsym.[.bar.[.b1.[.loop.f.|.].n0.-.].].-.|.].]", - "start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.|.].-.loop2.[.loop.].].-.].-.|.].].].]",), - 'r': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.crv.].].vert.-.].].].]",), - 's': ("start.[.lc.[.lc2.[.lc3.[.ssym.[.s.[.crv.crv.-.|.].].].].].]",), - 't': ("start.[.lc.[.barsym.[.bar.[.vert.[.xtnd.[.cross.[.f0.].].].vert.-.].].].]",), - 'u': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.h.[.vert.-.].].].vert.-.].-.|.].].]",), - 'uu': ("start.[.lc.[.barsym.[.bar.[.n.[.hlike.[.m.[.h.[.vert.-.].vert.-.].].].vert.-.].-.|.].].]",), - 'v': ("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.vserr.].].].].]",), - 'w': ("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.w.[.vserr.].].].].].]",), - 'x': ("start.[.lc.[.lc2.[.dsym.[.diag.[.x.].-.diag.[.x.].|.].-.].].]",), - 'y': ("start.[.lc.[.lc2.[.vsym.[.v.[.vserl.vserr.y0.].].].].]",), - 'yogh': ("start.[.lc.[.lc2.[.dsym.[.diag.[.z.].|.diag.[.yogh.[.crv.-.].-.|.].-.].].].]",), - 'z': ("start.[.lc.[.lc2.[.dsym.[.diag.[.z.].diag.[.z.].-.|.].|.].].]",), - 'glot': ("start.[.lc.[.barsym.[.bar.[.vert.[.xtnd.[.?.|.].].vert.-.].].].]",), - '1l': ("start.[.lc.[.barsym.[.bar.[.vert.[.srf.[.lserif.].].vert.[.srf.[.serif.].-.].|.].].-.].]",), - '2l': ("start.[.lc.[.lc2.[.dsym.[.diag.[.2.].diag.[.z.].-.|.].|.].].]",), - '3l': ("start.[.lc.[.lc2.[.dsym.[.diag.[.z.].|.diag.[.yogh.[.crv.-.].-.|.].-.].].].]",), - '6l': ("start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.[.j.].].-.loop2.[.loop.].-.].-.].].].].]",), - '7l': ("start.[.lc.[.lc2.[.dsym.[.diag.[.z.].diag.[.7.].-.|.].|.].].]",), - '8l': ("start.[.lc.[.lc2.[.lc3.[.3sym.[.3.[.loop2.[.loop.[.30.|.].].].].].].].]",), - '9l': ("start.[.lc.[.lc2.[.lc3.[.asym.[.abase.[.b0.[.f.[.j.].].-.loop2.[.loop.].-.].|.].].].].]",), - '0l': ("start.[.lc.[.lc2.[.osym.[.o.[.loop2.[.loop.[.o0.|.].].].].].].]",) - } - -space = 4 # number of unit boxes to make a " " space in string -units = 36 # pixels per unit box in font -font = "alphabet_soup/" # location of font images - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/render_barcode.inx b/share/extensions/render_barcode.inx deleted file mode 100644 index 890ffb1bd..000000000 --- a/share/extensions/render_barcode.inx +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Classic</_name> - <id>org.inkscape.render.barcode</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">render_barcode.py</dependency> - <param name="type" type="enum" _gui-text="Barcode Type:"> - <item value="Ean2">EAN2 Extension</item> - <item value="Ean5">EAN5 Extension</item> - <item value="Ean13">EAN13 +Extensions</item> - <item value="Ean8">EAN8</item> - <item value="Upca">UPC-A</item> - <item value="Upce">UPC-E</item> - <item value="Code25i">Code25 Interleaved 2 of 5</item> - <item value="Code39">Code39</item> - <item value="Code39Ext">Code39 Extended</item> - <item value="Code93">Code93</item> - <item value="Code128">Code128</item> - <item value="Rm4scc">RM4CC / RM4SCC</item> - </param> - <param name="text" type="string" _gui-text="Barcode Data:"></param> - <param name="height" type="int" _gui-text="Bar Height:" min="20" max="80">30</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Barcode" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_barcode.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/render_barcode.py b/share/extensions/render_barcode.py deleted file mode 100755 index 63436f03c..000000000 --- a/share/extensions/render_barcode.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2007 Martin Owens -# -# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA. -# -""" -Inkscape's general barcode extension. Run from within inkscape or use the -Barcode module provided for outside or scripting. -""" - -import inkex -import sys -from Barcode import getBarcode -from simpletransform import computePointInNode - -class InsertBarcode(inkex.Effect): - """ - Raw barcode Effect class, see Barcode base class. - """ - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-l", "--height", - action="store", type="int", - dest="height", default=30, - help="Barcode Height") - self.OptionParser.add_option("-t", "--type", - action="store", type="string", - dest="type", default='', - help="Barcode Type") - self.OptionParser.add_option("-d", "--text", - action="store", type="string", - dest="text", default='', - help="Text to print on barcode") - - def effect(self): - (pos_x, pos_y) = computePointInNode( - list(self.view_center), self.current_layer) - - barcode = getBarcode(self.options.type, - text=self.options.text, - height=self.options.height, - document=self.document, - x=pos_x, y=pos_y, - scale=self.unittouu('1px'), - ).generate() - if barcode is not None: - self.current_layer.append(barcode) - else: - sys.stderr.write("No barcode was generated\n") - -def test_barcode(): - """Run from command line""" - for (kind, text) in ( - ('Ean2', '55'), - ('Ean5', '54321'), - ('Ean8', '0123456'), - ('Ean13', '123456789101'), - ('Ean13', '12345678910155'), - ('Ean13', '12345678910154321'), - ('Code128', 'Martin is Great'), - ('Code25i', '3242322'), - ('Code39', '4443322888'), - ('Code93', '3332222'), - ('Rm4scc', 'ROYAL POINT'), - ('Upca', '12345678911'), - ('Upce', '123456'), - ): - print "RENDER TEST: %s" % kind - bargen = getBarcode(kind, text=text) - if bargen is not None: - barcode = bargen.generate() - if barcode is not None: - print inkex.etree.tostring(barcode, pretty_print=True) - - -if __name__ == '__main__': - if len(sys.argv) == 1: - # Debug mode without inkex - test_barcode() - exit(0) - InsertBarcode().affect() - diff --git a/share/extensions/render_barcode_datamatrix.inx b/share/extensions/render_barcode_datamatrix.inx deleted file mode 100644 index 5fd709610..000000000 --- a/share/extensions/render_barcode_datamatrix.inx +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Datamatrix</_name> - <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="symbol" _gui-text="Size, in unit squares:" type="enum"> - <item value="sq10">10x10</item> - <item value="sq12">12x12</item> - <item value="sq14">14x14</item> - <item value="sq16">16x16</item> - <item value="sq18">18x18</item> - <item value="sq20">20x20</item> - <item value="sq22">22x22</item> - <item value="sq24">24x24</item> - <item value="sq26">26x26</item> - <item value="sq32">32x32</item> - <item value="sq36">36x36</item> - <item value="sq40">40x40</item> - <item value="sq44">44x44</item> - <item value="sq48">48x48</item> - <item value="sq52">52x52</item> - <item value="sq64">64x64</item> - <item value="sq72">72x72</item> - <item value="sq80">80x80</item> - <item value="sq88">88x88</item> - <item value="sq96">96x96</item> - <item value="sq104">104x104</item> - <item value="sq120">120x120</item> - <item value="sq132">132x132</item> - <item value="sq144">144x144</item> - <item value="rect8x18">8x18</item> - <item value="rect8x32">8x32</item> - <item value="rect12x26">12x26</item> - <item value="rect12x36">12x36</item> - <item value="rect16x36">16x36</item> - <item value="rect16x48">16x48</item> - </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> - <submenu _name="Render"> - <submenu _name="Barcode" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_barcode_datamatrix.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/render_barcode_datamatrix.py b/share/extensions/render_barcode_datamatrix.py deleted file mode 100755 index 0f237297f..000000000 --- a/share/extensions/render_barcode_datamatrix.py +++ /dev/null @@ -1,697 +0,0 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- -''' -Copyright (C) 2009 John Beard john.j.beard@gmail.com - -######DESCRIPTION###### - -This extension renders a DataMatrix 2D barcode, as specified in -BS ISO/IEC 16022:2006. Only ECC200 codes are considered, as these are the only -ones recommended for an "open" system. - -The size of the DataMatrix is variable between 10x10 to 144x144 - -The absolute size of the DataMatrix modules (the little squares) is also -variable. - -If more data is given than can be contained in one DataMatrix, -more than one DataMatrices will be produced. - -Text is encoded as ASCII (the standard provides for other options, but these are -not implemented). Consecutive digits are encoded in a compressed form, halving -the space required to store them. - -The basis processing flow is; - * Convert input string to codewords (modified ASCII and compressed digits) - * Split codewords into blocks of the right size for Reed-Solomon coding - * Interleave the blocks if required - * Apply Reed-Solomon coding - * De-interleave the blocks if required - * Place the codewords into the matrix bit by bit - * Render the modules in the matrix as squares - -######LICENCE####### -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -######VERSION HISTORY##### - Ver. Date Notes - - 0.50 2009-10-25 Full functionality, up to 144x144. - ASCII and compressed digit encoding only. -''' -# local library -import inkex -import simplestyle -from simpletransform import computePointInNode - -symbols = { - 'sq10': (10, 10), - 'sq12': (12, 12), - 'sq14': (14, 14), - 'sq16': (16, 16), - 'sq18': (18, 18), - 'sq20': (20, 20), - 'sq22': (22, 22), - 'sq24': (24, 24), - 'sq26': (26, 26), - 'sq32': (32, 32), - 'sq36': (36, 36), - 'sq40': (40, 40), - 'sq44': (44, 44), - 'sq48': (48, 48), - 'sq52': (52, 52), - 'sq64': (64, 64), - 'sq72': (72, 72), - 'sq80': (80, 80), - 'sq88': (88, 88), - 'sq96': (96, 96), - 'sq104': (104, 104), - 'sq120': (120, 120), - 'sq132': (132, 132), - 'sq144': (144, 144), - 'rect8x18': (8, 18), - 'rect8x32': (8, 32), - 'rect12x26': (12, 26), - 'rect12x36': (12, 36), - 'rect16x36': (16, 36), - 'rect16x48': (16, 48), -} - -#ENCODING ROUTINES =================================================== -# Take an input string and convert it to a sequence (or sequences) -# of codewords as specified in ISO/IEC 16022:2006 (section 5.2.3) -#===================================================================== - -#create a 2d list corresponding to the 1's and 0s of the DataMatrix -def encode(text, (nrow, ncol) ): - #retrieve the parameters of this size of DataMatrix - data_nrow, data_ncol, reg_row, reg_col, nd, nc, inter = get_parameters( nrow, ncol ) - - if not ((nrow == 144) and (ncol == 144)): #we have a regular datamatrix - size144 = False - else: #special handling will be required by get_codewords() - size144 = True - - #generate the codewords including padding and ECC - codewords = get_codewords( text, nd, nc, inter, size144 ) - - # break up into separate arrays if more than one DataMatrix is needed - module_arrays = [] - for codeword_stream in codewords: #for each datamatrix - bit_array = place_bits(codeword_stream, (data_nrow*reg_row, data_ncol*reg_col)) #place the codewords' bits across the array as modules - module_arrays.append(add_finder_pattern( bit_array, data_nrow, data_ncol, reg_row, reg_col )) #add finder patterns around the modules - - return module_arrays - -#return parameters for the selected datamatrix size -# data_nrow number of rows in each data region -# data_ncol number of cols in each data region -# reg_row number of rows of data regions -# reg_col number of cols of data regions -# nd number of data codewords per reed-solomon block -# nc number of ECC codewords per reed-solomon block -# inter number of interleaved Reed-Solomon blocks -def get_parameters(nrow, ncol): - - #SQUARE SYMBOLS - if ( nrow == 10 and ncol == 10 ): - return 8, 8, 1, 1, 3, 5, 1 - elif ( nrow == 12 and ncol == 12 ): - return 10, 10, 1, 1, 5, 7, 1 - elif ( nrow == 14 and ncol == 14 ): - return 12, 12, 1, 1, 8, 10, 1 - elif ( nrow == 16 and ncol == 16 ): - return 14, 14, 1, 1, 12, 12, 1 - elif ( nrow == 18 and ncol == 18 ): - return 16, 16, 1, 1, 18, 14, 1 - elif ( nrow == 20 and ncol == 20 ): - return 18, 18, 1, 1, 22, 18, 1 - elif ( nrow == 22 and ncol == 22 ): - return 20, 20, 1, 1, 30, 20, 1 - elif ( nrow == 24 and ncol == 24 ): - return 22, 22, 1, 1, 36, 24, 1 - elif ( nrow == 26 and ncol == 26 ): - return 24, 24, 1, 1, 44, 28, 1 - elif ( nrow == 32 and ncol == 32 ): - return 14, 14, 2, 2, 62, 36, 1 - elif ( nrow == 36 and ncol == 36 ): - return 16, 16, 2, 2, 86, 42, 1 - elif ( nrow == 40 and ncol == 40): - return 18, 18, 2, 2, 114, 48, 1 - elif ( nrow == 44 and ncol == 44): - return 20, 20, 2, 2, 144, 56, 1 - elif ( nrow == 48 and ncol == 48 ): - return 22, 22, 2, 2, 174, 68, 1 - - elif ( nrow == 52 and ncol == 52 ): - return 24, 24, 2, 2, 102, 42, 2 - elif ( nrow == 64 and ncol == 64 ): - return 16, 16, 4, 4, 140, 56, 2 - - elif ( nrow == 72 and ncol == 72 ): - return 16, 16, 4, 4, 92, 36, 4 - elif ( nrow == 80 and ncol == 80 ): - return 18, 18, 4, 4, 114, 48, 4 - elif ( nrow == 88 and ncol == 88 ): - return 20, 20, 4, 4, 144, 56, 4 - elif ( nrow == 96 and ncol == 96 ): - return 22, 22, 4, 4, 174, 68, 4 - - elif ( nrow == 104 and ncol == 104 ): - return 24, 24, 4, 4, 136, 56, 6 - elif ( nrow == 120 and ncol == 120): - return 18, 18, 6, 6, 175, 68, 6 - - elif ( nrow == 132 and ncol == 132): - return 20, 20, 6, 6, 163, 62, 8 - - elif (nrow == 144 and ncol == 144): - return 22, 22, 6, 6, 0, 0, 0 #there are two separate sections of the data matrix with - #different interleaving and reed-solomon parameters. - #this will be handled separately - - #RECTANGULAR SYMBOLS - elif ( nrow == 8 and ncol == 18 ): - return 6, 16, 1, 1, 5, 7, 1 - elif ( nrow == 8 and ncol == 32 ): - return 6, 14, 1, 2, 10, 11, 1 - elif ( nrow == 12 and ncol == 26 ): - return 10, 24, 1, 1, 16, 14, 1 - elif ( nrow == 12 and ncol == 36 ): - return 10, 16, 1, 2, 22, 18, 1 - elif ( nrow == 16 and ncol == 36 ): - return 14, 16, 1, 2, 32, 24, 1 - elif ( nrow == 16 and ncol == 48 ): - return 14, 22, 1, 2, 49, 28, 1 - - #RETURN ERROR - else: - inkex.errormsg(_('Unrecognised DataMatrix size')) - exit(0) - - return None - -# CODEWORD STREAM GENERATION ========================================= -#take the text input and return the codewords, -#including the Reed-Solomon error-correcting codes. -#===================================================================== - -def get_codewords( text, nd, nc, inter, size144 ): - #convert the data to the codewords - data = encode_to_ascii( text ) - - if not size144: #render a "normal" datamatrix - data_blocks = partition_data(data, nd*inter) #partition into data blocks of length nd*inter -> inter Reed-Solomon block - - data_blocks = interleave( data_blocks, inter) # interleave consecutive inter blocks if required - - data_blocks = reed_solomon(data_blocks, nd, nc) #generate and append the Reed-Solomon codewords - - data_blocks = combine_interleaved(data_blocks, inter, nd, nc, False) #concatenate Reed-Solomon blocks bound for the same datamatrix - - else: #we have a 144x144 datamatrix - data_blocks = partition_data(data, 1558) #partition the data into datamtrix-sized chunks (1558 =156*8 + 155*2 ) - - for i in range(len(data_blocks)): #for each datamtrix - - - inter = 8 - nd = 156 - nc = 62 - block1 = data_blocks[i][0:156*8] - block1 = interleave( [block1], inter) # interleave into 8 blocks - block1 = reed_solomon(block1, nd, nc) #generate and append the Reed-Solomon codewords - - inter = 2 - nd = 155 - nc = 62 - block2 = data_blocks[i][156*8:] - block2 = interleave( [block2], inter) # interleave into 2 blocks - block2 = reed_solomon(block2, nd, nc) #generate and append the Reed-Solomon codewords - - blocks = block1 - blocks.extend(block2) - - blocks = combine_interleaved(blocks, 10, nd, nc, True) - - data_blocks[i] = blocks[0] - - - return data_blocks - - -#Takes a codeword stream and splits up into "inter" blocks. -#eg interleave( [1,2,3,4,5,6], 2 ) -> [1,3,5], [2,4,6] -def interleave( blocks, inter): - - if inter == 1: # if we don't have to interleave, just return the blocks - return blocks - else: - result = [] - for block in blocks: #for each codeword block in the stream - block_length = len(block)/inter #length of each interleaved block - inter_blocks = [[0] * block_length for i in xrange(inter)] #the interleaved blocks - - for i in range(block_length): #for each element in the interleaved blocks - for j in range(inter): #for each interleaved block - inter_blocks[j][i] = block[ i*inter + j ] - - result.extend(inter_blocks) #add the interleaved blocks to the output - - return result - -#Combine interleaved blocks into the groups for the same datamatrix -# -#e.g combine_interleaved( [[d1, d3, d5, e1, e3, e5], [d2, d4, d6, e2, e4, e6]], 2, 3, 3 ) -# --> [[d1, d2, d3, d4, d5, d6, e1, e2, e3, e4, e5, e6]] -def combine_interleaved( blocks, inter, nd, nc, size144): - if inter == 1: #the blocks aren't interleaved - return blocks - else: - result = [] - for i in range( len(blocks) / inter ): #for each group of "inter" blocks -> one full datamatrix - data_codewords = [] #interleaved data blocks - - if size144: - nd_range = 1558 #1558 = 156*8 + 155*2 - nc_range = 620 #620 = 62*8 + 62*2 - else: - nd_range = nd*inter - nc_range = nc*inter - - for j in range(nd_range): #for each codeword in the final list - data_codewords.append( blocks[i*inter + j%inter][j/inter] ) - - for j in range(nc_range): #for each block, add the ecc codewords - data_codewords.append( blocks[i*inter + j%inter][nd + j/inter] ) - - result.append(data_codewords) - return result - -#checks if an ASCII character is a digit from 0 - 9 -def is_digit( char ): - - if ord(char) >= 48 and ord(char) <= 57: - return True - else: - return False - -def encode_to_ascii( text): - - ascii = [] - i = 0 - while i < len(text): - #check for double digits - if is_digit( text[i] ) and ( i < len(text)-1) and is_digit( text[i+1] ): #if the next char is also a digit - - codeword = int( text[i] + text[i+1] ) + 130 - ascii.append( codeword ) - i = i + 2 #move on 2 characters - else: #encode as a normal ascii, - ascii.append( ord(text[i] ) + 1 ) #codeword is ASCII value + 1 (ISO 16022:2006 5.2.3) - i = i + 1 #next character - - return ascii - - -#partition data into blocks of the appropriate size to suit the -#Reed-Solomon block being used. -#e.g. partition_data([1,2,3,4,5], 3) -> [[1,2,3],[4,5,PAD]] -def partition_data( data , rs_data): - - PAD_VAL = 129 # PAD codeword (ISO 16022:2006 5.2.3) - data_blocks = [] - i = 0 - while i < len(data): - if len(data) >= i+rs_data: #we have a whole block in our data - data_blocks.append( data[i:i+rs_data] ) - i = i + rs_data - else: #pad out with the pad codeword - data_block = data[i:len(data)] #add any remaining data - pad_pos = len(data) - padded = False - while len(data_block) < rs_data:#and then pad with randomised pad codewords - if not padded: - data_block.append( PAD_VAL ) #add a normal pad codeword - padded = True - else: - data_block.append( randomise_pad_253( PAD_VAL, pad_pos) ) - pad_pos = pad_pos + 1 - data_blocks.append( data_block) - break - - return data_blocks - -#Pad character randomisation, to prevent regular patterns appearing -#in the data matrix -def randomise_pad_253(pad_value, pad_position ): - pseudo_random_number = ( ( 149 * pad_position ) % 253 )+ 1 - randomised = pad_value + pseudo_random_number - if ( randomised <= 254 ): - return randomised - else: - return randomised - 254 - -# REED-SOLOMON ENCODING ROUTINES ===================================== - -# "prod(x,y,log,alog,gf)" returns the product "x" times "y" -def prod(x, y, log, alog, gf): - - if ( x==0 or y==0): - return 0 - else: - result = alog[ ( log[x] + log[y] ) % (gf - 1) ] - return result - -# generate the log & antilog lists: -def gen_log_alog(gf, pp): - log = [0]*gf - alog = [0]*gf - - log[0] = 1-gf - alog[0] = 1 - - for i in range(1,gf): - alog[i] = alog[i-1] * 2 - - if (alog[i] >= gf): - alog[i] = alog[i] ^ pp - - log[alog[i]] = i - - return log, alog - -# generate the generator polynomial coefficients: -def gen_poly_coeffs(nc, log, alog, gf): - c = [0] * (nc+1) - c[0] = 1 - - for i in range(1,nc+1): - c[i] = c[i-1] - - j = i-1 - while j >= 1: - c[j] = c[j-1] ^ prod(c[j],alog[i],log,alog,gf) - j = j - 1 - - c[0] = prod(c[0],alog[i],log,alog,gf) - - return c - -# "ReedSolomon(wd,nd,nc)" takes "nd" data codeword values in wd[] -# and adds on "nc" check codewords, all within GF(gf) where "gf" is a -# power of 2 and "pp" is the value of its prime modulus polynomial */ -def reed_solomon(data, nd, nc): - #parameters of the polynomial arithmetic - gf = 256 #operating on 8-bit codewords -> Galois field = 2^8 = 256 - pp = 301 #prime modulus polynomial for ECC-200 is 0b100101101 = 301 (ISO 16022:2006 5.7.1) - - log, alog = gen_log_alog(gf,pp) - c = gen_poly_coeffs(nc, log, alog, gf) - - for block in data: #for each block of data codewords - - block.extend( [0]*(nc+1) ) #extend to make space for the error codewords - - #generate "nc" checkwords in the list block - for i in range(0, nd): - k = block[nd] ^ block[i] - - for j in range(0,nc): - block[nd+j] = block[nd+j+1] ^ prod(k,c[nc-j-1],log, alog,gf) - - block.pop() - - return data - -#MODULE PLACEMENT ROUTINES=========================================== -# These routines take a steam of codewords, and place them into the -# DataMatrix in accordance with Annex F of BS ISO/IEC 16022:2006 - -# bit() returns the bit'th bit of the byte -def bit(byte, bit): - #the MSB is bit 1, LSB is bit 8 - return ( byte >> (8-bit) ) %2 - -# "module" places a given bit with appropriate wrapping within array -def module(array, nrow, ncol, row, col, bit) : - if (row < 0) : - row = row + nrow - col = col + 4 - ((nrow+4)%8) - - if (col < 0): - col = col + ncol - row = row + 4 - ((ncol+4)%8) - - array[row][col] = bit - -def corner1(array, nrow, ncol, char): - module(array, nrow, ncol, nrow-1, 0, bit(char,1)); - module(array, nrow, ncol, nrow-1, 1, bit(char,2)); - module(array, nrow, ncol, nrow-1, 2, bit(char,3)); - module(array, nrow, ncol, 0, ncol-2, bit(char,4)); - module(array, nrow, ncol, 0, ncol-1, bit(char,5)); - module(array, nrow, ncol, 1, ncol-1, bit(char,6)); - module(array, nrow, ncol, 2, ncol-1, bit(char,7)); - module(array, nrow, ncol, 3, ncol-1, bit(char,8)); - -def corner2(array, nrow, ncol, char): - module(array, nrow, ncol, nrow-3, 0, bit(char,1)); - module(array, nrow, ncol, nrow-2, 0, bit(char,2)); - module(array, nrow, ncol, nrow-1, 0, bit(char,3)); - module(array, nrow, ncol, 0, ncol-4, bit(char,4)); - module(array, nrow, ncol, 0, ncol-3, bit(char,5)); - module(array, nrow, ncol, 0, ncol-2, bit(char,6)); - module(array, nrow, ncol, 0, ncol-1, bit(char,7)); - module(array, nrow, ncol, 1, ncol-1, bit(char,8)); - -def corner3(array, nrow, ncol, char): - module(array, nrow, ncol, nrow-3, 0, bit(char,1)); - module(array, nrow, ncol, nrow-2, 0, bit(char,2)); - module(array, nrow, ncol, nrow-1, 0, bit(char,3)); - module(array, nrow, ncol, 0, ncol-2, bit(char,4)); - module(array, nrow, ncol, 0, ncol-1, bit(char,5)); - module(array, nrow, ncol, 1, ncol-1, bit(char,6)); - module(array, nrow, ncol, 2, ncol-1, bit(char,7)); - module(array, nrow, ncol, 3, ncol-1, bit(char,8)); - -def corner4(array, nrow, ncol, char): - module(array, nrow, ncol, nrow-1, 0, bit(char,1)); - module(array, nrow, ncol, nrow-1, ncol-1, bit(char,2)); - module(array, nrow, ncol, 0, ncol-3, bit(char,3)); - module(array, nrow, ncol, 0, ncol-2, bit(char,4)); - module(array, nrow, ncol, 0, ncol-1, bit(char,5)); - module(array, nrow, ncol, 1, ncol-3, bit(char,6)); - module(array, nrow, ncol, 1, ncol-2, bit(char,7)); - module(array, nrow, ncol, 1, ncol-1, bit(char,8)); - -#"utah" places the 8 bits of a utah-shaped symbol character in ECC200 -def utah(array, nrow, ncol, row, col, char): - module(array, nrow, ncol,row-2, col-2, bit(char,1)) - module(array, nrow, ncol,row-2, col-1, bit(char,2)) - module(array, nrow, ncol,row-1, col-2, bit(char,3)) - module(array, nrow, ncol,row-1, col-1, bit(char,4)) - module(array, nrow, ncol,row-1, col, bit(char,5)) - module(array, nrow, ncol,row, col-2, bit(char,6)) - module(array, nrow, ncol,row, col-1, bit(char,7)) - module(array, nrow, ncol,row, col, bit(char,8)) - -#"place_bits" fills an nrow x ncol array with the bits from the -# codewords in data. -def place_bits(data, (nrow, ncol)): -# First, fill the array[] with invalid entries */ - INVALID = 2 - array = [[INVALID] * ncol for i in xrange(nrow)] #initialise and fill with -1's (invalid value) -# Starting in the correct location for character #1, bit 8,... - char = 0 - row = 4 - col = 0 - while True: - - #first check for one of the special corner cases, then... - if ((row == nrow) and (col == 0)): - corner1(array, nrow, ncol, data[char]) - char = char + 1 - if ((row == nrow-2) and (col == 0) and (ncol%4)) : - corner2(array, nrow, ncol, data[char]) - char = char + 1 - if ((row == nrow-2) and (col == 0) and (ncol%8 == 4)): - corner3(array, nrow, ncol, data[char]) - char = char + 1 - if ((row == nrow+4) and (col == 2) and ((ncol%8) == 0)): - corner4(array, nrow, ncol, data[char]) - char = char + 1 - - #sweep upward diagonally, inserting successive characters,... - while True: - if ((row < nrow) and (col >= 0) and (array[row][col] == INVALID)) : - utah(array, nrow, ncol,row,col,data[char]) - char = char+1 - row = row - 2 - col = col + 2 - - if not((row >= 0) and (col < ncol)): - break - - row = row + 1 - col = col + 3 - - # & then sweep downward diagonally, inserting successive characters,... - while True: - if ((row >= 0) and (col < ncol) and (array[row][col] == INVALID)) : - utah(array, nrow, ncol,row,col,data[char]) - char = char + 1 - row = row + 2 - col = col - 2 - - if not((row < nrow) and (col >= 0)): - break - - row = row + 3 - col = col + 1 - - #... until the entire array is scanned - if not((row < nrow) or (col < ncol)): - break - - # Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ - if (array[nrow-1][ncol-1] == INVALID): - array[nrow-1][ncol-2] = 0 - array[nrow-1][ncol-1] = 1 - array[nrow-2][ncol-1] = 0 - array[nrow-2][ncol-2] = 1 - - return array #return the array of 1's and 0's - - -def add_finder_pattern( array, data_nrow, data_ncol, reg_row, reg_col ): - - #get the total size of the datamatrix - nrow = (data_nrow+2) * reg_row - ncol = (data_ncol+2) * reg_col - - datamatrix = [[0] * ncol for i in xrange(nrow)] #initialise and fill with 0's - - for i in range( reg_col ): #for each column of data regions - for j in range(nrow): - datamatrix[j][i*(data_ncol+2)] = 1 #vertical black bar on left - datamatrix[j][i*(data_ncol+2)+data_ncol+1] = (j)%2 # alternating blocks - - for i in range( reg_row): # for each row of data regions - for j in range(ncol): - datamatrix[i*(data_nrow+2)+data_nrow+1][j] = 1 #horizontal black bar at bottom - datamatrix[i*(data_nrow+2)][j] = (j+1)%2 # alternating blocks - - for i in range( data_nrow*reg_row ): - for j in range( data_ncol* reg_col ): - dest_col = j + 1 + 2*(j/(data_ncol)) #offset by 1, plus two for every addition block - dest_row = i + 1 + 2*(i/(data_nrow)) - - datamatrix[dest_row][dest_col] = array[i][j] #transfer from the plain bit array - - return datamatrix - -#RENDERING ROUTINES ================================================== -# Take the array of 1's and 0's and render as a series of black -# squares. A binary 1 is a filled square -#===================================================================== - -#SVG element generation routine -def draw_SVG_square((w,h), (x,y), parent): - - style = { 'stroke' : 'none', - 'stroke-width' : '1', - 'fill' : '#000000' - } - - attribs = { - 'style' :simplestyle.formatStyle(style), - 'height' : str(h), - 'width' : str(w), - 'x' : str(x), - 'y' : str(y) - } - circ = inkex.etree.SubElement(parent, inkex.addNS('rect','svg'), attribs ) - -#turn a 2D array of 1's and 0's into a set of black squares -def render_data_matrix( module_arrays, size, spacing, parent): - - for i in range(len(module_arrays)): #for each data matrix - - height = len(module_arrays[i]) - width = len(module_arrays[i][0] ) - - for y in range(height): #loop over all the modules in the datamatrix - for x in range(width): - - if module_arrays[i][y][x] == 1: #A binary 1 is a filled square - draw_SVG_square((size,size), (x*size + i*spacing,y*size), parent) - elif module_arrays[i][y][x] != 0: #we have an invalid bit value - inkex.errormsg(_('Invalid bit value, this is a bug!')) - -class DataMatrix(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - #PARSE OPTIONS - self.OptionParser.add_option("--text", - action="store", type="string", - dest="TEXT", default='Inkscape') - self.OptionParser.add_option("--symbol", - action="store", type="string", - dest="SYMBOL", default='') - self.OptionParser.add_option("--rows", - action="store", type="int", - dest="ROWS", default=10) - self.OptionParser.add_option("--cols", - action="store", type="int", - dest="COLS", default=10) - self.OptionParser.add_option("--size", - action="store", type="int", - dest="SIZE", default=4) - - def effect(self): - - scale = self.unittouu('1px') # convert to document units - so = self.options - - rows = so.ROWS - cols = so.COLS - if (so.SYMBOL != '' and (so.SYMBOL in symbols)): - rows = symbols[so.SYMBOL][0] - cols = symbols[so.SYMBOL][1] - - if so.TEXT == '': #abort if converting blank text - inkex.errormsg(_('Please enter an input string')) - else: - - #INKSCAPE GROUP TO CONTAIN EVERYTHING - - centre = tuple(computePointInNode(list(self.view_center), self.current_layer)) #Put in in the centre of the current view - grp_transform = 'translate' + str( centre ) + ' scale(%f)' % scale - grp_name = 'DataMatrix' - 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 DATAMATRIX - encoded = encode( so.TEXT, (rows, cols) ) #get the pattern of squares - render_data_matrix( encoded, so.SIZE, cols*so.SIZE*1.5, grp ) # generate the SVG elements - -if __name__ == '__main__': - e = DataMatrix() - e.affect() - -# 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 deleted file mode 100644 index 367850e45..000000000 --- a/share/extensions/render_barcode_qrcode.inx +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>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="encoding" type="enum" _gui-text="Character encoding:"> - <item value="latin_1">Latin 1</item> - <item value="cp1250">CP 1250</item> - <item value="cp1252">CP 1252</item> - <item value="utf_8">UTF 8</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"> - <submenu _name="Barcode" /> - </submenu> - </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 deleted file mode 100755 index 062488ca1..000000000 --- a/share/extensions/render_barcode_qrcode.py +++ /dev/null @@ -1,1076 +0,0 @@ -#!/usr/bin/env python - -import math, sys -import inkex -from simpletransform import computePointInNode - -#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("--encoding", - action="store", type="string", - dest="input_encode", default="latin_1") - self.OptionParser.add_option("--modulesize", - action="store", type="float", - dest="MODULESIZE", default=10) - - def effect(self): - - scale = self.unittouu('1px') # convert to document units - so = self.options - - if so.TEXT == '': #abort if converting blank text - inkex.errormsg(_('Please enter an input text')) - else: - - #INKSCAPE GROUP TO CONTAIN EVERYTHING - - so.TEXT = unicode(so.TEXT, so.input_encode) - centre = tuple(computePointInNode(list(self.view_center), self.current_layer)) #Put in in the centre of the current view - grp_transform = 'translate' + str( centre ) + ' scale(%f)' % scale - 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/render_gear_rack.inx b/share/extensions/render_gear_rack.inx deleted file mode 100644 index 9da3e36e4..000000000 --- a/share/extensions/render_gear_rack.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Rack Gear</_name> - <id>org.bg.filter.rackgear</id> - <dependency type="executable" location="extensions">render_gear_rack.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="length" type="float" min="0.1" max="3000.0" _gui-text="Rack Length:">100.</param> - <param name="spacing" type="float" min="0.01" max="100.0" _gui-text="Tooth Spacing:">10.0</param> - <param name="angle" type="float" min="-45.0" max="45.0" _gui-text="Contact Angle:">20.0</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Gear" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_gear_rack.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/render_gear_rack.py b/share/extensions/render_gear_rack.py deleted file mode 100755 index 95076ba64..000000000 --- a/share/extensions/render_gear_rack.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2013 Brett Graham (hahahaha @ hahaha.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle -from simpletransform import computePointInNode -from math import * - - -def involute_intersect_angle(Rb, R): - Rb, R = float(Rb), float(R) - return (sqrt(R**2 - Rb**2) / (Rb)) - (acos(Rb / R)) - - -def point_on_circle(radius, angle): - x = radius * cos(angle) - y = radius * sin(angle) - return (x, y) - - -def points_to_svgd(p): - """ - p: list of 2 tuples (x, y coordinates) - """ - f = p[0] - p = p[1:] - svgd = 'M%.3f,%.3f' % f - for x in p: - svgd += 'L%.3f,%.3f' % x - return svgd - - -class RackGear(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option( - "-l", "--length", - action="store", type="float", - dest="length", default=100., - help="Rack Length") - self.OptionParser.add_option( - "-s", "--spacing", - action="store", type="float", - dest="spacing", default=10., - help="Tooth Spacing") - self.OptionParser.add_option( - "-a", "--angle", - action="store", type="float", - dest="angle", default=20., - help="Contact Angle") - - def effect(self): - length = self.unittouu(str(self.options.length) + 'px') - spacing = self.unittouu(str(self.options.spacing) + 'px') - angle = radians(self.options.angle) - - # generate points: list of (x, y) pairs - points = [] - x = 0 - tas = tan(angle) * spacing - while x < length: - # move along path, generating the next 'tooth' - points.append((x, 0)) - points.append((x + tas, spacing)) - points.append((x + spacing, spacing)) - points.append((x + spacing + tas, 0)) - x += spacing * 2. - - path = points_to_svgd(points) - - # Embed gear in group to make animation easier: - # Translate group, Rotate path. - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str(view_center[0]) + ',' + \ - str(view_center[1]) + ')' - g_attribs = { - inkex.addNS('label', 'inkscape'): 'RackGear' + str(length), - 'transform': t} - g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - # Create SVG Path for gear - style = {'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.unittouu('1px'))} - gear_attribs = { - 'style': simplestyle.formatStyle(style), - 'd': path} - gear = inkex.etree.SubElement( - g, inkex.addNS('path', 'svg'), gear_attribs) - -if __name__ == '__main__': - e = RackGear() - e.affect() diff --git a/share/extensions/render_gears.inx b/share/extensions/render_gears.inx deleted file mode 100644 index 13a3afd40..000000000 --- a/share/extensions/render_gears.inx +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Gear</_name> - <id>org.ekips.filter.gears</id> - <dependency type="executable" location="extensions">render_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 (tooth size):">20.0</param> - <param name="angle" type="float" min="10.0" max="30.0" _gui-text="Pressure angle (degrees):">20.0</param> - <param name="centerdiameter" type="float" min="0.0" max="1000.0" _gui-text="Diameter of center hole (0 for none):">20.0</param> - <param name="unit" _gui-text="Units:" type="optiongroup" appearance="minimal"> - <_option value="px">px</_option> - <_option value="in">in</_option> - <_option value="mm">mm</_option> - </param> - <_param name="unit_text" type="description">Unit of measurement for both circular pitch and center diameter.</_param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"> - <submenu _name="Gear"/> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">render_gears.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/render_gears.py b/share/extensions/render_gears.py deleted file mode 100755 index fbec5d052..000000000 --- a/share/extensions/render_gears.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 Aaron Spike (aaron @ ekips.org) -Copyright (C) 2007 Tavmjong Bah (tavmjong @ free.fr) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle, sys -from simpletransform import computePointInNode -from math import * -import string - -def involute_intersect_angle(Rb, R): - Rb, R = float(Rb), float(R) - return (sqrt(R**2 - Rb**2) / (Rb)) - (acos(Rb / R)) - -def point_on_circle(radius, angle): - x = radius * cos(angle) - y = radius * sin(angle) - return (x, y) - -def points_to_svgd(p): - f = p[0] - p = p[1:] - svgd = 'M%.5f,%.5f' % f - for x in p: - svgd += ' L%.5f,%.5f' % x - svgd += 'z' - return svgd - -class Gears(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-t", "--teeth", - action="store", type="int", - dest="teeth", default=24, - help="Number of teeth") - self.OptionParser.add_option("-p", "--pitch", - action="store", type="float", - dest="pitch", default=20.0, - help="Circular Pitch (length of arc from one tooth to next)") - self.OptionParser.add_option("-a", "--angle", - action="store", type="float", - dest="angle", default=20.0, - help="Pressure Angle (common values: 14.5, 20, 25 degrees)") - self.OptionParser.add_option("-c", "--centerdiameter", - action="store", type="float", - dest="centerdiameter", default=10.0, - help="Diameter of central hole - 0.0 for no hole") - self.OptionParser.add_option("-u", "--unit", - action="store", type="string", - dest="unit", default="px", - help="unit of measure for circular pitch and center diameter") - def effect(self): - - teeth = self.options.teeth - pitch = self.unittouu( str(self.options.pitch) + self.options.unit) - angle = self.options.angle # Angle of tangent to tooth at circular pitch wrt radial line. - centerdiameter = self.unittouu( str(self.options.centerdiameter) + self.options.unit) - - # print >>sys.stderr, "Teeth: %s\n" % teeth - - two_pi = 2.0 * pi - - # Pitch (circular pitch): Length of the arc from one tooth to the next) - # Pitch diameter: Diameter of pitch circle. - pitch_diameter = float( teeth ) * pitch / pi - pitch_radius = pitch_diameter / 2.0 - - # Base Circle - base_diameter = pitch_diameter * cos( radians( angle ) ) - base_radius = base_diameter / 2.0 - - # Diametrial pitch: Number of teeth per unit length. - pitch_diametrial = float( teeth )/ pitch_diameter - - # Addendum: Radial distance from pitch circle to outside circle. - addendum = 1.0 / pitch_diametrial - - # Outer Circle - outer_radius = pitch_radius + addendum - outer_diameter = outer_radius * 2.0 - - # Tooth thickness: Tooth width along pitch circle. - tooth = ( pi * pitch_diameter ) / ( 2.0 * float( teeth ) ) - - # Undercut? - undercut = (2.0 / ( sin( radians( angle ) ) ** 2)) - needs_undercut = teeth < undercut - - - # Clearance: Radial distance between top of tooth on one gear to bottom of gap on another. - clearance = 0.0 - - # Dedendum: Radial distance from pitch circle to root diameter. - dedendum = addendum + clearance - - # Root diameter: Diameter of bottom of tooth spaces. - root_radius = pitch_radius - dedendum - root_diameter = root_radius * 2.0 - - half_thick_angle = two_pi / (4.0 * float( teeth ) ) - pitch_to_base_angle = involute_intersect_angle( base_radius, pitch_radius ) - pitch_to_outer_angle = involute_intersect_angle( base_radius, outer_radius ) - pitch_to_base_angle - - centers = [(x * two_pi / float( teeth) ) for x in range( teeth ) ] - - points = [] - - for c in centers: - - # Angles - pitch1 = c - half_thick_angle - base1 = pitch1 - pitch_to_base_angle - outer1 = pitch1 + pitch_to_outer_angle - - pitch2 = c + half_thick_angle - base2 = pitch2 + pitch_to_base_angle - outer2 = pitch2 - pitch_to_outer_angle - - # Points - b1 = point_on_circle( base_radius, base1 ) - p1 = point_on_circle( pitch_radius, pitch1 ) - o1 = point_on_circle( outer_radius, outer1 ) - - b2 = point_on_circle( base_radius, base2 ) - p2 = point_on_circle( pitch_radius, pitch2 ) - o2 = point_on_circle( outer_radius, outer2 ) - - if root_radius > base_radius: - pitch_to_root_angle = pitch_to_base_angle - involute_intersect_angle(base_radius, root_radius ) - root1 = pitch1 - pitch_to_root_angle - root2 = pitch2 + pitch_to_root_angle - r1 = point_on_circle(root_radius, root1) - r2 = point_on_circle(root_radius, root2) - p_tmp = [r1,p1,o1,o2,p2,r2] - else: - r1 = point_on_circle(root_radius, base1) - r2 = point_on_circle(root_radius, base2) - p_tmp = [r1,b1,p1,o1,o2,p2,b2,r2] - - points.extend( p_tmp ) - - path = points_to_svgd( points ) - - # Embed gear in group to make animation easier: - # Translate group, Rotate path. - view_center = computePointInNode(list(self.view_center), self.current_layer) - t = 'translate(' + str( view_center[0] ) + ',' + str( view_center[1] ) + ')' - g_attribs = {inkex.addNS('label','inkscape'):'Gear' + str( teeth ), - 'transform':t } - g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs) - - # Create SVG Path for gear - style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.unittouu('1px')) } - gear_attribs = {'style':simplestyle.formatStyle(style), 'd':path} - gear = inkex.etree.SubElement(g, inkex.addNS('path','svg'), gear_attribs ) - if(centerdiameter > 0.0): - center_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('cx','sodipodi') :'0.0', - inkex.addNS('cy','sodipodi') :'0.0', - inkex.addNS('rx','sodipodi') :str(centerdiameter/2), - inkex.addNS('ry','sodipodi') :str(centerdiameter/2), - inkex.addNS('type','sodipodi') :'arc' - } - center = inkex.etree.SubElement(g, inkex.addNS('path','svg'), center_attribs ) - -if __name__ == '__main__': - e = Gears() - 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 deleted file mode 100644 index 265acdb0b..000000000 --- a/share/extensions/replace_font.inx +++ /dev/null @@ -1,38 +0,0 @@ -<?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 font: "></param> - <param name="fr_replace" type="string" _gui-text="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 deleted file mode 100755 index 06d8a8661..000000000 --- a/share/extensions/replace_font.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/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. -''' -# standard library -import os -import sys -# local library -import inkex -import simplestyle - -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 deleted file mode 100644 index e14d2d5d5..000000000 --- a/share/extensions/restack.inx +++ /dev/null @@ -1,60 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Restack</_name> - <id>org.inkscape.filter.restack</id> - <dependency type="executable" location="extensions">restack.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="tab" type="notebook"> - <page name="positional" _gui-text="Based on Position"> - <_param name="desc_dir" type="description" appearance="header">Restack Direction</_param> - <param name="nb_direction" type="notebook"> - <page name="presets" _gui-text="Presets"> - <param name="direction" type="enum" gui-text=""> - <_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> - </param> - </page> - <page name="custom" _gui-text="Custom"> - <param name="angle" type="float" min="0.0" max="360.0" _gui-text="Angle:">0.00</param> - </page> - </param> - <_param name="desc_ref" type="description" appearance="header">Object Reference Point</_param> - <param name="xanchor" type="enum" _gui-text="Horizontal:"> - <_item value="l">Left</_item> - <_item value="m">Middle</_item> - <_item value="r">Right</_item> - </param> - <param name="yanchor" type="enum" _gui-text="Vertical:"> - <_item value="t">Top</_item> - <_item value="m">Middle</_item> - <_item value="b">Bottom</_item> - </param> - </page> - <page name="z_order" _gui-text="Based on Z-Order"> - <_param name="desc_zsort" type="description" appearance="header">Restack Mode</_param> - <param name="zsort" type="enum" gui-text=""> - <_item value="rev">Reverse Z-Order</_item> - <_item value="rand">Shuffle Z-Order</_item> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="desc_help" type="description">This extension changes the z-order of objects based on their position on the canvas or their current z-order. - -Selection: -The extension restacks either objects inside a single selected group, or a selection of multiple objects on the current drawing level (layer or group).</_param> - </page> - </param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Arrange"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">restack.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/restack.py b/share/extensions/restack.py deleted file mode 100755 index d38e18b52..000000000 --- a/share/extensions/restack.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -""" -Copyright (C) 2007-2011 Rob Antonishen; rob.antonishen@gmail.com - -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. - -""" -import inkex, os, csv, math, random -from pathmodifier import zSort - - -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False - -class Restack(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-d", "--direction", - action="store", type="string", - dest="direction", default="tb", - help="direction to restack") - self.OptionParser.add_option("-a", "--angle", - action="store", type="float", - dest="angle", default=0.0, - help="arbitrary angle") - self.OptionParser.add_option("-x", "--xanchor", - action="store", type="string", - dest="xanchor", default="m", - help="horizontal point to compare") - self.OptionParser.add_option("-y", "--yanchor", - action="store", type="string", - dest="yanchor", default="m", - help="vertical point to compare") - self.OptionParser.add_option("--zsort", - action="store", type="string", - dest="zsort", default="rev", - help="Restack mode based on Z-Order") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", - help="The selected UI-tab when OK was pressed") - self.OptionParser.add_option("--nb_direction", - action="store", type="string", - dest="nb_direction", - help="The selected UI-tab when OK was pressed") - - def effect(self): - if self.options.tab == '"help"': - pass - elif len(self.selected) > 0: - if self.options.tab == '"positional"': - self.restack_positional() - elif self.options.tab == '"z_order"': - self.restack_z_order() - else: - inkex.errormsg(_("There is no selection to restack.")) - - def restack_positional(self): - objects = {} - objlist = [] - file = self.args[ -1 ] - - if self.options.nb_direction == '"custom"': - self.options.direction = "aa" - - # process selection to get list of objects to be arranged - firstobject = self.selected[self.options.ids[0]] - if len(self.selected) == 1 and firstobject.tag == inkex.addNS('g', 'svg'): - parentnode = firstobject - for child in parentnode.iterchildren(): - objects[child.get('id')] = child - else: - parentnode = self.current_layer - objects = self.selected - - #get all bounding boxes in file by calling inkscape again with the --query-all command line option - #it returns a comma separated list structured id,x,y,w,h - if bsubprocess: - p = Popen('inkscape --query-all "%s"' % (file), shell=True, stdout=PIPE, stderr=PIPE) - err = p.stderr - f = p.communicate()[0] - try: - reader=csv.CSVParser().parse_string(f) #there was a module cvs.py in earlier inkscape that behaved differently - except: - reader=csv.reader(f.split( os.linesep )) - err.close() - else: - _,f,err = os.popen3('inkscape --query-all "%s"' % ( file ) ) - reader=csv.reader( f ) - err.close() - - #build a dictionary with id as the key - dimen = dict() - for line in reader: - if len(line) > 0: - dimen[line[0]] = map( float, line[1:]) - - if not bsubprocess: #close file if opened using os.popen3 - f.close - - #find the center of all selected objects **Not the average! - x,y,w,h = dimen[objects.keys()[0]] - minx = x - miny = y - maxx = x + w - maxy = y + h - - for id, node in objects.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - if x < minx: - minx = x - if (x + w) > maxx: - maxx = x + w - if y < miny: - miny = y - if (y + h) > maxy: - maxy = y + h - - midx = (minx + maxx) / 2 - midy = (miny + maxy) / 2 - - #calculate distances for each selected object - for id, node in objects.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - - # calc the comparison coords - if self.options.xanchor == "l": - cx = x - elif self.options.xanchor == "r": - cx = x + w - else: # middle - cx = x + w / 2 - - if self.options.yanchor == "t": - cy = y - elif self.options.yanchor == "b": - cy = y + h - else: # middle - cy = y + h / 2 - - #direction chosen - if self.options.direction == "tb" or (self.options.direction == "aa" and self.options.angle == 270): - objlist.append([cy,id]) - elif self.options.direction == "bt" or (self.options.direction == "aa" and self.options.angle == 90): - objlist.append([-cy,id]) - elif self.options.direction == "lr" or (self.options.direction == "aa" and (self.options.angle == 0 or self.options.angle == 360)): - objlist.append([cx,id]) - elif self.options.direction == "rl" or (self.options.direction == "aa" and self.options.angle == 180): - objlist.append([-cx,id]) - elif self.options.direction == "aa": - distance = math.hypot(cx,cy)*(math.cos(math.radians(-self.options.angle)-math.atan2(cy, cx))) - objlist.append([distance,id]) - elif self.options.direction == "ro": - distance = math.hypot(midx - cx, midy - cy) - objlist.append([distance,id]) - elif self.options.direction == "ri": - distance = -math.hypot(midx - cx, midy - cy) - objlist.append([distance,id]) - - objlist.sort() - #move them to the top of the object stack in this order. - for item in objlist: - parentnode.append( objects[item[1]]) - - def restack_z_order(self): - parentnode = None - objects = [] - if len(self.selected) == 1: - firstobject = self.selected[self.options.ids[0]] - if firstobject.tag == inkex.addNS('g', 'svg'): - parentnode = firstobject - for child in parentnode.iterchildren(reversed=False): - objects.append(child) - else: - parentnode = self.current_layer - for id_ in zSort(self.document.getroot(), self.selected.keys()): - objects.append(self.selected[id_]) - if self.options.zsort == "rev": - objects.reverse() - elif self.options.zsort == "rand": - random.shuffle(objects) - if parentnode is not None: - for item in objects: - parentnode.append(item) - - -if __name__ == '__main__': - e = Restack() - e.affect() - - -# 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 deleted file mode 100644 index 8f6baee7d..000000000 --- a/share/extensions/rtree.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Random Tree</_name> - <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="pentoggle" type="boolean" _gui-text="Omit redundant segments" _gui-description="Lift pen for backward steps">false</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">rtree.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/rtree.py b/share/extensions/rtree.py deleted file mode 100755 index b336c4e3a..000000000 --- a/share/extensions/rtree.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2005 Aaron Spike, aaron@ekips.org -Copyright (C) 2015 su_v, suv-sf@users.sf.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 -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplestyle, pturtle, random -from simpletransform import computePointInNode - -def rtree(turtle, size, min, pt=False): - if size < min: - return - turtle.fd(size) - turn = random.uniform(20, 40) - turtle.lt(turn) - rtree(turtle, size*random.uniform(0.5,0.9), min, pt) - turtle.rt(turn) - turn = random.uniform(20, 40) - turtle.rt(turn) - rtree(turtle, size*random.uniform(0.5,0.9), min, pt) - turtle.lt(turn) - if pt: - turtle.pu() - turtle.bk(size) - if pt: - turtle.pd() - -class RTreeTurtle(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--size", - action="store", type="float", - dest="size", default=100.0, - help="initial branch size") - self.OptionParser.add_option("-m", "--minimum", - action="store", type="float", - dest="minimum", default=4.0, - help="minimum branch size") - self.OptionParser.add_option("--pentoggle", - action="store", type="inkbool", - dest="pentoggle", default=False, - help="Lift pen for backward steps") - def effect(self): - self.options.size = self.unittouu(str(self.options.size) + 'px') - self.options.minimum = self.unittouu(str(self.options.minimum) + 'px') - s = {'stroke-linejoin': 'miter', 'stroke-width': str(self.unittouu('1px')), - 'stroke-opacity': '1.0', 'fill-opacity': '1.0', - 'stroke': '#000000', 'stroke-linecap': 'butt', - 'fill': 'none'} - t = pturtle.pTurtle() - t.pu() - t.setpos(computePointInNode(list(self.view_center), self.current_layer)) - t.pd() - rtree(t, self.options.size, self.options.minimum, self.options.pentoggle) - - attribs = {'d':t.getPath(),'style':simplestyle.formatStyle(s)} - inkex.etree.SubElement(self.current_layer, inkex.addNS('path','svg'), attribs) - -if __name__ == '__main__': - e = RTreeTurtle() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/rubberstretch.inx b/share/extensions/rubberstretch.inx deleted file mode 100644 index e23d8dfee..000000000 --- a/share/extensions/rubberstretch.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Rubber Stretch</_name> - <id>math.univ-lille1.barraud.spherify</id> - <dependency type="executable" location="extensions">pathmodifier.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="ratio" type="float" _gui-text="Strength (%):" min="-400" max="400">25</param> - <param name="curve" type="float" _gui-text="Curve (%):" min="-400" max="400">25</param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">rubberstretch.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/rubberstretch.py b/share/extensions/rubberstretch.py deleted file mode 100755 index 2e6b85ad5..000000000 --- a/share/extensions/rubberstretch.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -barraud@math.univ-lille1.fr - -''' - -import inkex, cubicsuperpath, bezmisc, pathmodifier -import copy, math, re - -class RubberStretch(pathmodifier.Diffeo): - def __init__(self): - pathmodifier.Diffeo.__init__(self) - self.OptionParser.add_option("-r", "--ratio", - action="store", type="float", - dest="ratio", default=0.5) - self.OptionParser.add_option("-c", "--curve", - action="store", type="float", - dest="curve", default=0.5) - - def applyDiffeo(self,bpt,vects=()): - for v in vects: - v[0]-=bpt[0] - v[1]-=bpt[1] - v[1]*=-1 - bpt[1]*=-1 - a=self.options.ratio/100 - b=min(self.options.curve/100,0.99) - x0= (self.bbox[0]+self.bbox[1])/2 - y0=-(self.bbox[2]+self.bbox[3])/2 - w,h=(self.bbox[1]-self.bbox[0])/2,(self.bbox[3]-self.bbox[2])/2 - - x,y=(bpt[0]-x0),(bpt[1]-y0) - sx=(1+b*(x/w+1)*(x/w-1))*2**(-a) - sy=(1+b*(y/h+1)*(y/h-1))*2**(-a) - bpt[0]=x0+x*sy - bpt[1]=y0+y/sx - for v in vects: - dx,dy=v - dXdx=sy - dXdy= x*2*b*y/h/h*2**(-a) - dYdx=-y*2*b*x/w/w*2**(-a)/sx/sx - dYdy=1/sx - v[0]=dXdx*dx+dXdy*dy - v[1]=dYdx*dx+dYdy*dy - - #--spherify - #s=((x*x+y*y)/(w*w+h*h))**(-a/2) - #bpt[0]=x0+s*x - #bpt[1]=y0+s*y - #for v in vects: - # dx,dy=v - # v[0]=(1-a/2/(x*x+y*y)*2*x*x)*s*dx+( -a/2/(x*x+y*y)*2*y*x)*s*dy - # v[1]=( -a/2/(x*x+y*y)*2*x*y)*s*dx+(1-a/2/(x*x+y*y)*2*y*y)*s*dy - - for v in vects: - v[0]+=bpt[0] - v[1]+=bpt[1] - v[1]*=-1 - bpt[1]*=-1 - -if __name__ == '__main__': - e = RubberStretch() - e.affect() - - -# 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 deleted file mode 100755 index b36b61203..000000000 --- a/share/extensions/run_command.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python -import os -import sys -import tempfile - -""" -run_command.py -Module for running SVG-generating commands in Inkscape extensions - -Copyright (C) 2008 Stephen Silver - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -# Run a command that generates an SVG (or PDF) file from an input file. -# On success, outputs the contents of the resulting file to stdout, and exits -# with a return code of 0. -# On failure, outputs an error message to stderr, and exits with a return -# code of 1. -def run(command_format, prog_name): - svgfile = tempfile.mktemp(".svg") - command = command_format % svgfile - msg = None - # ps2pdf may attempt to write to the current directory, which may not - # be writeable, so we switch to the temp directory first. - try: - os.chdir(tempfile.gettempdir()) - except Exception: - pass - # In order to get a return code from the process, we use subprocess.Popen - # if it's available (Python 2.4 onwards) and otherwise use popen2.Popen3 - # (Unix only). As the Inkscape package for Windows includes Python 2.5, - # this should cover all supported platforms. - try: - try: - from subprocess import Popen, PIPE - p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - out = p.stdout.read() - err = p.stderr.read() - except ImportError: - try: - from popen2 import Popen3 - p = Popen3(command, True) - p.wait() - rc = p.poll() - out = p.fromchild.read() - err = p.childerr.read() - except ImportError: - # shouldn't happen... - msg = "Neither subprocess.Popen nor popen2.Popen3 is available" - if msg is None: - if rc: - msg = "%s failed:\n%s\n%s\n" % (prog_name, out, err) - elif err: - sys.stderr.write("%s executed but logged the following error:\n%s\n%s\n" % (prog_name, out, err)) - except Exception, inst: - msg = "Error attempting to run %s: %s" % (prog_name, str(inst)) - - # If successful, copy the output file to stdout. - if msg is None: - if os.name == 'nt': # make stdout work in binary on Windows - import msvcrt - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - try: - f = open(svgfile, "rb") - data = f.read() - sys.stdout.write(data) - f.close() - except IOError, inst: - msg = "Error reading temporary file: %s" % str(inst) - - # Clean up. - try: - os.remove(svgfile) - except Exception: - pass - - # Output error message (if any) and exit. - if msg is not None: - sys.stderr.write(msg + "\n") - sys.exit(1) - else: - sys.exit(0) - - -# 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 deleted file mode 100755 index 3d3f35bdb..000000000 --- a/share/extensions/scour.inkscape.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import platform -import sys - -from distutils.version import StrictVersion - -import inkex - -try: - import scour - try: - from scour.scour import scourString - except ImportError: # compatibility for very old Scour (<= 0.26) - deprecated! - try: - from scour import scourString - scour.__version__ = scour.VER - except: - raise -except Exception as e: - inkex.errormsg("Failed to import Python module 'scour'.\nPlease make sure it is installed (e.g. using 'pip install scour' or 'sudo apt-get install python-scour') and try again.") - inkex.errormsg("\nDetails:\n" + str(e)) - sys.exit() - -try: - import six -except Exception as e: - inkex.errormsg("Failed to import Python module 'six'.\nPlease make sure it is installed (e.g. using 'pip install six' or 'sudo apt-get install python-six') and try again.") - inkex.errormsg("\nDetails:\n" + str(e)) - sys.exit() - - -class ScourInkscape (inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - - # Scour options - self.OptionParser.add_option("--tab", type="string", action="store", dest="tab") - self.OptionParser.add_option("--simplify-colors", type="inkbool", action="store", dest="simple_colors") - self.OptionParser.add_option("--style-to-xml", type="inkbool", action="store", dest="style_to_xml") - self.OptionParser.add_option("--group-collapsing", type="inkbool", action="store", dest="group_collapse") - self.OptionParser.add_option("--create-groups", type="inkbool", action="store", dest="group_create") - self.OptionParser.add_option("--enable-id-stripping", type="inkbool", action="store", dest="strip_ids") - self.OptionParser.add_option("--shorten-ids", type="inkbool", action="store", dest="shorten_ids") - self.OptionParser.add_option("--shorten-ids-prefix", type="string", action="store", dest="shorten_ids_prefix", default="") - self.OptionParser.add_option("--embed-rasters", type="inkbool", action="store", dest="embed_rasters") - self.OptionParser.add_option("--keep-unreferenced-defs", type="inkbool", action="store", dest="keep_defs") - self.OptionParser.add_option("--keep-editor-data", type="inkbool", action="store", dest="keep_editor_data") - self.OptionParser.add_option("--remove-metadata", type="inkbool", action="store", dest="remove_metadata") - self.OptionParser.add_option("--strip-xml-prolog", type="inkbool", action="store", dest="strip_xml_prolog") - self.OptionParser.add_option("--set-precision", type=int, action="store", dest="digits") - self.OptionParser.add_option("--indent", type="string", action="store", dest="indent_type") - self.OptionParser.add_option("--nindent", type=int, action="store", dest="indent_depth") - self.OptionParser.add_option("--line-breaks", type="inkbool", action="store", dest="newlines") - self.OptionParser.add_option("--strip-xml-space", type="inkbool", action="store", dest="strip_xml_space_attribute") - self.OptionParser.add_option("--protect-ids-noninkscape", type="inkbool", action="store", dest="protect_ids_noninkscape") - self.OptionParser.add_option("--protect-ids-list", type="string", action="store", dest="protect_ids_list") - self.OptionParser.add_option("--protect-ids-prefix", type="string", action="store", dest="protect_ids_prefix") - self.OptionParser.add_option("--enable-viewboxing", type="inkbool", action="store", dest="enable_viewboxing") - self.OptionParser.add_option("--enable-comment-stripping", type="inkbool", action="store", dest="strip_comments") - self.OptionParser.add_option("--renderer-workaround", type="inkbool", action="store", dest="renderer_workaround") - - # options for internal use of the extension - self.OptionParser.add_option("--scour-version", type="string", action="store", dest="scour_version") - self.OptionParser.add_option("--scour-version-warn-old", type="inkbool", action="store", dest="scour_version_warn_old") - - def effect(self): - # version check if enabled in options - if (self.options.scour_version_warn_old): - scour_version = scour.__version__ - scour_version_min = self.options.scour_version - if (StrictVersion(scour_version) < StrictVersion(scour_version_min)): - inkex.errormsg("The extension 'Optimized SVG Output' is designed for Scour " + scour_version_min + " and later " - "but you're using the older version Scour " + scour_version + ".") - inkex.errormsg("This usually works just fine but not all options available in the UI might be supported " - "by the version of Scour installed on your system " - "(see https://github.com/scour-project/scour/blob/master/HISTORY.md for release notes of Scour).") - inkex.errormsg("Note: You can permanently disable this message on the 'About' tab of the extension window.") - del self.options.scour_version - del self.options.scour_version_warn_old - - # do the scouring - try: - input = file(self.args[0], "r") - self.options.infilename = self.args[0] - sys.stdout.write(scourString(input.read(), self.options).encode("UTF-8")) - input.close() - sys.stdout.close() - except Exception as e: - inkex.errormsg("Error during optimization.") - inkex.errormsg("\nDetails:\n" + str(e)) - inkex.errormsg("\nOS version: " + platform.platform()) - inkex.errormsg("Python version: " + sys.version) - inkex.errormsg("Scour version: " + scour.__version__) - sys.exit() - - -if __name__ == '__main__': - e = ScourInkscape() - e.affect(output=False) diff --git a/share/extensions/scour.inx b/share/extensions/scour.inx deleted file mode 100644 index 7d7555664..000000000 --- a/share/extensions/scour.inx +++ /dev/null @@ -1,121 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Optimized SVG Output</_name> - <id>org.inkscape.output.scour</id> - <dependency type="executable" location="extensions">scour.inkscape.py</dependency> - <param name="tab" type="notebook"> - <page name="Options" _gui-text="Options"> - <param _gui-text="Number of significant digits for coordinates:" - _gui-description="Specifies the number of significant digits that should be output for coordinates. Note that significant digits are *not* the number of decimals but the overall number of digits in the output. For example if a value of "3" is specified, the coordinate 3.14159 is output as 3.14 while the coordinate 123.675 is output as 124." - name="set-precision" type="int">5</param> - <param name="spacer" type="description"> </param> - <param _gui-text="Shorten color values" - _gui-description="Convert all color specifications to #RRGGBB (or #RGB where applicable) format." - name="simplify-colors" type="boolean">true</param> - <param _gui-text="Convert CSS attributes to XML attributes" - _gui-description="Convert styles from style tags and inline style="" declarations into XML attributes." - name="style-to-xml" type="boolean">true</param> - <param name="spacer" type="description"> </param> - <param _gui-text="Collapse groups" - _gui-description="Remove useless groups, promoting their contents up one level. Requires "Remove unused IDs" to be set." - name="group-collapsing" type="boolean">true</param> - <param _gui-text="Create groups for similar attributes" - _gui-description="Create groups for runs of elements having at least one attribute in common (e.g. fill-color, stroke-opacity, ...)." - name="create-groups" type="boolean">true</param> - <param name="spacer" type="description"> </param> - <param _gui-text="Keep editor data" - _gui-description="Don't remove editor-specific elements and attributes. Currently supported: Inkscape, Sodipodi and Adobe Illustrator." - name="keep-editor-data" type="boolean">false</param> - <param _gui-text="Keep unreferenced definitions" - _gui-description="Keep element definitions that are not currently used in the SVG" - name="keep-unreferenced-defs" type="boolean">false</param> - <param name="spacer" type="description"> </param> - <param _gui-text="Work around renderer bugs" - _gui-description="Works around some common renderer bugs (mainly libRSVG) at the cost of a slightly larger SVG file." - name="renderer-workaround" type="boolean">true</param> - </page> - <page name="Output" _gui-text="SVG Output"> - <_param name="SVG_doc" type="description" appearance="header">Document options</_param> - <param _gui-text="Remove the XML declaration" - _gui-description="Removes the XML declaration (which is optional but should be provided, especially if special characters are used in the document) from the file header." - name="strip-xml-prolog" type="boolean">false</param> - <param _gui-text="Remove metadata" - _gui-description="Remove metadata tags along with all the contained information, which may include license and author information, alternate versions for non-SVG-enabled browsers, etc." - name="remove-metadata" type="boolean">false</param> - <param _gui-text="Remove comments" - _gui-description="Remove all XML comments from output." - name="enable-comment-stripping" type="boolean">false</param> - <param _gui-text="Embed raster images" - _gui-description="Resolve external references to raster images and embed them as Base64-encoded data URLs." - name="embed-rasters" type="boolean">true</param> - <param _gui-text="Enable viewboxing" - _gui-description="Set page size to 100%/100% (full width and height of the display area) and introduce a viewBox specifying the drawings dimensions." - name="enable-viewboxing" type="boolean">false</param> - <param name="spacer" type="description"> </param> - <_param name="pretty_print" type="description" appearance="header">Pretty-printing</_param> - <param _gui-text="Format output with line-breaks and indentation" - _gui-description="Produce nicely formatted output including line-breaks. If you do not intend to hand-edit the SVG file you can disable this option to bring down the file size even more at the cost of clarity." - name="line-breaks" type="boolean">true</param> - <param _gui-text="Indentation characters:" - _gui-description="The type of indentation used for each level of nesting in the output. Specify "None" to disable indentation. This option has no effect if "Format output with line-breaks and indentation" is disabled." - name="indent" type="enum"> - <_item value="space">Space</_item> - <_item value="tab">Tab</_item> - <_item msgctxt="Indent" value="none">None</_item> - </param> - <param _gui-text="Depth of indentation:" - _gui-description="The depth of the chosen type of indentation. E.g. if you choose "2" every nesting level in the output will be indented by two additional spaces/tabs." - name="nindent" type="int">1</param> - <param _gui-text="Strip the "xml:space" attribute from the root SVG element" - _gui-description="This is useful if the input file specifies "xml:space='preserve'" in the root SVG element which instructs the SVG editor not to change whitespace in the document at all (and therefore overrides the options above)." - name="strip-xml-space" type="boolean">false</param> - </page> - <page name="IDs" _gui-text="IDs"> - <param _gui-text="Remove unused IDs" - _gui-description="Remove all unreferenced IDs from elements. Those are not needed for rendering." - name="enable-id-stripping" type="boolean">true</param> - <param name="spacer" type="description"> </param> - <param _gui-text="Shorten IDs" - _gui-description="Minimize the length of IDs using only lowercase letters, assigning the shortest values to the most-referenced elements. For instance, "linearGradient5621" will become "a" if it is the most used element." - name="shorten-ids" type="boolean">false</param> - <param _gui-text="Prefix shortened IDs with:" - _gui-description="Prepend shortened IDs with the specified prefix." - name="shorten-ids-prefix" type="string"></param> - <param name="spacer" type="description"> </param> - <param _gui-text="Preserve manually created IDs not ending with digits" - _gui-description="Descriptive IDs which were manually created to reference or label specific elements or groups (e.g. #arrowStart, #arrowEnd or #textLabels) will be preserved while numbered IDs (as they are generated by most SVG editors including Inkscape) will be removed/shortened." - name="protect-ids-noninkscape" type="boolean">true</param> - <param _gui-text="Preserve the following IDs:" - _gui-description="A comma-separated list of IDs that are to be preserved." - name="protect-ids-list" type="string"></param> - <param _gui-text="Preserve IDs starting with:" - _gui-description="Preserve all IDs that start with the specified prefix (e.g. specify "flag" to preserve "flag-mx", "flag-pt", etc.)." - name="protect-ids-prefix" type="string"></param> - </page> - <page name="About" _gui-text="About"> - <param name="spacer" type="description"> </param> - <_param name="about_name_desc" type="description">Optimized SVG Output is provided by</_param> - <param name="about_name" type="description" appearance="header" indent="1">Scour - An SVG Scrubber</param> - <param name="spacer" type="description"> </param> - <_param name="about_link_desc" type="description">For details please refer to</_param> - <param name="about_link" type="description" appearance="url" indent="1">https://github.com/scour-project/scour</param> - <param name="spacer" type="description"> </param> - <param name="spacer" type="description"> </param> - <param name="spacer" type="description"> </param> - <_param name="about_version_desc" type="description">This version of the extension is designed for</_param> - <param name="about_version" type="description">Scour 0.31+</param> - <param name="scour-version" type="string" gui-hidden="true">0.31</param> <!-- this parameter is checked programatically in the extension to show a warning --> - <param _gui-text="Show warnings for older versions of Scour" - name="scour-version-warn-old" type="boolean">true</param> - </page> - </param> - <output> - <extension>.svg</extension> - <mimetype>image/svg+xml</mimetype> - <_filetypename>Optimized SVG (*.svg)</_filetypename> - <_filetypetooltip>Scalable Vector Graphics</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">scour.inkscape.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/seamless_pattern.inx b/share/extensions/seamless_pattern.inx deleted file mode 100644 index 219319b85..000000000 --- a/share/extensions/seamless_pattern.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Seamless Pattern</_name> - <id>org.inkscape.render.seamless_pattern</id> - <dependency type="executable" location="extensions">seamless_pattern.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="width" _gui-text="Custom Width (px):" type="int" min="1" max="99999999">100</param> - <param name="height" _gui-text="Custom Height (px):" type="int" min="1" max="99999999">100</param> - <_param name="help-info" type="description">This extension overwrites the current document</_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">seamless_pattern.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/seamless_pattern.py b/share/extensions/seamless_pattern.py deleted file mode 100755 index db8fd8c51..000000000 --- a/share/extensions/seamless_pattern.py +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/env python - -# Written by Jabiertxof -# V.06 - -import inkex, sys, re, os -from lxml import etree - -class C(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-w", "--width", action="store", type="int", dest="desktop_width", default="100", help="Custom width") - self.OptionParser.add_option("-z", "--height", action="store", type="int", dest="desktop_height", default="100", help="Custom height") - - def effect(self): - saveout = sys.stdout - sys.stdout = sys.stderr - width = self.options.desktop_width - height = self.options.desktop_height - if height == 0 | width == 0: - return; - factor = float(width)/float(height) - path = os.path.dirname(os.path.realpath(__file__)) - self.document = etree.parse(os.path.join(path, "seamless_pattern.svg")) - root = self.document.getroot() - root.set("id", "SVGRoot") - root.set("width", str(width)) - root.set("height", str(height)) - root.set("viewBox", "0 0 " + str(width) + " " + str(height) ) - - xpathStr = '//svg:rect[@id="clipPathRect"]' - clipPathRect = root.xpath(xpathStr, namespaces=inkex.NSS) - if clipPathRect != []: - clipPathRect[0].set("width", str(width)) - clipPathRect[0].set("height", str(height)) - - xpathStr = '//svg:pattern[@id="Checkerboard"]' - designZoneData = root.xpath(xpathStr, namespaces=inkex.NSS) - if designZoneData != []: - if factor <= 1: - designZoneData[0].set("patternTransform", "scale(" + str(10.0) + "," + str(factor * 10) + ")") - else: - designZoneData[0].set("patternTransform", "scale(" + str(10.0/factor) + "," + str(10.0) + ")") - - xpathStr = '//svg:g[@id="designTop"] | //svg:g[@id="designBottom"]' - designZone = root.xpath(xpathStr, namespaces=inkex.NSS) - if designZone != []: - designZone[0].set("transform", "scale(" + str(width/100.0) + "," + str(height/100.0) + ")") - designZone[1].set("transform", "scale(" + str(width /100.0) + "," + str(height/100.0) + ")") - - xpathStr = '//svg:g[@id="designTop"]/child::*' - designZoneData = root.xpath(xpathStr, namespaces=inkex.NSS) - if designZoneData != []: - if factor <= 1: - designZoneData[0].set("transform", "scale(1," + str(factor) + ")") - designZoneData[1].set("transform", "scale(1," + str(factor) + ")") - designZoneData[2].set("transform", "scale(1," + str(factor) + ")") - else: - designZoneData[0].set("transform", "scale(" + str(1.0/factor) + ",1)") - designZoneData[1].set("transform", "scale(" + str(1.0/factor) + ",1)") - designZoneData[2].set("transform", "scale(" + str(1.0/factor) + ",1)") - - xpathStr = '//svg:g[@id="textPreview"]' - previewText = root.xpath(xpathStr, namespaces=inkex.NSS) - if previewText != []: - if factor <= 1: - previewText[0].set("transform", "translate(" + str(width * 2) + ",0) scale(" + str(width/100.0) + "," + str((height/100.0) * factor) + ")") - else: - previewText[0].set("transform", "translate(" + str(width * 2) + ",0) scale(" + str((width/100.0)/factor) + "," + str(height/100.0) + ")") - - xpathStr = '//svg:g[@id="infoGroup"]' - infoGroup = root.xpath(xpathStr, namespaces=inkex.NSS) - if infoGroup != []: - if factor <= 1: - infoGroup[0].set("transform", "scale(" + str(width/100.0) + "," + str((height/100.0) * factor) + ")") - else: - infoGroup[0].set("transform", "scale(" + str(width/1000.0) + "," + str((height/1000.0) * factor) + ")") - - xpathStr = '//svg:use[@id="top1"] | //svg:use[@id="bottom1"]' - pattern1 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern1 != []: - pattern1[0].set("transform", "translate(" + str(-width) + "," + str(-height) + ")") - pattern1[1].set("transform", "translate(" + str(-width) + "," + str(-height) + ")") - - xpathStr = '//svg:use[@id="top2"] | //svg:use[@id="bottom2"]' - pattern2 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern2 != []: - pattern2[0].set("transform", "translate(0," + str(-height) +")" ) - pattern2[1].set("transform", "translate(0," + str(-height) +")" ) - - xpathStr = '//svg:use[@id="top3"] | //svg:use[@id="bottom3"]' - pattern3 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern3 != []: - pattern3[0].set("transform", "translate(" + str(width) + "," + str(-height) + ")" ) - pattern3[1].set("transform", "translate(" + str(width) + "," + str(-height) + ")" ) - - xpathStr = '//svg:use[@id="top4"] | //svg:use[@id="bottom4"]' - pattern4 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern4 != []: - pattern4[0].set("transform", "translate(" + str(-width) + ",0)" ) - pattern4[1].set("transform", "translate(" + str(-width) + ",0)" ) - - xpathStr = '//svg:use[@id="top5"] | //svg:use[@id="bottom5"]' - pattern5 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern5 != []: - pattern5[0].set("transform", "translate(0,0)" ) - pattern5[1].set("transform", "translate(0,0)" ) - - xpathStr = '//svg:use[@id="top6"] | //svg:use[@id="bottom6"]' - pattern6 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern6 != []: - pattern6[0].set("transform", "translate(" + str(width) + ",0)" ) - pattern6[1].set("transform", "translate(" + str(width) + ",0)" ) - - xpathStr = '//svg:use[@id="top7"] | //svg:use[@id="bottom7"]' - pattern7 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern7 != []: - pattern7[0].set("transform", "translate(" + str(-width) + "," + str(height) + ")" ) - pattern7[1].set("transform", "translate(" + str(-width) + "," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="top8"] | //svg:use[@id="bottom8"]' - pattern8 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern8 != []: - pattern8[0].set("transform", "translate(0," + str(height) + ")" ) - pattern8[1].set("transform", "translate(0," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="top9"] | //svg:use[@id="bottom9"]' - pattern9 = root.xpath(xpathStr, namespaces=inkex.NSS) - if pattern9 != []: - pattern9[0].set("transform", "translate(" + str(width) + "," + str(height) + ")" ) - pattern9[1].set("transform", "translate(" + str(width) + "," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview1"]' - clonePreview1 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview1 != []: - clonePreview1[0].set("transform", "translate(0," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview2"]' - clonePreview2 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview2 != []: - clonePreview2[0].set("transform", "translate(0," + str(height * 2) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview3"]' - clonePreview3 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview3 != []: - clonePreview3[0].set("transform", "translate(" + str(width) + ",0)" ) - - xpathStr = '//svg:use[@id="clonePreview4"]' - clonePreview4 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview4 != []: - clonePreview4[0].set("transform", "translate(" + str(width) + "," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview5"]' - clonePreview5 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview5 != []: - clonePreview5[0].set("transform", "translate(" + str(width) + "," + str(height * 2) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview6"]' - clonePreview6 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview6 != []: - clonePreview6[0].set("transform", "translate(" + str(width*2) + ", 0)" ) - - xpathStr = '//svg:use[@id="clonePreview7"]' - clonePreview7 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview7 != []: - clonePreview7[0].set("transform", "translate(" + str(width*2) + "," + str(height) + ")" ) - - xpathStr = '//svg:use[@id="clonePreview8"]' - clonePreview8 = root.xpath(xpathStr, namespaces=inkex.NSS) - if clonePreview8 != []: - clonePreview8[0].set("transform", "translate(" + str(width*2) + "," + str(height*2) + ")" ) - - xpathStr = '//svg:use[@id="fullPatternClone"]' - patternGenerator = root.xpath(xpathStr, namespaces=inkex.NSS) - if patternGenerator != []: - patternGenerator[0].set("transform", "translate(" + str(width * 2) + ",-" + str(height) + ")" ) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-cx", str(width/2)) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-cy", str(height/2)) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-w", str(width)) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-h", str(height)) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-x0", str(width)) - patternGenerator[0].set("{http://www.inkscape.org/namespaces/inkscape}tile-y0", str(height)) - patternGenerator[0].set("width", str(width)) - patternGenerator[0].set("height", str(height)) - - namedview = root.find(inkex.addNS('namedview', 'sodipodi')) - if namedview is None: - namedview = inkex.etree.SubElement( root, inkex.addNS('namedview', 'sodipodi') ); - - namedview.set(inkex.addNS('document-units', 'inkscape'), 'px') - - namedview.set(inkex.addNS('cx', 'inkscape'), str((width*5.5)/2.0) ) - namedview.set(inkex.addNS('cy', 'inkscape'), "0" ) - namedview.set(inkex.addNS('zoom', 'inkscape'), str(1.0 / (width/100.00)) ) - sys.stdout = saveout - -c = C() -c.affect() diff --git a/share/extensions/seamless_pattern.svg b/share/extensions/seamless_pattern.svg deleted file mode 100644 index 5bff87af8..000000000 --- a/share/extensions/seamless_pattern.svg +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="100px" height="100px" viewBox="0 0 100 100" id="SVGRoot" version="1.1" inkscape:version="0.91+devel r14699 custom" sodipodi:docname="seamless_pattern.svg" inkscape:export-xdpi="96" inkscape:export-ydpi="96" enable-background="new"> -<defs id="defs4787"> -<linearGradient inkscape:collect="always" id="linearGradient4217"> -<stop style="stop-color:#ffffff;stop-opacity:1" offset="0" id="stop4213" /> -<stop style="stop-color:#ffffff;stop-opacity:0.21960784" offset="1" id="stop4215" /> -</linearGradient> -<clipPath clipPathUnits="userSpaceOnUse" id="patternClipPath"> -<rect y="0" x="0" height="100" width="100" id="clipPathRect" style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.09889996;stroke-opacity:1;marker:none;enable-background:accumulate" /> -</clipPath> -<marker inkscape:stockid="Arrow2Mend" orient="auto" refY="0.0" refX="0.0" id="Arrow2Mend" style="overflow:visible;" inkscape:isstock="true"> -<path id="path19572" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(0.6) rotate(180) translate(0,0)" /> -</marker> -<radialGradient inkscape:collect="always" xlink:href="#linearGradient4217" id="radialGradient4159" gradientUnits="userSpaceOnUse" cx="50" cy="50" fx="50" fy="50" r="50" /> -</defs> -<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.93166" inkscape:cx="98.45167" inkscape:cy="143.1829" inkscape:document-units="px" inkscape:current-layer="patternLayer" showgrid="false" inkscape:pagecheckerboard="true" inkscape:snap-global="false" /> -<metadata id="metadata4790"> -<rdf:RDF> -<cc:Work rdf:about=""> -<dc:format>image/svg+xml</dc:format> -<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> -<dc:title></dc:title> -</cc:Work> -</rdf:RDF> -</metadata> -<g inkscape:groupmode="layer" id="patternLayer" inkscape:label="Pattern" style="display:inline"> -<g id="g8891" sodipodi:insensitive="true"> -<use x="0" y="0" xlink:href="#fullPattern" id="fullPatternClone" transform="translate(200,-100)" width="100" height="100" inkscape:tile-cx="50" inkscape:tile-cy="50" inkscape:tile-w="100" inkscape:tile-h="100" inkscape:tile-x0="100" inkscape:tile-y0="100" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(0,100)" id="clonePreview1" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(0,200)" id="clonePreview2" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(100)" id="clonePreview3" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(100,100)" id="clonePreview4" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(100,200)" id="clonePreview5" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(200)" id="clonePreview6" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(200,100)" id="clonePreview7" /> -<use height="100%" width="100%" x="0" y="0" inkscape:tiled-clone-of="#fullPatternClone" xlink:href="#fullPatternClone" transform="translate(200,200)" id="clonePreview8" /> -</g> -<use style="opacity:0.3" height="100%" width="100%" id="phantomBottom" xlink:href="#designBottom" y="0" x="0" sodipodi:insensitive="true" /> -<use style="opacity:0.3" height="100%" width="100%" id="phantomTop" xlink:href="#designTop" y="0" x="0" sodipodi:insensitive="true" /> -<g id="infoGroup" sodipodi:insensitive="true"> -<rect style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:74.66007233;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" id="rect4130" width="526.66248" height="338.53928" x="-348.83969" y="-380.86212" /> -<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.66861534px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" x="-326.82172" y="-349.80621" id="text8664" sodipodi:linespacing="125%"><tspan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold'" sodipodi:role="line" id="tspan8666" x="-326.82172" y="-349.80621">Seamless pattern</tspan></text> -<flowRoot xml:space="preserve" id="infoText" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.75px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" transform="translate(-709.3014,-231.7039)"><flowRegion id="flowRegion11597"><rect ry="0.97061312" id="rect11599" width="491.7114" height="324.99371" x="383.75671" y="-110.4523" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.75px;font-family:sans-serif;-inkscape-font-specification:sans-serif" /></flowRegion><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara6756">Use the layers "<flowSpan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold'" id="flowSpan7476">Pattern Foreground</flowSpan>" and "<flowSpan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold'" id="flowSpan7478">Pattern Background</flowSpan>" on the pattern page to create your design. The separation into two layers will make it easier for you to create and edit overlapping content like a foreground drawing with a background fill.</flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7456" /><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7458">The layer named "<flowSpan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold'" id="flowSpan7480">Pattern</flowSpan>" is for using the seamless pattern, copying it to other documents, adding opacity etc. </flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7460">Select the group on the page, and use <flowSpan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold'" id="flowSpan7484">Object->Pattern->Objects to Pattern</flowSpan> to convert your creation into a fill pattern.</flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7462" /><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7464">The layer "<flowSpan style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold'" id="flowSpan7482">Preview Background</flowSpan>" provides an easy way to preview your creation if it contains transparency.</flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7466">Changing this layer's visibility will not alter the pattern.</flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7468" /><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7470">If an object is moved outside the pattern/page limits, it will be difficult to select it. </flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7472">To move it back onto the page, select the object using the rubberband selection (click and drag a selection box) with the selection tool.</flowPara><flowPara style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;font-family:Cantarell;-inkscape-font-specification:Cantarell" id="flowPara7474">Then move it back onto the page, using the arrow keys or the "Align and Distribute" dialog (Shift+Ctrl+A).</flowPara></flowRoot><path sodipodi:nodetypes="cccc" inkscape:connector-curvature="0" id="path19539" d="m -354.4906,-359.49 h -6.1704 V 51.51566 h 229.6052" style="color:#000000;text-decoration:none;text-decoration-line:none;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:3.77952766;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-end:url(#Arrow2Mend);enable-background:accumulate" /> -</g> -<g id="textPreview" sodipodi:insensitive="true"> -<path d="m -29.56541,100 0,-7.16704 2.00731,0 0,4.51126 1.91761,0 0,-4.24223 2.00731,0 0,4.24223 4.36647,0 0,2.65578 -10.2987,0 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9845" inkscape:connector-curvature="0" /> -<path d="m -22.7433,87.81814 q 0,0.77256 0.26214,1.16575 0.26214,0.38628 0.77256,0.38628 0.46906,0 0.73808,-0.3104 0.26214,-0.31731 0.26214,-0.87604 0,-0.6967 -0.49667,-1.17266 -0.50355,-0.47596 -1.25547,-0.47596 l -0.28278,0 0,1.28303 z m -0.93124,-3.7732 4.40783,0 0,2.49017 -1.14504,0 q 0.70359,0.49666 1.02773,1.11747 0.31735,0.62082 0.31735,1.51066 0,1.20024 -0.69671,1.95213 -0.70359,0.74498 -1.82103,0.74498 -1.35893,0 -1.99355,-0.93123 -0.63462,-0.93812 -0.63462,-2.93854 l 0,-1.45547 -0.19316,0 q -0.58628,0 -0.8553,0.46216 -0.2759,0.46217 -0.2759,1.44168 0,0.79327 0.15859,1.47617 0.15868,0.6829 0.47603,1.26923 l -1.88321,0 q -0.19317,-0.79327 -0.28966,-1.59344 -0.10355,-0.80016 -0.10355,-1.60033 0,-2.09008 0.82778,-3.01441 0.8209,-0.93123 2.67642,-0.93123 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9847" inkscape:connector-curvature="0" /> -<path d="m -26.75105,75.72598 1.87625,0 q -0.33111,0.79327 -0.49658,1.53136 -0.16556,0.73808 -0.16556,1.39338 0,0.7036 0.17932,1.04849 0.17243,0.338 0.53803,0.338 0.29663,0 0.45531,-0.25522 0.15858,-0.26212 0.23453,-0.93122 l 0.0624,-0.43458 q 0.2415,-1.89694 0.79329,-2.55225 0.55189,-0.65531 1.73142,-0.65531 1.23474,0 1.85551,0.91054 0.62086,0.91053 0.62086,2.7178 0,0.76568 -0.12419,1.58654 -0.11722,0.81396 -0.35872,1.67621 l -1.87624,0 q 0.35872,-0.73809 0.53803,-1.51067 0.17941,-0.77947 0.17941,-1.57963 0,-0.72429 -0.20005,-1.08988 -0.20004,-0.3656 -0.59325,-0.3656 -0.33111,0 -0.4897,0.25524 -0.16555,0.24832 -0.25525,1.00019 l -0.055,0.43458 q -0.20692,1.64862 -0.76568,2.31082 -0.55868,0.66221 -1.69684,0.66221 -1.22787,0 -1.82112,-0.84156 -0.59325,-0.84155 -0.59325,-2.57984 0,-0.6829 0.10355,-1.43477 0.10346,-0.75188 0.32415,-1.63483 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9849" inkscape:connector-curvature="0" /> -<path d="m -29.18596,70.67666 2.19351,0 0,-2.54535 1.7659,0 0,2.54535 3.27654,0 q 0.53804,0 0.7312,-0.21383 0.1862,-0.21384 0.1862,-0.84846 l 0,-1.26922 1.7659,0 0,2.11768 q 0,1.46237 -0.60701,2.07628 -0.61398,0.60703 -2.07629,0.60703 l -3.27654,0 0,1.22784 -1.7659,0 0,-1.22784 -2.19351,0 0,-2.46948 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9851" inkscape:connector-curvature="0" /> -<path d="m -20.38415,59.23292 4.05599,0 0,2.46948 -10.66429,0 0,-2.46948 1.13128,0 q -0.67598,-0.51044 -0.99334,-1.13127 -0.32423,-0.62081 -0.32423,-1.42788 0,-1.42787 1.13826,-2.3453 1.13119,-0.91744 2.91782,-0.91744 1.78654,0 2.92471,0.91744 1.13128,0.91743 1.13128,2.3453 0,0.80707 -0.31735,1.42788 -0.32414,0.62083 -1.00013,1.13127 z m -5.00108,-1.64171 q 0,0.79327 0.58637,1.22093 0.5794,0.42078 1.6762,0.42078 1.09671,0 1.68308,-0.42078 0.5794,-0.42766 0.5794,-1.22093 0,-0.79327 -0.5794,-1.20715 -0.5794,-0.42078 -1.68308,-0.42078 -1.10368,0 -1.68317,0.42078 -0.5794,0.41388 -0.5794,1.20715 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9853" inkscape:connector-curvature="0" /> -<path d="m -24.88856,45.83706 q -0.1518,0.3242 -0.22077,0.6484 -0.0761,0.31731 -0.0761,0.64151 0,0.95193 0.61389,1.46927 0.6071,0.51045 1.74526,0.51045 l 3.55932,0 0,2.46948 -7.72574,0 0,-2.46948 1.26923,0 q -0.7588,-0.47595 -1.10367,-1.08988 -0.35185,-0.62081 -0.35185,-1.48306 0,-0.12416 0.0138,-0.26902 0.009,-0.14486 0.0413,-0.42078 l 2.23496,-0.007 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9855" inkscape:connector-curvature="0" /> -<path d="m -23.15027,36.88348 0.7036,0 0,5.77361 q 0.86914,-0.0897 1.30372,-0.62772 0.43457,-0.53804 0.43457,-1.50375 0,-0.77948 -0.22765,-1.59344 -0.23453,-0.82086 -0.70359,-1.6831 l 1.90385,0 q 0.33111,0.87604 0.49667,1.75208 0.17243,0.87604 0.17243,1.75209 0,2.09698 -1.06231,3.26274 -1.06919,1.15886 -2.99368,1.15886 -1.89009,0 -2.97304,-1.13817 -1.08304,-1.14506 -1.08304,-3.14547 0,-1.82107 1.0968,-2.91095 1.0968,-1.09678 2.93167,-1.09678 z m -0.8209,2.53846 q -0.70359,0 -1.13119,0.41388 -0.43458,0.40698 -0.43458,1.06918 0,0.71739 0.40697,1.16576 0.40009,0.44836 1.1588,0.55873 l 0,-3.20755 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9857" inkscape:connector-curvature="0" /> -<path d="m -26.99245,35.99364 0,-2.46947 5.33907,-1.92454 -5.33907,-1.91764 0,-2.47637 7.72574,3.04201 0,2.7109 -7.72574,3.03511 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9859" inkscape:connector-curvature="0" /> -<path d="m -26.99245,25.80534 0,-2.46948 7.72574,0 0,2.46948 -7.72574,0 z m -3.00753,0 0,-2.46948 2.01419,0 0,2.46948 -2.01419,0 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9861" inkscape:connector-curvature="0" /> -<path d="m -23.15027,13.23722 0.7036,0 0,5.77361 q 0.86914,-0.0897 1.30372,-0.62772 0.43457,-0.53805 0.43457,-1.50376 0,-0.77947 -0.22765,-1.59344 -0.23453,-0.82085 -0.70359,-1.6831 l 1.90385,0 q 0.33111,0.87604 0.49667,1.75208 0.17243,0.87605 0.17243,1.75209 0,2.09698 -1.06231,3.26275 -1.06919,1.15885 -2.99368,1.15885 -1.89009,0 -2.97304,-1.13816 -1.08304,-1.14506 -1.08304,-3.14548 0,-1.82106 1.0968,-2.91094 1.0968,-1.09678 2.93167,-1.09678 z m -0.8209,2.53845 q -0.70359,0 -1.13119,0.41389 -0.43458,0.40697 -0.43458,1.06918 0,0.71738 0.40697,1.16575 0.40009,0.44837 1.1588,0.55874 l 0,-3.20756 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9863" inkscape:connector-curvature="0" /> -<path d="m -26.99245,12.06456 0,-2.400495 5.32522,-1.29682 -5.32522,-1.303718 0,-2.062494 5.2701,-1.29682 -5.2701,-1.303717 0,-2.4004958732508 L -19.26671,2.034903 l 0,2.697109 -5.31147,1.303717 5.31147,1.296819 0,2.697112 -7.72574,2.0349 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="path9865" inkscape:connector-curvature="0" /> -</g> -<g inkscape:label="Helper Layer (don't use)" clip-path="url(#patternClipPath)" id="fullPattern" style="display:inline"> -<g inkscape:groupmode="layer" id="designBottom" inkscape:label="Pattern Background"> -<rect y="0" x="0" height="100" width="100" id="rect9111" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient4159);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;enable-background:accumulate" /> -</g> -<g inkscape:groupmode="layer" id="designTop" inkscape:label="Pattern Foreground"> -<path id="path1790" d="m 84.87396,19.36488 h -4.9936 v 0.31955 h 0.14957 c 0.67301,0 0.74773,0.0342 0.74773,0.31968 v 0.197 3.23589 0.19726 c 0,0.28537 -0.0747,0.31942 -0.74773,0.31942 h -0.14957 v 0.31955 h 5.10156 l 0.16619,-1.81515 h -0.36562 c -0.10782,0.47574 -0.29915,0.89731 -0.49844,1.09457 -0.25767,0.27186 -0.73125,0.40103 -1.42912,0.40103 h -0.54844 c -0.24928,0 -0.45696,-0.0407 -0.53181,-0.10201 -0.058,-0.0405 -0.0663,-0.0815 -0.0663,-0.22416 v -1.73354 h 0.16619 c 0.50668,0 0.71449,0.0407 0.88082,0.18336 0.21578,0.177 0.29901,0.39453 0.31563,0.79542 h 0.39048 v -2.22968 h -0.39048 c -0.0416,0.66626 -0.374,0.93136 -1.16335,0.93136 h -0.19929 v -1.55005 c 0,-0.29226 0.0748,-0.33995 0.52343,-0.33995 h 0.43197 c 0.73125,0 1.08849,0.0613 1.37115,0.25172 0.27415,0.17673 0.47345,0.55735 0.59816,1.16915 h 0.35738 L 84.874,19.36488 Z m -11.02598,2.72609 h 0.93892 c 0.74787,0 1.13835,-0.0476 1.47087,-0.17659 0.58978,-0.23132 0.92216,-0.66639 0.92216,-1.20334 0,-0.51642 -0.2909,-0.91095 -0.8392,-1.13525 -0.32401,-0.13579 -0.8392,-0.21091 -1.4125,-0.21091 h -2.90809 v 0.31955 h 0.14957 c 0.67301,0 0.74773,0.0342 0.74773,0.31968 v 0.197 3.23589 0.19726 c 0,0.28537 -0.0747,0.31942 -0.74773,0.31942 h -0.14957 v 0.31955 h 2.79176 v -0.31955 h -0.21619 c -0.67301,0 -0.74773,-0.034 -0.74773,-0.31942 V 23.437 Z m 0,-0.31941 v -1.74029 c 0,-0.31266 0.05,-0.34684 0.50696,-0.34684 h 0.53181 c 0.86407,0 1.27117,0.33319 1.27117,1.05376 0,0.70031 -0.42372,1.03337 -1.30441,1.03337 z m -7.22869,-2.50167 h -0.34886 l -1.91122,3.96308 c -0.16605,0.3536 -0.19929,0.40129 -0.32387,0.50993 -0.13309,0.12917 -0.36576,0.21078 -0.59018,0.21078 h -0.0331 v 0.31955 h 2.20185 v -0.31955 h -0.16633 c -0.44845,0 -0.67288,-0.12917 -0.67288,-0.38738 0,-0.0817 0.025,-0.17673 0.0747,-0.2855 l 0.27429,-0.59829 h 2.20184 l 0.44872,0.91095 c 0.0499,0.10201 0.0665,0.14944 0.0665,0.18362 0,0.10863 -0.20794,0.1766 -0.5152,0.1766 h -0.349 v 0.31955 h 2.57584 v -0.31955 h -0.11633 c -0.41562,0 -0.50695,-0.0543 -0.69801,-0.43494 L 66.6193,19.26989 Z m -0.4071,1.11484 0.93878,1.93067 H 65.28976 Z M 60.47896,19.31745 H 60.1632 l -0.33225,0.40116 C 59.24076,19.36488 58.91702,19.263 58.36021,19.263 c -0.80596,0 -1.47073,0.26523 -2.03565,0.81569 -0.53182,0.51669 -0.7811,1.08769 -0.7811,1.78799 0,1.46168 1.17145,2.50856 2.80851,2.50856 1.3294,0 2.17685,-0.6391 2.36804,-1.78123 l -0.39049,-0.0543 c -0.0831,0.36036 -0.18294,0.60491 -0.33252,0.80894 -0.34049,0.46912 -0.8723,0.70719 -1.54545,0.70719 -1.22969,0 -1.81122,-0.70043 -1.81122,-2.16185 0,-0.7684 0.12444,-1.28495 0.40696,-1.69286 0.25767,-0.38062 0.77273,-0.61869 1.30468,-0.61869 0.58154,0 1.09673,0.25158 1.4125,0.68679 0.15782,0.22429 0.28253,0.48939 0.47372,1.01283 h 0.36521 l -0.12444,-1.96459 z m -8.31718,0.007 h -0.30739 l -0.33238,0.40791 c -0.39062,-0.3059 -0.9223,-0.46912 -1.51222,-0.46912 -1.08849,0 -1.8196,0.571 -1.8196,1.42101 0,0.74084 0.44845,1.10795 1.6699,1.36629 l 0.78934,0.16322 c 0.61491,0.12904 0.67301,0.14268 0.84758,0.25159 0.24929,0.15619 0.38224,0.38048 0.38224,0.64572 0,0.27185 -0.12471,0.49614 -0.37386,0.6799 -0.27429,0.197 -0.5483,0.27185 -1.0054,0.27185 -0.61491,0 -1.05525,-0.15646 -1.44573,-0.50993 -0.34901,-0.31968 -0.52344,-0.63909 -0.64802,-1.16253 h -0.35738 l 0.0332,1.93756 h 0.32414 l 0.37373,-0.46237 c 0.55668,0.37387 1.02229,0.50993 1.74489,0.50993 1.22144,0 2.00254,-0.58451 2.00254,-1.49573 0,-0.42143 -0.17456,-0.78165 -0.49844,-1.03999 -0.22442,-0.17673 -0.54843,-0.29239 -1.21334,-0.42831 l -0.88906,-0.18349 c -0.73935,-0.15633 -1.08835,-0.42156 -1.08835,-0.83623 0,-0.47574 0.47358,-0.80232 1.17983,-0.80232 0.58167,0 1.05511,0.20416 1.3875,0.59154 0.24105,0.27874 0.39048,0.56424 0.49871,0.91095 h 0.35725 l -0.0997,-1.76745 z m -11.23365,2.72609 v -1.84919 -0.197 c 0,-0.2855 0.0746,-0.31968 0.74773,-0.31968 h 0.15795 v -0.31955 h -2.73366 v 0.31955 h 0.14957 c 0.67301,0 0.7476,0.0342 0.7476,0.31968 v 0.197 3.23589 0.19726 c 0,0.28537 -0.0746,0.31942 -0.7476,0.31942 h -0.14957 v 0.31955 h 2.73366 v -0.31955 h -0.15795 c -0.67315,0 -0.74773,-0.0341 -0.74773,-0.31942 v -0.19726 -0.86326 l 0.96378,-0.79542 1.44574,1.73353 c 0.13309,0.16308 0.16619,0.21754 0.16619,0.28563 0,0.10864 -0.15768,0.1562 -0.56492,0.1562 h -0.25766 v 0.31955 h 2.84161 v -0.31955 h -0.15781 c -0.45696,0 -0.57343,-0.0476 -0.81434,-0.33982 l -2.01066,-2.37263 1.23806,-1.01283 c 0.39873,-0.3467 0.90555,-0.54397 1.40413,-0.54397 v -0.31955 h -2.55923 v 0.31955 h 0.20794 c 0.38225,0 0.53993,0.0613 0.53993,0.20402 0,0.0951 -0.1662,0.29226 -0.40711,0.48939 z m -9.28947,-2.68542 h -1.71165 v 0.31955 h 0.20781 c 0.42372,0 0.61491,0.0544 0.76435,0.22456 v 2.88904 c 0,0.93136 -0.16619,1.12849 -0.96378,1.15565 v 0.31955 h 2.36817 v -0.31955 c -0.78962,-0.0272 -0.95567,-0.22429 -0.95567,-1.15565 V 20.2762 l 3.70595,4.09252 h 0.34887 v -3.52827 c 0,-0.93122 0.16606,-1.12849 0.96378,-1.15578 v -0.31955 h -2.36804 v 0.31955 c 0.78935,0.0273 0.95554,0.22456 0.95554,1.15578 V 22.975 Z m -5.40071,0.83623 v -0.197 c 0,-0.2855 0.0747,-0.31968 0.73935,-0.31968 h 0.16619 v -0.31955 h -2.75014 v 0.31955 h 0.16619 c 0.67301,0 0.74773,0.0342 0.74773,0.31968 v 0.197 3.23589 0.19726 c 0,0.28537 -0.0747,0.31942 -0.74773,0.31942 h -0.16619 v 0.31955 h 2.75014 V 23.95392 H 26.9773 c -0.66463,0 -0.73935,-0.0341 -0.73935,-0.31942 v -0.19726 z" style="fill:#000000;fill-opacity:1;stroke-width:1pt" inkscape:connector-curvature="0" /> -<g id="g7535" transform="matrix(1.314547,0,0,1.314547,-17.94833,-33.3228)"> -<path id="path2313" d="M 49.37627,75.52654 34.51809,90.7309 c -5.02019,6.2169 3.41648,5.49357 7.03314,7.28421 1.29735,1.32611 -4.97263,2.30489 -3.67528,3.63219 1.29735,1.3261 7.84495,2.5548 9.14451,3.881 1.29736,1.3261 -2.65553,2.7329 -1.35818,4.059 1.29735,1.3261 4.29797,0.07 4.85982,3.1311 0.40038,2.1877 5.4073,0.9402 7.85601,-0.8516 1.29736,-1.3272 -2.48189,-1.2022 -1.18454,-2.5283 3.22624,-3.2993 6.23017,-1.199 7.33397,-4.5048 0.54527,-1.6336 -4.74922,-2.5184 -3.44965,-3.8445 3.73279,-2.17998 16.63444,-3.59899 10.51265,-9.72077 L 56.18931,75.52654 c -1.88354,-1.80833 -5.02683,-1.82824 -6.81304,0 z m 17.06689,29.30716 c 0,0.7543 5.55771,1.2487 5.55771,-0.1781 -0.7919,-2.2917 -4.90074,-2.1368 -5.55771,0.1781 z m -25.03571,4.0082 c 1.31615,1.1381 3.34901,-0.2832 3.95842,-1.8714 -1.27523,-1.6944 -6.04879,0.061 -3.95842,1.8714 z m 24.33892,-2.4587 c -1.69662,1.5219 0.19023,3.0659 1.86253,2.0826 0.37272,-0.3782 -0.01,-1.7043 -1.86253,-2.0826 z" inkscape:connector-curvature="0" /> -<path style="fill:#ffffff" id="path2315" d="m 45.82044,98.83798 c 0.39706,0.24664 6.40271,1.46662 7.87039,1.70992 0.50876,0.1073 0.1482,0.6315 -0.55301,0.9854 -1.5816,0.4203 -9.2529,-2.69532 -7.31738,-2.69532 z" inkscape:connector-curvature="0" /> -<path style="fill:#ffffff" id="path2317" d="m 55.29123,76.59274 5.87846,5.97026 c 0.55743,0.5696 0.54969,1.6734 0.23779,1.99082 l -2.91877,-2.33479 -0.57402,3.4574 -2.43876,-1.2874 -3.90533,2.46751 -1.29293,-5.20158 -2.0981,3.62994 h -3.20744 c -1.30731,0 -1.46104,-1.65902 -0.27319,-2.84688 2.07488,-2.23968 4.45613,-4.52249 5.75016,-5.84528 1.30068,-1.32943 3.5669,-1.29182 4.84213,0 z" inkscape:connector-curvature="0" /> -</g> -<path id="path3959" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:100%;font-family:'Euphoria Script';-inkscape-font-specification:'Euphoria Script';letter-spacing:0px;word-spacing:0px;fill:#f58908;fill-opacity:1;stroke:none;stroke-width:2.2432382px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 109.8503,40.23567 q 2.3202,-1.13792 2.5606,-3.97352 0.186,-2.4898 -0.6114,-5.68054 -4.6175,2.38741 -5.4222,7.07206 -0.039,0.31176 -0.4521,0.31617 -0.2327,-0.0181 -0.2304,-0.20804 0.2868,-2.21912 1.6902,-4.37864 1.4161,-2.13367 4.2015,-3.62721 -0.3485,-1.42876 -0.9383,-3.28215 -0.589,-1.85376 -1.0504,-3.6417 l -0.2322,0.11386 q -0.4308,7.59868 -2.1838,8.45843 -1.9593,0.96092 -3.4388,-2.05579 -1.4792,-3.01595 -1.6821,-6.68994 -0.2158,-3.70067 0.7277,-4.45045 l 0.1545,-0.0758 q 0.4384,-0.21504 0.7184,0.35587 0.056,0.83196 0.1759,2.18389 0.1055,1.32413 0.6479,4.25553 0.5302,2.90629 1.2384,4.35032 0.6952,1.41738 1.314,1.11387 0.7217,-0.35392 1.0938,-3.63852 0.5507,-4.81127 0.4321,-9.42182 -0.024,-1.93929 0.8271,-2.3566 0.5412,-0.26544 0.8324,0.32831 -0.048,1.14247 0.4702,3.95838 0.518,2.81594 1.3185,5.5575 0.788,2.71564 1.1744,4.28536 2.1236,-0.62598 3.1031,0.58868 0.169,0.20985 0.3557,0.59046 0.2016,0.41105 0.031,0.84428 -0.156,0.46367 -0.3882,0.57753 -0.036,-0.20882 -0.2945,-0.65823 -0.2394,-0.43031 -0.5463,-0.65751 -0.2817,-0.24901 -0.8327,-0.39429 -0.5509,-0.14529 -1.2443,0.006 1.6818,8.45026 -3.2164,10.8525 -2.114,1.03679 -3.5436,-0.11763 -0.06,-0.0649 -0.086,-0.11821 -0.075,-0.15224 0.1831,-0.34478 0.2581,-0.12656 0.4763,-0.007 0.9829,0.8296 2.6841,-0.005 z m -5.8407,-2.47555 q -1.4953,0.73334 -2.9885,-0.4853 -1.46703,-1.23146 -3.00964,-4.37681 -1.54261,-3.14535 -2.72572,-7.9052 -1.18349,-4.76062 -1.33672,-8.20304 -0.12779,-3.45585 0.80028,-3.91101 0.43846,-0.21504 0.69233,0.30259 0.0658,1.50318 0.46712,4.40843 0.3887,2.87934 0.85833,5.27137 0.49552,2.37934 1.42237,5.4433 0.9522,3.05057 1.95085,5.08683 0.9864,2.01114 1.9039,2.90394 0.9566,0.90675 1.6525,0.56545 0.593,-0.29083 0.8543,-1.12726 0.2762,-0.8059 0.2422,-1.46251 -0.01,-0.34475 0.3897,-0.37998 0.1659,0.013 0.154,0.1794 0.036,0.20882 0.01,0.54268 0,0.3219 -0.098,1.0397 -0.1791,1.59116 -1.2361,2.10957 z M 88.98873,24.94693 q 1.9593,-0.96092 3.08453,1.33339 0.64474,1.31462 0.47641,3.18855 -0.31956,3.13037 -2.79443,4.34415 -0.3867,0.18965 -0.70822,0.1868 -0.32152,-0.003 -0.5771,-0.19857 1.83035,-0.89767 2.31467,-3.75757 0.40304,-2.30821 -0.29248,-3.72636 -0.51818,-1.05657 -1.36892,-0.63933 -1.70147,0.83447 -1.86875,4.21028 -0.15655,3.65857 1.33529,6.70039 1.26447,2.57825 2.98667,2.37291 0.3362,-0.0327 0.7739,-0.24735 0.43847,-0.21504 0.82728,-0.66069 0.37449,-0.47641 0.55987,-0.94505 0.36747,-0.94512 0.43843,-1.91007 0.002,-0.25593 0.2859,-0.39518 0.46434,-0.22773 0.51313,-0.0628 0.0605,0.31973 -0.12521,1.24463 -0.16169,0.9103 -0.39682,1.53838 -0.22218,0.59056 -0.76883,1.23639 -0.50561,0.66347 -1.20205,1.00503 -2.73269,1.34022 -4.74476,-0.87137 -0.66188,-0.7623 -1.11734,-1.69098 -0.84709,-1.72721 -1.04663,-4.15539 -0.25398,-3.71313 1.29294,-6.16685 0.85704,-1.31743 2.1202,-1.93693 z M 78.98146,29.8549 q 1.95922,-0.96088 3.08445,1.33343 0.64474,1.31462 0.47648,3.18851 -0.31963,3.13041 -2.7945,4.34419 -0.3867,0.18965 -0.70822,0.1868 -0.32152,-0.003 -0.5771,-0.19857 1.83035,-0.89767 2.31467,-3.75757 0.40304,-2.30821 -0.29248,-3.72636 -0.51818,-1.05657 -1.36892,-0.63933 -1.70148,0.83447 -1.86875,4.21028 -0.15655,3.65857 1.33529,6.70039 1.26447,2.57825 2.98667,2.37291 0.3362,-0.0327 0.7739,-0.24735 0.43846,-0.21504 0.82728,-0.66069 0.37449,-0.47641 0.55987,-0.94505 0.36747,-0.94512 0.43843,-1.91007 0.002,-0.25593 0.2859,-0.39518 0.46434,-0.22773 0.51312,-0.0628 0.0605,0.31973 -0.1252,1.24463 -0.16169,0.9103 -0.39682,1.53838 -0.22219,0.59056 -0.76883,1.23639 -0.50561,0.66347 -1.20205,1.00503 -2.73269,1.34022 -4.74476,-0.87137 -0.66188,-0.7623 -1.11734,-1.69098 -0.84709,-1.72721 -1.04656,-4.15543 -0.25405,-3.71309 1.29294,-6.16685 0.85697,-1.31739 2.12021,-1.93693 z m -5.99756,9.27308 q -0.97961,0.48044 -2.02905,-1.65934 -0.59397,-1.2111 -0.64818,-2.49616 -1.00717,2.38069 -1.1369,7.59367 -0.1428,5.18633 0.47693,6.44995 0.15307,0.3121 -0.25951,0.51445 -0.74752,0.36661 -1.74656,-1.67041 -1.88383,-3.8411 -2.64035,-7.33988 -0.75614,-3.49801 0.35242,-4.0417 0.49022,-0.24042 0.77022,0.33049 0.65986,4.34508 2.07889,8.54256 l 0.18041,-0.0885 q -0.27614,-5.84491 0.9227,-9.79086 0.68511,-2.25485 1.87094,-2.83643 0.25805,-0.12656 0.48724,-0.0501 0.25508,0.0638 0.37081,0.29974 -0.0908,0.27117 -0.17339,0.7555 -0.0826,0.48434 0.15133,2.06843 0.21898,1.55555 1.0026,3.15334 0.1008,0.20553 -0.0278,0.26863 z m -24.00261,4.57617 q 0.93557,1.90762 2.08179,1.50599 0.0978,0.39586 -0.41752,0.6486 -1.05703,0.51841 -2.12769,-0.55616 -0.49748,-0.49258 -0.91412,-1.3421 -0.43008,-0.87692 -0.35418,-2.41655 0.14265,-3.55637 3.74658,-6.31542 1.23938,-0.92891 2.78618,-1.68752 1.5726,-0.77127 2.52802,-1.62701 0.95549,-0.85579 1.18133,-1.4387 0.58996,-1.53584 1.10553,-1.7887 0.51534,-0.25274 0.66841,0.0594 0.0373,0.0761 0.0747,0.15224 0.17425,0.81164 -0.87704,2.12424 -0.64947,0.76235 -1.57615,1.48124 -0.67528,0.77501 -0.44428,2.68066 0.2169,1.87669 1.09001,5.22196 1.27704,-0.78684 2.15358,-1.21673 0.23217,-0.11387 0.34443,0.18048 0.0503,0.36249 -0.37696,0.60037 -0.43847,0.21504 -1.90971,1.25766 1.72164,6.57513 2.03307,9.49236 0.80387,7.37746 -3.39828,9.43837 -3.01625,1.47929 -5.1168,-0.91272 -0.75172,-0.81455 -1.21951,-1.76836 -0.88479,-1.80408 -0.81608,-4.07675 0.0907,-3.46668 2.43669,-4.61725 0.33494,-0.16427 0.61589,-0.1132 0.30684,0.0384 0.53679,0.31277 -2.21705,1.08733 -2.53547,4.08967 -0.26189,2.3353 0.67368,4.24291 1.36564,2.78454 3.62846,2.44249 0.52781,-0.0983 1.2751,-0.46483 0.74752,-0.36661 1.35607,-1.21277 0.64913,-0.82829 0.76238,-2.29275 0.1518,-1.45032 0.22381,-2.41295 0.0592,-0.98843 -0.33485,-3.22587 -0.50499,-2.72598 -1.04037,-4.99039 -0.54701,-2.28988 -0.64659,-2.75286 -1.33165,0.93639 -2.07925,1.30304 -0.72163,0.35392 -1.14234,-0.24241 -0.2767,-0.50643 -0.007,-0.73301 0.20331,0.0891 0.87387,-0.23971 0.69575,-0.34123 2.10204,-1.19147 -0.59433,-2.84269 -0.77295,-4.70604 -0.19101,-1.88939 0.2038,-3.10571 -0.41258,0.20235 -1.28905,0.6322 -4.94974,2.42755 -5.50603,6.31427 -0.28375,1.83421 0.3987,3.22572 z m 13.93518,-0.27799 q 0.0635,0.1294 -0.1687,0.24327 -0.23218,0.11386 -0.51288,0.12877 -0.25856,-0.005 -0.34442,-0.18047 -1.28949,-2.62925 -1.4805,-4.51863 -0.2037,-1.91527 0.77591,-2.39571 0.25805,-0.12656 0.52806,-0.0324 0.27001,0.0942 0.41934,0.3987 -0.59114,1.72906 0.0184,4.27626 0.26186,1.05574 0.76736,2.08643 z m -26.85252,8.49992 q 1.02752,0.2043 1.69785,-0.12446 0.69575,-0.34122 0.89009,-0.66317 0.16426,0.33494 0.008,0.79861 -0.1458,0.4209 -0.7126,0.69889 -0.54123,0.26544 -1.31284,0.3228 1.13504,2.44909 1.6409,5.36728 0.49157,2.89309 0.15269,5.20195 -0.35143,2.2829 -1.51153,2.85186 -1.16009,0.56895 -2.22121,-0.0297 -1.13792,-0.68935 -2.04848,-2.54596 -0.51818,-1.05657 -0.98388,-2.33152 -0.38965,7.2914 -2.11693,8.13853 -1.70148,0.83447 -3.1179,-2.05359 -1.46645,-2.99006 -1.66579,-7.11339 -0.0901,-3.31378 0.87762,-3.94894 0.49023,-0.24042 0.75529,0.30004 0.0568,0.89757 0.17487,2.3128 0.10462,1.38783 0.596,4.34523 0.51696,2.94486 1.12362,4.18184 0.59435,1.21185 1.13557,0.94642 0.67064,-0.32891 1.02605,-3.18979 0.38152,-2.87369 0.40214,-5.57039 l 0.0595,-2.6827 q 0.0134,-1.79795 0.58076,-2.0762 0.56711,-0.27813 0.83217,0.26234 1.06992,6.15913 2.56176,9.20095 0.69552,1.41815 1.52045,1.01357 0.92808,-0.45516 1.18758,-2.46917 0.27261,-2.05255 -0.25815,-4.83011 -0.51832,-2.81671 -1.69395,-5.21378 l -0.0747,-0.15224 q -1.01258,-0.17386 -1.84406,-0.69527 -0.83021,-0.51827 -1.00791,-0.88061 -0.1904,-0.38822 -0.005,-0.85697 0.18187,-0.47636 0.56857,-0.66602 0.48946,-0.24005 1.30654,0.44707 0.80372,0.66063 1.47631,1.70663 z M 17.6483,75.44555 q -2.11398,1.03678 -3.74507,-2.28898 -0.97365,-1.98526 -1.15689,-4.83693 -0.26478,-3.99586 1.35792,-6.29505 0.70002,-0.98545 1.52495,-1.39003 0.82501,-0.40461 1.46451,-0.27442 0.66569,0.11734 0.97354,0.41963 l 0.31879,0.25915 q 0.13889,0.47959 -0.22193,0.65655 -0.41258,0.20234 -0.57982,0.0577 -0.15409,-0.17939 -0.29291,-0.27184 -0.15231,-0.11416 -0.55122,-0.21126 -0.41087,-0.11956 -0.77168,0.0574 -1.67575,0.82185 -1.56254,4.50865 0.16007,4.2389 1.6646,7.30661 0.75861,1.54679 1.37748,1.24327 0.49023,-0.24042 0.83544,-1.75254 0.3584,-1.55165 0.529,-3.68165 0.31044,-3.67077 0.34334,-6.27716 -0.0336,-2.28574 0.89444,-2.74091 0.48946,-0.24005 0.78066,0.3537 0.007,0.60105 0.0898,1.68309 0.0816,1.07901 0.80339,4.05088 0.72189,2.97183 2.02445,5.62772 1.30218,2.65513 2.10138,2.26317 0.30906,-0.15157 0.42898,-0.55978 0.13112,-0.38538 0.0723,-1.02701 -0.0605,-0.31973 0.22269,-0.45861 0.10276,-0.0504 0.19186,3.3e-4 0.0906,0.05 0.12693,0.25882 0.0363,0.20882 0.0585,0.57566 0.0356,0.39802 -0.1374,1.15429 -0.14751,0.74281 -0.61148,0.97036 -1.08275,0.53102 -2.37081,-0.59558 -1.26253,-1.13998 -2.2108,-3.07348 -0.94826,-1.93349 -1.5368,-3.85171 l -0.25806,0.12656 q -0.53045,7.19993 -2.18032,8.00909 z M 10.10761,69.96506 Q 9.127997,70.4455 8.078561,68.30572 7.484589,67.09462 7.430374,65.80956 q -1.007167,2.38069 -1.1369,7.59367 -0.142799,5.18633 0.476932,6.44996 0.153066,0.3121 -0.259514,0.51444 -0.747516,0.36661 -1.746553,-1.67041 -1.883833,-3.8411 -2.640351,-7.33988 -0.756144,-3.49801 0.352417,-4.0417 0.490225,-0.24042 0.770224,0.33049 0.659852,4.34508 2.078886,8.54257 l 0.180409,-0.0885 q -0.276139,-5.84492 0.922698,-9.79086 0.685115,-2.25486 1.87094,-2.83644 0.258053,-0.12656 0.487247,-0.0501 0.255075,0.0638 0.370808,0.29974 -0.09081,0.27117 -0.173396,0.75551 -0.08259,0.48433 0.151337,2.06842 0.218977,1.55555 1.002602,3.15335 0.1008,0.20552 -0.0278,0.26862 z m -28.80073,8.01722 q -0.95389,0.46782 -1.61132,-0.87268 -0.65744,-1.34051 -0.0747,-3.67358 0.95492,-3.92169 4.86469,-6.38313 l 1.38051,-0.77149 q 4.691995,-2.30114 8.638958,0.3997 2.388837,1.67552 3.855286,4.66559 0.607038,1.23774 1.0708788,2.7053 1.50293,4.95523 0.2604394,9.52978 -1.3613282,5.04927 -5.4861402,7.07224 -4.099006,2.01032 -6.332712,0.25966 -0.6896,-0.55889 -1.08086,-1.35665 -0.40469,-0.82516 -0.40862,-1.94224 0.0414,-2.06756 1.5108,-2.78824 0.12865,-0.0631 0.2292,0.0765 0.11675,0.10327 0.11529,0.29285 0.0214,0.17838 -0.10574,0.24072 -0.87654,0.4299 -0.96443,1.88097 -0.021,1.00087 0.30795,1.6715 0.32854,0.66987 0.8651,1.11118 1.684414,1.3477 4.803733,-0.18214 3.531898,-1.73218 4.623501,-6.74455 0.984933,-4.51244 -0.416672,-9.26146 -0.437465,-1.54471 -1.057196,-2.80833 -1.377969,-2.80965 -3.589474,-4.1236 -2.952842,-1.78231 -6.536272,-0.0249 -4.4857,2.19997 -5.24904,6.31666 -0.37568,2.1031 0.28176,3.4436 0.26506,0.54047 0.49723,0.4266 0.0993,0.59342 -0.39088,0.83384 z m 8.50402,7.94956 q -1.92191,-3.91875 -3.03383,-7.94579 -1.12499,-4.05368 -1.16871,-6.68671 -0.031,-2.67138 0.9229,-3.13921 0.41258,-0.20234 0.61418,0.20871 0.0159,2.9668 1.09898,7.39232 1.95388,8.09206 3.547261,11.34094 0.164266,0.33493 -0.196551,0.51189 Q -9.178267,87.9933 -10.19,85.9304 Z" inkscape:connector-curvature="0" /> -</g> -<g id="designBottomGenerator" sodipodi:insensitive="true"> -<use height="100%" width="100%" id="bottom1" transform="translate(-100,-100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom2" transform="translate(0,-100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom3" transform="translate(100,-100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom4" transform="translate(-100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom5" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom6" transform="translate(100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom7" transform="translate(-100,100)" xlink:href="#designBottom" y="0" x="0" /> -<use height="100%" width="100%" id="bottom8" transform="translate(0,100)" xlink:href="#designBottom" y="0" x="0" /> -<use transform="translate(100,100)" height="100%" width="100%" id="bottom9" xlink:href="#designBottom" y="0" x="0" /> -</g> -<g id="designTopGenerator" sodipodi:insensitive="true"> -<use height="100%" width="100%" id="top1" transform="translate(-100,-100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top2" transform="translate(0,-100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top3" transform="translate(100,-100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top4" transform="translate(-100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top5" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top6" transform="translate(100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top7" transform="translate(-100,100)" xlink:href="#designTop" y="0" x="0" /> -<use height="100%" width="100%" id="top8" transform="translate(0,100)" xlink:href="#designTop" y="0" x="0" /> -<use transform="translate(100,100)" height="100%" width="100%" id="top9" xlink:href="#designTop" y="0" x="0" /> -</g> -</g> -</g> -<inkscape:_templateinfo id="_templateinfo10"> -<inkscape:_name id="_name12">Seamless Pattern</inkscape:_name> -<inkscape:_shortdesc id="_shortdesc14">Seamless Pattern</inkscape:_shortdesc> -<inkscape:_keywords id="_keywords16">Seamless Pattern</inkscape:_keywords> -</inkscape:_templateinfo> -</svg> diff --git a/share/extensions/seamless_pattern_procedural.inx b/share/extensions/seamless_pattern_procedural.inx deleted file mode 100644 index 0c173fd0c..000000000 --- a/share/extensions/seamless_pattern_procedural.inx +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"> - <_name>Seamless Pattern Procedural</_name> - <id>org.inkscape.render.seamless_pattern_procedural</id> - <dependency type="executable" location="extensions">seamless_pattern.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - - <param name="width" _gui-text="Custom Width (px):" type="int" min="1" max="99999999">100</param> - <param name="height" _gui-text="Custom Height (px):" type="int" min="1" max="99999999">100</param> - - <effect needs-live-preview="false"> - <object-type>all</object-type> - <effects-menu hidden="true" /> - </effect> - <inkscape:_templateinfo> - <inkscape:_name>Seamless Pattern...</inkscape:_name> - <inkscape:author>Jabiertxof</inkscape:author> - <inkscape:_shortdesc>Create seamless patterns.</inkscape:_shortdesc> - <inkscape:date>2014-10-16</inkscape:date> - <inkscape:_keywords>live seamless patterns</inkscape:_keywords> - </inkscape:_templateinfo> - <script> - <command reldir="extensions" interpreter="python">seamless_pattern.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/setup_typography_canvas.inx b/share/extensions/setup_typography_canvas.inx deleted file mode 100644 index 8e7739b5c..000000000 --- a/share/extensions/setup_typography_canvas.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>1 - Setup Typography Canvas</_name> - <id>org.inkscape.typography.setuptypographycanvas</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">setup_typography_canvas.py</dependency> - <param name="emsize" type="int" _gui-text="Em-size:" min="10" max="2048">1000</param> - <param name="ascender" type="int" _gui-text="Ascender:" min="0" max="2048">750</param> - <param name="caps" type="int" _gui-text="Caps Height:" min="0" max="2048">700</param> - <param name="xheight" type="int" _gui-text="X-Height:" min="0" max="2048">500</param> - <param name="descender" type="int" _gui-text="Descender:" min="0" max="1024">250</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">setup_typography_canvas.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/setup_typography_canvas.py b/share/extensions/setup_typography_canvas.py deleted file mode 100755 index 209c9757f..000000000 --- a/share/extensions/setup_typography_canvas.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import sys - -class SetupTypographyCanvas(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-e", "--emsize", - action="store", type="int", - dest="emsize", default=1000, - help="Em-size") - self.OptionParser.add_option("-a", "--ascender", - action="store", type="int", - dest="ascender", default='750', - help="Ascender") - self.OptionParser.add_option("-c", "--caps", - action="store", type="int", - dest="caps", default='700', - help="Caps Height") - self.OptionParser.add_option("-x", "--xheight", - action="store", type="int", - dest="xheight", default='500', - help="x-height") - self.OptionParser.add_option("-d", "--descender", - action="store", type="int", - dest="descender", default='250', - help="Descender") - - def create_horizontal_guideline(self, name, position): - self.create_guideline(name, "0,1", 0, position) - - def create_vertical_guideline(self, name, position): - self.create_guideline(name, "1,0", position, 0) - - def create_guideline(self, label, orientation, x,y): - namedview = self.svg.find(inkex.addNS('namedview', 'sodipodi')) - guide = inkex.etree.SubElement(namedview, inkex.addNS('guide', 'sodipodi')) - guide.set("orientation", orientation) - guide.set("position", str(x)+","+str(y)) - guide.set(inkex.addNS('label', 'inkscape'), label) - - def effect(self): - # Get all the options - emsize = self.options.emsize - ascender = self.options.ascender - caps = self.options.caps - xheight = self.options.xheight - descender = self.options.descender - - # Get access to main SVG document element - self.svg = self.document.getroot() - self.svg.set("width", str(emsize)) - self.svg.set("height", str(emsize)) - self.svg.set("viewBox", "0 0 " + str(emsize) + " " + str(emsize) ) - - baseline = descender - # Create guidelines - self.create_horizontal_guideline("baseline", baseline) - self.create_horizontal_guideline("ascender", baseline+ascender) - self.create_horizontal_guideline("caps", baseline+caps) - self.create_horizontal_guideline("xheight", baseline+xheight) - self.create_horizontal_guideline("descender", baseline-descender) - - namedview = self.svg.find(inkex.addNS('namedview', 'sodipodi')) - namedview.set(inkex.addNS('document-units', 'inkscape'), 'px') - namedview.set(inkex.addNS('cx', 'inkscape'), str(emsize/2.0 )) - namedview.set(inkex.addNS('cy', 'inkscape'), str(emsize/2.0 )) - - -if __name__ == '__main__': - e = SetupTypographyCanvas() - e.affect() - diff --git a/share/extensions/simplepath.py b/share/extensions/simplepath.py deleted file mode 100644 index 2d30a9e33..000000000 --- a/share/extensions/simplepath.py +++ /dev/null @@ -1,211 +0,0 @@ -""" -simplepath.py -functions for digesting paths into a simple list structure - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -import re, math - -def lexPath(d): - """ - returns and iterator that breaks path data - identifies command and parameter tokens - """ - offset = 0 - length = len(d) - delim = re.compile(r'[ \t\r\n,]+') - command = re.compile(r'[MLHVCSQTAZmlhvcsqtaz]') - parameter = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') - while 1: - m = delim.match(d, offset) - if m: - offset = m.end() - if offset >= length: - break - m = command.match(d, offset) - if m: - yield [d[offset:m.end()], True] - offset = m.end() - continue - m = parameter.match(d, offset) - if m: - yield [d[offset:m.end()], False] - offset = m.end() - continue - #TODO: create new exception - raise Exception, 'Invalid path data!' -''' -pathdefs = {commandfamily: - [ - implicitnext, - #params, - [casts,cast,cast], - [coord type,x,y,0] - ]} -''' -pathdefs = { - 'M':['L', 2, [float, float], ['x','y']], - 'L':['L', 2, [float, float], ['x','y']], - 'H':['H', 1, [float], ['x']], - 'V':['V', 1, [float], ['y']], - 'C':['C', 6, [float, float, float, float, float, float], ['x','y','x','y','x','y']], - 'S':['S', 4, [float, float, float, float], ['x','y','x','y']], - 'Q':['Q', 4, [float, float, float, float], ['x','y','x','y']], - 'T':['T', 2, [float, float], ['x','y']], - 'A':['A', 7, [float, float, float, int, int, float, float], ['r','r','a',0,'s','x','y']], - 'Z':['L', 0, [], []] - } -def parsePath(d): - """ - Parse SVG path and return an array of segments. - Removes all shorthand notation. - Converts coordinates to absolute. - """ - retval = [] - lexer = lexPath(d) - - pen = (0.0,0.0) - subPathStart = pen - lastControl = pen - lastCommand = '' - - while 1: - try: - token, isCommand = lexer.next() - except StopIteration: - break - params = [] - needParam = True - if isCommand: - if not lastCommand and token.upper() != 'M': - raise Exception, 'Invalid path, must begin with moveto.' - else: - command = token - else: - #command was omitted - #use last command's implicit next command - needParam = False - if lastCommand: - if lastCommand.isupper(): - command = pathdefs[lastCommand][0] - else: - command = pathdefs[lastCommand.upper()][0].lower() - else: - raise Exception, 'Invalid path, no initial command.' - numParams = pathdefs[command.upper()][1] - while numParams > 0: - if needParam: - try: - token, isCommand = lexer.next() - if isCommand: - raise Exception, 'Invalid number of parameters' - except StopIteration: - raise Exception, 'Unexpected end of path' - cast = pathdefs[command.upper()][2][-numParams] - param = cast(token) - if command.islower(): - if pathdefs[command.upper()][3][-numParams]=='x': - param += pen[0] - elif pathdefs[command.upper()][3][-numParams]=='y': - param += pen[1] - params.append(param) - needParam = True - numParams -= 1 - #segment is now absolute so - outputCommand = command.upper() - - #Flesh out shortcut notation - if outputCommand in ('H','V'): - if outputCommand == 'H': - params.append(pen[1]) - if outputCommand == 'V': - params.insert(0,pen[0]) - outputCommand = 'L' - if outputCommand in ('S','T'): - params.insert(0,pen[1]+(pen[1]-lastControl[1])) - params.insert(0,pen[0]+(pen[0]-lastControl[0])) - if outputCommand == 'S': - outputCommand = 'C' - if outputCommand == 'T': - outputCommand = 'Q' - - #current values become "last" values - if outputCommand == 'M': - subPathStart = tuple(params[0:2]) - pen = subPathStart - if outputCommand == 'Z': - pen = subPathStart - else: - pen = tuple(params[-2:]) - - if outputCommand in ('Q','C'): - lastControl = tuple(params[-4:-2]) - else: - lastControl = pen - lastCommand = command - - retval.append([outputCommand,params]) - return retval - -def formatPath(a): - """Format SVG path data from an array""" - return "".join([cmd + " ".join([str(p) for p in params]) for cmd, params in a]) - -def translatePath(p, x, y): - for cmd,params in p: - defs = pathdefs[cmd] - for i in range(defs[1]): - if defs[3][i] == 'x': - params[i] += x - elif defs[3][i] == 'y': - params[i] += y - -def scalePath(p, x, y): - for cmd,params in p: - defs = pathdefs[cmd] - for i in range(defs[1]): - if defs[3][i] == 'x': - params[i] *= x - elif defs[3][i] == 'y': - params[i] *= y - elif defs[3][i] == 'r': # radius parameter - params[i] *= x - elif defs[3][i] == 's': # sweep-flag parameter - if x*y < 0: - params[i] = 1 - params[i] - elif defs[3][i] == 'a': # x-axis-rotation angle - if y < 0: - params[i] = - params[i] - -def rotatePath(p, a, cx = 0, cy = 0): - if a == 0: - return p - for cmd,params in p: - defs = pathdefs[cmd] - for i in range(defs[1]): - if defs[3][i] == 'x': - x = params[i] - cx - y = params[i + 1] - cy - r = math.sqrt((x**2) + (y**2)) - if r != 0: - theta = math.atan2(y, x) + a - params[i] = (r * math.cos(theta)) + cx - params[i + 1] = (r * math.sin(theta)) + cy - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/simplepath.rb b/share/extensions/simplepath.rb deleted file mode 100755 index dc7123b43..000000000 --- a/share/extensions/simplepath.rb +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env ruby - -# simplepath.rb -# functions for digesting paths into a simple list structure -# -# Ruby port by MenTaLguY -# -# Copyright (C) 2005 Aaron Spike <aaron@ekips.org> -# Copyright (C) 2006 MenTaLguY <mental@rydia.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 -# 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 - -require 'strscan' - -def lexPath(d) - # iterator which breaks path data - # identifies command and parameter tokens - - scanner = StringScanner.new(d) - - delim = /[ \t\r\n,]+/ - command = /[MLHVCSQTAZmlhvcsqtaz]/ - parameter = /(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)/ - - until scanner.eos? - scanner.skip(delim) - if m = scanner.scan(command) - yield m, true - elsif m = scanner.scan(parameter) - yield m, false - else - #TODO: create new exception - raise 'Invalid path data!' - end - end -end - -PathDef = Struct.new :implicit_next, :param_count, :casts, :coord_types -PATHDEFS = { - 'M' => PathDef['L', 2, [:to_f, :to_f], [:x,:y]], - 'L' => PathDef['L', 2, [:to_f, :to_f], [:x,:y]], - 'H' => PathDef['H', 1, [:to_f], [:x]], - 'V' => PathDef['V', 1, [:to_f], [:y]], - 'C' => PathDef['C', 6, [:to_f, :to_f, :to_f, :to_f, :to_f, :to_f], [:x,:y,:x,:y,:x,:y]], - 'S' => PathDef['S', 4, [:to_f, :to_f, :to_f, :to_f], [:x,:y,:x,:y]], - 'Q' => PathDef['Q', 4, [:to_f, :to_f, :to_f, :to_f], [:x,:y,:x,:y]], - 'T' => PathDef['T', 2, [:to_f, :to_f], [:x,:y]], - 'A' => PathDef['A', 7, [:to_f, :to_f, :to_f, :to_i, :to_i, :to_f, :to_f], [0,0,0,0,0,:x,:y]], - 'Z' => PathDef['L', 0, [], []] -} - -def parsePath(d) - # Parse SVG path and return an array of segments. - # Removes all shorthand notation. - # Converts coordinates to absolute. - - retval = [] - - command = nil - outputCommand = nil - params = [] - - pen = [0.0,0.0] - subPathStart = pen - lastControl = pen - lastCommand = nil - - lexPath(d) do |token, isCommand| - raise 'Invalid number of parameters' if command and isCommand - - unless command - if isCommand - raise 'Invalid path, must begin with moveto.' \ - unless lastCommand or token.upcase == 'M' - command = token - else - #command was omitted - #use last command's implicit next command - raise 'Invalid path, no initial command.' unless lastCommand - if lastCommand =~ /[A-Z]/ - command = PATHDEFS[lastCommand].implicit_next - else - command = PATHDEFS[lastCommand.upcase].implicit_next.downcase - end - end - outputCommand = command.upcase - end - - unless isCommand - param = token.send PATHDEFS[outputCommand].casts[params.length] - if command =~ /[a-z]/ - case PATHDEFS[outputCommand].coord_types[params.length] - when :x: param += pen[0] - when :y: param += pen[1] - end - end - params.push param - end - - if params.length == PATHDEFS[outputCommand].param_count - - #Flesh out shortcut notation - case outputCommand - when 'H','V' - case outputCommand - when 'H': params.push pen[1] - when 'V': params.unshift pen[0] - end - outputCommand = 'L' - when 'S','T' - params.unshift(pen[1]+(pen[1]-lastControl[1])) - params.unshift(pen[0]+(pen[0]-lastControl[0])) - case outputCommand - when 'S': outputCommand = 'C' - when 'T': outputCommand = 'Q' - end - end - - #current values become "last" values - case outputCommand - when 'M' - subPathStart = params[0,2] - pen = subPathStart - when 'Z' - pen = subPathStart - else - pen = params[-2,2] - end - - case outputCommand - when 'Q','C' - lastControl = params[-4,2] - else - lastControl = pen - end - - lastCommand = command - retval.push [outputCommand,params] - command = nil - params = [] - end - end - - raise 'Unexpected end of path' if command - - return retval -end - -def formatPath(a) - # Format SVG path data from an array - a.map { |cmd,params| "#{cmd} #{params.join(' ')}" }.join -end - -def _transformPath(p) - p.each do |cmd,params| - coord_types = PATHDEFS[cmd].coord_types - for i in 0...(params.length) - yield params, i, coord_types[i] - end - end -end - -def translatePath(p, x, y) - _transformPath(p) do |params, i, coord_type| - case coord_type - when :x: params[i] += x - when :y: params[i] += y - end - end -end - -def scalePath(p, x, y) - _transformPath(p) do |params, i, coord_type| - case coord_type - when :x: params[i] *= x - when :y: params[i] *= y - end - end -end - -def rotatePath(p, a, cx = 0, cy = 0) - return p if a == 0 - _transformPath(p) do |params, i, coord_type| - if coord_type == :x - x = params[i] - cx - y = params[i + 1] - cy - r = Math.sqrt((x**2) + (y**2)) - unless r.zero? - theta = Math.atan2(y, x) + a - params[i] = (r * Math.cos(theta)) + cx - params[i + 1] = (r * Math.sin(theta)) + cy - end - end - end -end diff --git a/share/extensions/simplestyle.py b/share/extensions/simplestyle.py deleted file mode 100644 index b4d4233e2..000000000 --- a/share/extensions/simplestyle.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -simplestyle.py -Two simple functions for working with inline css -and some color handling on top. - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" - -svgcolors={ - 'aliceblue':'#f0f8ff', - 'antiquewhite':'#faebd7', - 'aqua':'#00ffff', - 'aquamarine':'#7fffd4', - 'azure':'#f0ffff', - 'beige':'#f5f5dc', - 'bisque':'#ffe4c4', - 'black':'#000000', - 'blanchedalmond':'#ffebcd', - 'blue':'#0000ff', - 'blueviolet':'#8a2be2', - 'brown':'#a52a2a', - 'burlywood':'#deb887', - 'cadetblue':'#5f9ea0', - 'chartreuse':'#7fff00', - 'chocolate':'#d2691e', - 'coral':'#ff7f50', - 'cornflowerblue':'#6495ed', - 'cornsilk':'#fff8dc', - 'crimson':'#dc143c', - 'cyan':'#00ffff', - 'darkblue':'#00008b', - 'darkcyan':'#008b8b', - 'darkgoldenrod':'#b8860b', - 'darkgray':'#a9a9a9', - 'darkgreen':'#006400', - 'darkgrey':'#a9a9a9', - 'darkkhaki':'#bdb76b', - 'darkmagenta':'#8b008b', - 'darkolivegreen':'#556b2f', - 'darkorange':'#ff8c00', - 'darkorchid':'#9932cc', - 'darkred':'#8b0000', - 'darksalmon':'#e9967a', - 'darkseagreen':'#8fbc8f', - 'darkslateblue':'#483d8b', - 'darkslategray':'#2f4f4f', - 'darkslategrey':'#2f4f4f', - 'darkturquoise':'#00ced1', - 'darkviolet':'#9400d3', - 'deeppink':'#ff1493', - 'deepskyblue':'#00bfff', - 'dimgray':'#696969', - 'dimgrey':'#696969', - 'dodgerblue':'#1e90ff', - 'firebrick':'#b22222', - 'floralwhite':'#fffaf0', - 'forestgreen':'#228b22', - 'fuchsia':'#ff00ff', - 'gainsboro':'#dcdcdc', - 'ghostwhite':'#f8f8ff', - 'gold':'#ffd700', - 'goldenrod':'#daa520', - 'gray':'#808080', - 'grey':'#808080', - 'green':'#008000', - 'greenyellow':'#adff2f', - 'honeydew':'#f0fff0', - 'hotpink':'#ff69b4', - 'indianred':'#cd5c5c', - 'indigo':'#4b0082', - 'ivory':'#fffff0', - 'khaki':'#f0e68c', - 'lavender':'#e6e6fa', - 'lavenderblush':'#fff0f5', - 'lawngreen':'#7cfc00', - 'lemonchiffon':'#fffacd', - 'lightblue':'#add8e6', - 'lightcoral':'#f08080', - 'lightcyan':'#e0ffff', - 'lightgoldenrodyellow':'#fafad2', - 'lightgray':'#d3d3d3', - 'lightgreen':'#90ee90', - 'lightgrey':'#d3d3d3', - 'lightpink':'#ffb6c1', - 'lightsalmon':'#ffa07a', - 'lightseagreen':'#20b2aa', - 'lightskyblue':'#87cefa', - 'lightslategray':'#778899', - 'lightslategrey':'#778899', - 'lightsteelblue':'#b0c4de', - 'lightyellow':'#ffffe0', - 'lime':'#00ff00', - 'limegreen':'#32cd32', - 'linen':'#faf0e6', - 'magenta':'#ff00ff', - 'maroon':'#800000', - 'mediumaquamarine':'#66cdaa', - 'mediumblue':'#0000cd', - 'mediumorchid':'#ba55d3', - 'mediumpurple':'#9370db', - 'mediumseagreen':'#3cb371', - 'mediumslateblue':'#7b68ee', - 'mediumspringgreen':'#00fa9a', - 'mediumturquoise':'#48d1cc', - 'mediumvioletred':'#c71585', - 'midnightblue':'#191970', - 'mintcream':'#f5fffa', - 'mistyrose':'#ffe4e1', - 'moccasin':'#ffe4b5', - 'navajowhite':'#ffdead', - 'navy':'#000080', - 'oldlace':'#fdf5e6', - 'olive':'#808000', - 'olivedrab':'#6b8e23', - 'orange':'#ffa500', - 'orangered':'#ff4500', - 'orchid':'#da70d6', - 'palegoldenrod':'#eee8aa', - 'palegreen':'#98fb98', - 'paleturquoise':'#afeeee', - 'palevioletred':'#db7093', - 'papayawhip':'#ffefd5', - 'peachpuff':'#ffdab9', - 'peru':'#cd853f', - 'pink':'#ffc0cb', - 'plum':'#dda0dd', - 'powderblue':'#b0e0e6', - 'purple':'#800080', - 'rebeccapurple':'#663399', - 'red':'#ff0000', - 'rosybrown':'#bc8f8f', - 'royalblue':'#4169e1', - 'saddlebrown':'#8b4513', - 'salmon':'#fa8072', - 'sandybrown':'#f4a460', - 'seagreen':'#2e8b57', - 'seashell':'#fff5ee', - 'sienna':'#a0522d', - 'silver':'#c0c0c0', - 'skyblue':'#87ceeb', - 'slateblue':'#6a5acd', - 'slategray':'#708090', - 'slategrey':'#708090', - 'snow':'#fffafa', - 'springgreen':'#00ff7f', - 'steelblue':'#4682b4', - 'tan':'#d2b48c', - 'teal':'#008080', - 'thistle':'#d8bfd8', - 'tomato':'#ff6347', - 'turquoise':'#40e0d0', - 'violet':'#ee82ee', - 'wheat':'#f5deb3', - 'white':'#ffffff', - 'whitesmoke':'#f5f5f5', - 'yellow':'#ffff00', - 'yellowgreen':'#9acd32' -} - -def parseStyle(s): - """Create a dictionary from the value of an inline style attribute""" - if s is None: - return {} - else: - return dict([[x.strip() for x in i.split(":")] for i in s.split(";") if len(i.strip())]) - -def formatStyle(a): - """Format an inline style attribute from a dictionary""" - return ";".join([att+":"+str(val) for att,val in a.iteritems()]) - -def isColor(c): - """Determine if its a color we can use. If not, leave it unchanged.""" - if c.startswith('#') and (len(c)==4 or len(c)==7): - return True - if c.lower() in svgcolors.keys(): - return True - #might be "none" or some undefined color constant or rgb() - #however, rgb() shouldn't occur at this point - return False - -def parseColor(c): - """Creates a rgb int array""" - tmp = svgcolors.get(c.lower()) - if tmp is not None: - c = tmp - elif c.startswith('#') and len(c)==4: - c='#'+c[1:2]+c[1:2]+c[2:3]+c[2:3]+c[3:]+c[3:] - elif c.startswith('rgb('): - # remove the rgb(...) stuff - tmp = c.strip()[4:-1] - numbers = [number.strip() for number in tmp.split(',')] - converted_numbers = [] - if len(numbers) == 3: - for num in numbers: - if num.endswith(r'%'): - converted_numbers.append(int(float(num[0:-1])*255/100)) - else: - converted_numbers.append(int(num)) - return tuple(converted_numbers) - else: - return (0,0,0) - try: - r=int(c[1:3],16) - g=int(c[3:5],16) - b=int(c[5:],16) - except: - # unknown color ... - # Return a default color. Maybe not the best thing to do but probably - # better than raising an exception. - return(0,0,0) - return (r,g,b) - -def formatColoria(a): - """int array to #rrggbb""" - return '#%02x%02x%02x' % (a[0],a[1],a[2]) - -def formatColorfa(a): - """float array to #rrggbb""" - return '#%02x%02x%02x' % (int(round(a[0]*255)),int(round(a[1]*255)),int(round(a[2]*255))) - -def formatColor3i(r,g,b): - """3 ints to #rrggbb""" - return '#%02x%02x%02x' % (r,g,b) - -def formatColor3f(r,g,b): - """3 floats to #rrggbb""" - return '#%02x%02x%02x' % (int(round(r*255)),int(round(g*255)),int(round(b*255))) - - -# 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 deleted file mode 100644 index f6f68d2be..000000000 --- a/share/extensions/simpletransform.py +++ /dev/null @@ -1,261 +0,0 @@ -''' -Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr -Copyright (C) 2010 Alvin Penner, penner@vaxxine.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -barraud@math.univ-lille1.fr - -This code defines several functions to make handling of transform -attribute easier. -''' -import inkex, cubicsuperpath, bezmisc, simplestyle -import copy, math, re - -def parseTransform(transf,mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - if transf=="" or transf==None: - return(mat) - stransf = transf.strip() - result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf) -#-- translate -- - if result.group(1)=="translate": - args=result.group(2).replace(',',' ').split() - dx=float(args[0]) - if len(args)==1: - dy=0.0 - else: - dy=float(args[1]) - matrix=[[1,0,dx],[0,1,dy]] -#-- scale -- - if result.group(1)=="scale": - args=result.group(2).replace(',',' ').split() - sx=float(args[0]) - if len(args)==1: - sy=sx - else: - sy=float(args[1]) - matrix=[[sx,0,0],[0,sy,0]] -#-- rotate -- - if result.group(1)=="rotate": - args=result.group(2).replace(',',' ').split() - a=float(args[0])*math.pi/180 - if len(args)==1: - cx,cy=(0.0,0.0) - else: - cx,cy=map(float,args[1:]) - matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]] - matrix=composeTransform(matrix,[[1,0,-cx],[0,1,-cy]]) -#-- skewX -- - if result.group(1)=="skewX": - a=float(result.group(2))*math.pi/180 - matrix=[[1,math.tan(a),0],[0,1,0]] -#-- skewY -- - if result.group(1)=="skewY": - a=float(result.group(2))*math.pi/180 - matrix=[[1,0,0],[math.tan(a),1,0]] -#-- matrix -- - if result.group(1)=="matrix": - a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split() - matrix=[[float(a11),float(a12),float(v1)], [float(a21),float(a22),float(v2)]] - - matrix=composeTransform(mat,matrix) - if result.end() < len(stransf): - return(parseTransform(stransf[result.end():], matrix)) - else: - return matrix - -def formatTransform(mat): - return ("matrix(%f,%f,%f,%f,%f,%f)" % (mat[0][0], mat[1][0], mat[0][1], mat[1][1], mat[0][2], mat[1][2])) - -def invertTransform(mat): - det = mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0] - if det !=0: # det is 0 only in case of 0 scaling - # invert the rotation/scaling part - a11 = mat[1][1]/det - a12 = -mat[0][1]/det - a21 = -mat[1][0]/det - a22 = mat[0][0]/det - # invert the translational part - a13 = -(a11*mat[0][2] + a12*mat[1][2]) - a23 = -(a21*mat[0][2] + a22*mat[1][2]) - return [[a11,a12,a13],[a21,a22,a23]] - else: - return[[0,0,-mat[0][2]],[0,0,-mat[1][2]]] - -def composeTransform(M1,M2): - a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0] - a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1] - a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0] - a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1] - - v1 = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2] - v2 = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2] - return [[a11,a12,v1],[a21,a22,v2]] - -def composeParents(node, mat): - trans = node.get('transform') - if trans: - mat = composeTransform(parseTransform(trans), mat) - if node.getparent().tag == inkex.addNS('g','svg'): - mat = composeParents(node.getparent(), mat) - return mat - -def applyTransformToNode(mat,node): - m=parseTransform(node.get("transform")) - newtransf=formatTransform(composeTransform(mat,m)) - node.set("transform", newtransf) - -def applyTransformToPoint(mat,pt): - x = mat[0][0]*pt[0] + mat[0][1]*pt[1] + mat[0][2] - y = mat[1][0]*pt[0] + mat[1][1]*pt[1] + mat[1][2] - pt[0]=x - pt[1]=y - -def applyTransformToPath(mat,path): - for comp in path: - for ctl in comp: - for pt in ctl: - applyTransformToPoint(mat,pt) - -def fuseTransform(node): - if node.get('d')==None: - #FIXME: how do you raise errors? - raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute' - t = node.get("transform") - if t == None: - return - m = parseTransform(t) - d = node.get('d') - p = cubicsuperpath.parsePath(d) - applyTransformToPath(m,p) - node.set('d', cubicsuperpath.formatPath(p)) - del node.attrib["transform"] - -#################################################################### -##-- Some functions to compute a rough bbox of a given list of objects. -##-- this should be shipped out in an separate file... - -def boxunion(b1,b2): - if b1 is None: - return b2 - elif b2 is None: - return b1 - else: - return((min(b1[0],b2[0]), max(b1[1],b2[1]), min(b1[2],b2[2]), max(b1[3],b2[3]))) - -def roughBBox(path): - xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1] - for pathcomp in path: - for ctl in pathcomp: - for pt in ctl: - xmin = min(xmin,pt[0]) - xMax = max(xMax,pt[0]) - ymin = min(ymin,pt[1]) - yMax = max(yMax,pt[1]) - return xmin,xMax,ymin,yMax - -def refinedBBox(path): - xmin,xMax,ymin,yMax = path[0][0][1][0],path[0][0][1][0],path[0][0][1][1],path[0][0][1][1] - for pathcomp in path: - for i in range(1, len(pathcomp)): - cmin, cmax = cubicExtrema(pathcomp[i-1][1][0], pathcomp[i-1][2][0], pathcomp[i][0][0], pathcomp[i][1][0]) - xmin = min(xmin, cmin) - xMax = max(xMax, cmax) - cmin, cmax = cubicExtrema(pathcomp[i-1][1][1], pathcomp[i-1][2][1], pathcomp[i][0][1], pathcomp[i][1][1]) - ymin = min(ymin, cmin) - yMax = max(yMax, cmax) - return xmin,xMax,ymin,yMax - -def cubicExtrema(y0, y1, y2, y3): - cmin = min(y0, y3) - cmax = max(y0, y3) - d1 = y1 - y0 - d2 = y2 - y1 - d3 = y3 - y2 - if (d1 - 2*d2 + d3): - if (d2*d2 > d1*d3): - t = (d1 - d2 + math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3) - if (t > 0) and (t < 1): - y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t - cmin = min(cmin, y) - cmax = max(cmax, y) - t = (d1 - d2 - math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3) - if (t > 0) and (t < 1): - y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t - cmin = min(cmin, y) - cmax = max(cmax, y) - elif (d3 - d1): - t = -d1/(d3 - d1) - if (t > 0) and (t < 1): - y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t - cmin = min(cmin, y) - cmax = max(cmax, y) - return cmin, cmax - -def computeBBox(aList,mat=[[1,0,0],[0,1,0]]): - bbox=None - for node in aList: - m = parseTransform(node.get('transform')) - m = composeTransform(mat,m) - #TODO: text not supported! - d = None - if node.get("d"): - d = node.get('d') - elif node.get('points'): - d = 'M' + node.get('points') - elif node.tag in [ inkex.addNS('rect','svg'), 'rect', inkex.addNS('image','svg'), 'image' ]: - d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \ - 'h' + node.get('width') + 'v' + node.get('height') + \ - 'h-' + node.get('width') - elif node.tag in [ inkex.addNS('line','svg'), 'line' ]: - d = 'M' + node.get('x1') + ',' + node.get('y1') + \ - ' ' + node.get('x2') + ',' + node.get('y2') - elif node.tag in [ inkex.addNS('circle','svg'), 'circle', \ - inkex.addNS('ellipse','svg'), 'ellipse' ]: - rx = node.get('r') - if rx is not None: - ry = rx - else: - rx = node.get('rx') - ry = node.get('ry') - cx = float(node.get('cx', '0')) - cy = float(node.get('cy', '0')) - x1 = cx - float(rx) - x2 = cx + float(rx) - d = 'M %f %f ' % (x1, cy) + \ - 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x2, cy) + \ - 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x1, cy) - - if d is not None: - p = cubicsuperpath.parsePath(d) - applyTransformToPath(m,p) - bbox=boxunion(refinedBBox(p),bbox) - - elif node.tag == inkex.addNS('use','svg') or node.tag=='use': - refid=node.get(inkex.addNS('href','xlink')) - path = '//*[@id="%s"]' % refid[1:] - refnode = node.xpath(path) - bbox=boxunion(computeBBox(refnode,m),bbox) - - bbox=boxunion(computeBBox(node,m),bbox) - return bbox - - -def computePointInNode(pt, node, mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - if node.getparent() is not None: - applyTransformToPoint(invertTransform(composeParents(node, mat)), pt) - return pt - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/sk1_input.inx b/share/extensions/sk1_input.inx deleted file mode 100644 index 4483c2e13..000000000 --- a/share/extensions/sk1_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>sK1 vector graphics files input</_name> - <id>org.inkscape.input.sk1</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.sk1</extension> - <mimetype>application/x-xsk1</mimetype> - <_filetypename>sK1 vector graphics files (UC) (*.sk1)</_filetypename> - <_filetypetooltip>Open files saved in sK1 vector graphics editor</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/sk1_output.inx b/share/extensions/sk1_output.inx deleted file mode 100644 index 1aeedb6c7..000000000 --- a/share/extensions/sk1_output.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>sK1 vector graphics files output</_name> - <id>org.inkscape.output.sk1</id> - <dependency type="executable" location="extensions">sk1_output.py</dependency> - <output> - <extension>.sk1</extension> - <mimetype>application/x-xsk1</mimetype> - <_filetypename>sK1 vector graphics files (UC) (*.sk1)</_filetypename> - <_filetypetooltip>File format for use in sK1 vector graphics editor</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">sk1_output.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/sk1_output.py b/share/extensions/sk1_output.py deleted file mode 100755 index 5ad2eaccc..000000000 --- a/share/extensions/sk1_output.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -sk1_output.py -Module for running UniConverter sk1 exporting commands in Inkscape extensions - -Copyright (C) 2009 Nicolas Dufour (jazzynico) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import sys -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 fileencoding=utf-8 textwidth=99
\ No newline at end of file diff --git a/share/extensions/sk2svg.sh b/share/extensions/sk2svg.sh deleted file mode 100755 index 886e92e58..000000000 --- a/share/extensions/sk2svg.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -rc=0 - -TMPDIR="${TMPDIR-/tmp}" -UNIQTMPDIR=`mktemp -d 2>/dev/null || (mkdir "$TMPDIR/sk2svg.$$" && echo "$TMPDIR/sk2svg.$$") || echo "$TMPDIR"` -TMPSVG="$UNIQTMPDIR/sk2svg$$.svg" -skconvert "$1" "$TMPSVG" > /dev/null 2>&1 || rc=1 -cat < "$TMPSVG" || RC=1 -rm -f "$TMPSVG" -[ "$UNIQTMPDIR" = "$TMPDIR" ] || rmdir "$UNIQTMPDIR" -exit $rc diff --git a/share/extensions/sk_input.inx b/share/extensions/sk_input.inx deleted file mode 100644 index a29f8b078..000000000 --- a/share/extensions/sk_input.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Sketch Input</_name> - <id>org.inkscape.input.sk</id> - <dependency type="executable" location="extensions">sk2svg.sh</dependency> - <dependency type="executable">skconvert</dependency> - <input> - <extension>.sk</extension> - <mimetype>application/x-sketch</mimetype> - <_filetypename>Sketch Diagram (*.sk)</_filetypename> - <_filetypetooltip>A diagram created with the program Sketch</_filetypetooltip> - </input> - <script> - <command reldir="extensions">sk2svg.sh</command> - </script> -</inkscape-extension> diff --git a/share/extensions/spirograph.inx b/share/extensions/spirograph.inx deleted file mode 100644 index 612643336..000000000 --- a/share/extensions/spirograph.inx +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Spirograph</_name> - <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="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> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">spirograph.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/spirograph.py b/share/extensions/spirograph.py deleted file mode 100755 index 02cb02bcd..000000000 --- a/share/extensions/spirograph.py +++ /dev/null @@ -1,121 +0,0 @@ -#! /usr/bin/env python -''' -Copyright (C) 2007 Joel Holdsworth joel@airwebreathe.org.uk - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import inkex, simplestyle, math -from simpletransform import computePointInNode - -class Spirograph(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-R", "--primaryr", - action="store", type="float", - dest="primaryr", default=60.0, - help="The radius of the outer gear") - self.OptionParser.add_option("-r", "--secondaryr", - action="store", type="float", - dest="secondaryr", default=100.0, - help="The radius of the inner gear") - self.OptionParser.add_option("-d", "--penr", - action="store", type="float", - dest="penr", default=50.0, - help="The distance of the pen from the inner gear") - self.OptionParser.add_option("-p", "--gearplacement", - action="store", type="string", - dest="gearplacement", default="inside", - help="Selects whether the gear is inside or outside the ring") - self.OptionParser.add_option("-a", "--rotation", - action="store", type="float", - dest="rotation", default=0.0, - help="The number of degrees to rotate the image by") - self.OptionParser.add_option("-q", "--quality", - action="store", type="int", - dest="quality", default=16, - help="The quality of the calculated output") - - def effect(self): - self.options.primaryr = self.unittouu(str(self.options.primaryr) + 'px') - self.options.secondaryr = self.unittouu(str(self.options.secondaryr) + 'px') - self.options.penr = self.unittouu(str(self.options.penr) + 'px') - - if self.options.secondaryr == 0: - return - if self.options.quality == 0: - return - - if(self.options.gearplacement.strip(' ').lower().startswith('outside')): - a = self.options.primaryr + self.options.secondaryr - flip = -1 - else: - a = self.options.primaryr - self.options.secondaryr - flip = 1 - - ratio = a / self.options.secondaryr - if ratio == 0: - return - scale = 2 * math.pi / (ratio * self.options.quality) - - rotation = - math.pi * self.options.rotation / 180; - - new = inkex.etree.Element(inkex.addNS('path','svg')) - s = { 'stroke': '#000000', 'fill': 'none', 'stroke-width': str(self.unittouu('1px')) } - new.set('style', simplestyle.formatStyle(s)) - - pathString = '' - maxPointCount = 1000 - - for i in range(maxPointCount): - - theta = i * scale - - view_center = computePointInNode(list(self.view_center), self.current_layer) - x = a * math.cos(theta + rotation) + \ - self.options.penr * math.cos(ratio * theta + rotation) * flip + \ - view_center[0] - y = a * math.sin(theta + rotation) - \ - self.options.penr * math.sin(ratio * theta + rotation) + \ - view_center[1] - - dx = (-a * math.sin(theta + rotation) - \ - ratio * self.options.penr * math.sin(ratio * theta + rotation) * flip) * scale / 3 - dy = (a * math.cos(theta + rotation) - \ - ratio * self.options.penr * math.cos(ratio * theta + rotation)) * scale / 3 - - if i <= 0: - pathString += 'M ' + str(x) + ',' + str(y) + ' C ' + str(x + dx) + ',' + str(y + dy) + ' ' - else: - pathString += str(x - dx) + ',' + str(y - dy) + ' ' + str(x) + ',' + str(y) - - if math.fmod(i / ratio, self.options.quality) == 0 and i % self.options.quality == 0: - pathString += 'Z' - break - else: - if i == maxPointCount - 1: - pass # we reached the allowed maximum of points, stop here - else: - pathString += ' C ' + str(x + dx) + ',' + str(y + dy) + ' ' - - - new.set('d', pathString) - self.current_layer.append(new) - -if __name__ == '__main__': - e = Spirograph() - e.affect() - - -# 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 deleted file mode 100644 index 12e443011..000000000 --- a/share/extensions/split.inx +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Split text</_name> - <id>com.nerdson.split</id> - <dependency type="executable" location="extensions">split.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <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> - <submenu _name="Text"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">split.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/split.py b/share/extensions/split.py deleted file mode 100755 index 4e83b3d33..000000000 --- a/share/extensions/split.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Karlisson Bezerra, contato@nerdson.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex - -class Split(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--splittype", - action="store", type="string", - dest="split_type", default="word", - help="type of split") - self.OptionParser.add_option("-p", "--preserve", - 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""" - - lines = [] - count = 1 - - for n in node: - if not (n.tag == inkex.addNS("flowPara", "svg") or n.tag == inkex.addNS("tspan", "svg")): - if n.tag == inkex.addNS("textPath", "svg"): - inkex.debug("This type of text element isn't supported. First remove text from path.") - break - else: - continue - - text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib) - - #handling flowed text nodes - if node.tag == inkex.addNS("flowRoot", "svg"): - try: - from simplestyle import parseStyle - fontsize = parseStyle(node.get("style"))["font-size"] - except: - fontsize = "12px" - fs = self.unittouu(fontsize) - - #selects the flowRegion's child (svg:rect) to get @X and @Y - id = node.get("id") - flowref = self.xpathSingle('/svg:svg//*[@id="%s"]/svg:flowRegion[1]' % id)[0] - - if flowref.tag == inkex.addNS("rect", "svg"): - text.set("x", flowref.get("x")) - text.set("y", str(float(flowref.get("y")) + fs * count)) - count += 1 - else: - inkex.debug("This type of text element isn't supported. First unflow text.") - break - - #now let's convert flowPara into tspan - tspan = inkex.etree.Element(inkex.addNS("tspan", "svg")) - tspan.set(inkex.addNS("role","sodipodi"), "line") - tspan.text = n.text - text.append(tspan) - - else: - from copy import copy - x = n.get("x") or node.get("x") - y = n.get("y") or node.get("y") - - text.set("x", x) - text.set("y", y) - text.append(copy(n)) - - lines.append(text) - - return lines - - - def split_words(self, node): - """Returns a list of words""" - - words = [] - - #Function to recursively extract text - def plain_str(elem): - words = [] - if elem.text: - words.append(elem.text) - for n in elem: - words.extend(plain_str(n)) - if n.tail: - words.append(n.tail) - return words - - #if text has more than one line, iterates through elements - lines = self.split_lines(node) - if not lines: - return words - - for line in lines: - #gets the position of text node - x = float(line.get("x")) - y = line.get("y") - - #gets the font size. if element doesn't have a style attribute, it assumes font-size = 12px - try: - from simplestyle import parseStyle - fontsize = parseStyle(line.get("style"))["font-size"] - except: - fontsize = "12px" - fs = self.unittouu(fontsize) - - #extract and returns a list of words - words_list = "".join(plain_str(line)).split() - prev_len = 0 - - #creates new text nodes for each string in words_list - for word in words_list: - tspan = inkex.etree.Element(inkex.addNS("tspan", "svg")) - tspan.text = word - - text = inkex.etree.Element(inkex.addNS("text", "svg"), line.attrib) - tspan.set(inkex.addNS("role","sodipodi"), "line") - - #positioning new text elements - x = x + prev_len * fs - prev_len = len(word) - text.set("x", str(x)) - text.set("y", str(y)) - - text.append(tspan) - words.append(text) - - return words - - - def split_letters(self, node): - """Returns a list of letters""" - - letters = [] - - words = self.split_words(node) - if not words: - return letters - - for word in words: - - x = float(word.get("x")) - y = word.get("y") - - #gets the font size. If element doesn't have a style attribute, it assumes font-size = 12px - try: - import simplestyle - fontsize = simplestyle.parseStyle(word.get("style"))["font-size"] - except: - fontsize = "12px" - fs = self.unittouu(fontsize) - - #for each letter in element string - for letter in word[0].text: - tspan = inkex.etree.Element(inkex.addNS("tspan", "svg")) - tspan.text = letter - - text = inkex.etree.Element(inkex.addNS("text", "svg"), node.attrib) - text.set("x", str(x)) - text.set("y", str(y)) - x += fs - - text.append(tspan) - letters.append(text) - return letters - - - def effect(self): - """Applies the effect""" - - split_type = self.options.split_type - preserve = self.options.preserve - - #checks if the selected elements are text nodes - for id, node in self.selected.iteritems(): - if not (node.tag == inkex.addNS("text", "svg") or node.tag == inkex.addNS("flowRoot", "svg")): - inkex.debug("Please select only text elements.") - break - else: - if split_type == "line": - nodes = self.split_lines(node) - elif split_type == "word": - nodes = self.split_words(node) - elif split_type == "letter": - nodes = self.split_letters(node) - - for n in nodes: - node.getparent().append(n) - - #preserve original element - if not preserve and nodes: - parent = node.getparent() - parent.remove(node) - -b = Split() -b.affect() diff --git a/share/extensions/straightseg.inx b/share/extensions/straightseg.inx deleted file mode 100644 index 45014c879..000000000 --- a/share/extensions/straightseg.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Straighten Segments</_name> - <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> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">straightseg.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/straightseg.py b/share/extensions/straightseg.py deleted file mode 100755 index 9222ed5b5..000000000 --- a/share/extensions/straightseg.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import math, inkex, simplepath, sys - -def pointAtPercent((x1, y1), (x2, y2), percent): - percent /= 100.0 - x = x1 + (percent * (x2 - x1)) - y = y1 + (percent * (y2 - y1)) - return [x,y] - -class SegmentStraightener(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-p", "--percent", - action="store", type="float", - dest="percent", default=10.0, - help="move curve handles PERCENT percent closer to a straight line") - self.OptionParser.add_option("-b", "--behavior", - action="store", type="int", - dest="behave", default=1, - help="straightening behavior for cubic segments") - def effect(self): - for id, node in self.selected.iteritems(): - if node.tag == inkex.addNS('path', 'svg'): - d = node.get('d') - p = simplepath.parsePath(d) - last = [] - subPathStart = [] - for cmd,params in p: - if cmd == 'C': - if self.options.behave <= 1: - #shorten handles towards end points - params[:2] = pointAtPercent(params[:2],last[:],self.options.percent) - params[2:4] = pointAtPercent(params[2:4],params[-2:],self.options.percent) - else: - #shorten handles towards thirds of the segment - dest1 = pointAtPercent(last[:],params[-2:],33.3) - dest2 = pointAtPercent(params[-2:],last[:],33.3) - params[:2] = pointAtPercent(params[:2],dest1[:],self.options.percent) - params[2:4] = pointAtPercent(params[2:4],dest2[:],self.options.percent) - elif cmd == 'Q': - dest = pointAtPercent(last[:],params[-2:],50) - params[:2] = pointAtPercent(params[:2],dest,self.options.percent) - if cmd == 'M': - subPathStart = params[-2:] - if cmd == 'Z': - last = subPathStart[:] - else: - last = params[-2:] - node.set('d',simplepath.formatPath(p)) - -if __name__ == '__main__': - e = SegmentStraightener() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/summersnight.inx b/share/extensions/summersnight.inx deleted file mode 100644 index db4b83971..000000000 --- a/share/extensions/summersnight.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Envelope</_name> - <id>org.ekips.filter.summersnight</id> - <dependency type="executable" location="extensions">summersnight.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">summersnight.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/summersnight.py b/share/extensions/summersnight.py deleted file mode 100755 index a4f15ef1f..000000000 --- a/share/extensions/summersnight.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -""" -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -""" -# standard library -import os -# local library -import cubicsuperpath -import inkex -import simplepath -import simpletransform -from ffgeom import * - -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False - -class Project(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - def effect(self): - if len(self.options.ids) < 2: - inkex.errormsg(_("This extension requires two selected paths. \nThe second path must be exactly four nodes long.")) - exit() - - #obj is selected second - scale = self.unittouu('1px') # convert to document units - doc = self.document.getroot() - h = self.unittouu(doc.xpath('@height', namespaces=inkex.NSS)[0]) - # process viewBox height attribute to correct page scaling - viewBox = doc.get('viewBox') - if viewBox: - viewBox2 = viewBox.split(',') - if len(viewBox2) < 4: - viewBox2 = viewBox.split(' ') - scale *= self.unittouu(self.addDocumentUnit(viewBox2[3])) / h - obj = self.selected[self.options.ids[0]] - trafo = self.selected[self.options.ids[1]] - if obj.get(inkex.addNS('type','sodipodi')): - inkex.errormsg(_("The first selected object is of type '%s'.\nTry using the procedure Path->Object to Path." % obj.get(inkex.addNS('type','sodipodi')))) - exit() - if obj.tag == inkex.addNS('path','svg') or obj.tag == inkex.addNS('g','svg'): - if trafo.tag == inkex.addNS('path','svg'): - #distil trafo into four node points - mat = simpletransform.composeParents(trafo, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - trafo = cubicsuperpath.parsePath(trafo.get('d')) - if len(trafo[0]) < 4: - inkex.errormsg(_("This extension requires that the second selected path be four nodes long.")) - exit() - simpletransform.applyTransformToPath(mat, trafo) - trafo = [[Point(csp[1][0],csp[1][1]) for csp in subs] for subs in trafo][0][:4] - - #vectors pointing away from the trafo origin - self.t1 = Segment(trafo[0],trafo[1]) - self.t2 = Segment(trafo[1],trafo[2]) - self.t3 = Segment(trafo[3],trafo[2]) - self.t4 = Segment(trafo[0],trafo[3]) - - #query inkscape about the bounding box of obj - self.q = {'x':0,'y':0,'width':0,'height':0} - file = self.args[-1] - id = self.options.ids[0] - for query in self.q.keys(): - if bsubprocess: - p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query,id,file), shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - self.q[query] = scale*float(p.stdout.read()) - err = p.stderr.read() - else: - f,err = os.popen3('inkscape --query-%s --query-id=%s "%s"' % (query,id,file))[1:] - self.q[query] = scale*float(f.read()) - f.close() - err.close() - - if obj.tag == inkex.addNS("path",'svg'): - self.process_path(obj) - if obj.tag == inkex.addNS("g",'svg'): - self.process_group(obj) - else: - if trafo.tag == inkex.addNS('g','svg'): - inkex.errormsg(_("The second selected object is a group, not a path.\nTry using the procedure Object->Ungroup.")) - else: - inkex.errormsg(_("The second selected object is not a path.\nTry using the procedure Path->Object to Path.")) - exit() - else: - inkex.errormsg(_("The first selected object is not a path.\nTry using the procedure Path->Object to Path.")) - exit() - - def process_group(self,group): - for node in group: - if node.tag == inkex.addNS('path','svg'): - self.process_path(node) - if node.tag == inkex.addNS('g','svg'): - self.process_group(node) - - def process_path(self,path): - mat = simpletransform.composeParents(path, [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - d = path.get('d') - p = cubicsuperpath.parsePath(d) - simpletransform.applyTransformToPath(mat, p) - for subs in p: - for csp in subs: - csp[0] = self.trafopoint(csp[0]) - csp[1] = self.trafopoint(csp[1]) - csp[2] = self.trafopoint(csp[2]) - mat = simpletransform.invertTransform(mat) - simpletransform.applyTransformToPath(mat, p) - path.set('d',cubicsuperpath.formatPath(p)) - - def trafopoint(self,(x,y)): - #Transform algorithm thanks to Jose Hevia (freon) - vector = Segment(Point(self.q['x'],self.q['y']),Point(x,y)) - xratio = abs(vector.delta_x())/self.q['width'] - yratio = abs(vector.delta_y())/self.q['height'] - - horz = Segment(self.t1.pointAtRatio(xratio),self.t3.pointAtRatio(xratio)) - vert = Segment(self.t4.pointAtRatio(yratio),self.t2.pointAtRatio(yratio)) - - p = intersectSegments(vert,horz) - return [p['x'],p['y']] - - -if __name__ == '__main__': - e = Project() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/svg2fxg.inx b/share/extensions/svg2fxg.inx deleted file mode 100644 index e2f9761fc..000000000 --- a/share/extensions/svg2fxg.inx +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>FXG Output</_name> - <id>org.inkscape.output.fxg</id> - <output> - <extension>.fxg</extension> - <mimetype>text/xml+fxg</mimetype> - <_filetypename>Flash XML Graphics (*.fxg)</_filetypename> - <_filetypetooltip>Adobe's XML Graphics file format</_filetypetooltip> - </output> - <xslt> - <file reldir="extensions">svg2fxg.xsl</file> - </xslt> -</inkscape-extension> diff --git a/share/extensions/svg2fxg.xsl b/share/extensions/svg2fxg.xsl deleted file mode 100644 index fee5a858f..000000000 --- a/share/extensions/svg2fxg.xsl +++ /dev/null @@ -1,3008 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- -Authors: - Nicolas Dufour <nicoduf@yahoo.fr> - -Copyright (c) 2010 authors - -Released under GNU GPL, read the file 'COPYING' for more information ---> - -<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://ns.adobe.com/fxg/2008" -xmlns:fxg="http://ns.adobe.com/fxg/2008" -xmlns:d="http://ns.adobe.com/fxg/2008/dt" -xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" -xmlns:exsl="http://exslt.org/common" -xmlns:math="http://exslt.org/math" -xmlns:libxslt="http://xmlsoft.org/XSLT/namespace" -xmlns:svg="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd" -exclude-result-prefixes="rdf xlink xs exsl libxslt" -extension-element-prefixes="math"> - -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="UTF-8" indent="yes"/> - -<!-- - // Containers // - - * Root templace - * Graphic attributes - * Groups ---> - -<!-- - // Root template // ---> -<xsl:template match="/"> - <xsl:apply-templates mode="forward" /> -</xsl:template> -<!-- - // Graphic // - First SVG element is converted to Graphic ---> -<xsl:template mode="forward" match="/*[name(.) = 'svg']" priority="1"> - <Graphic> - <xsl:attribute name="version">2.0</xsl:attribute> - <xsl:if test="@width and not(contains(@width, '%'))"> - <xsl:attribute name="viewWidth"> - <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="viewHeight"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@height" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:if test="@width and not(contains(@width, '%')) and @height and not(contains(@height, '%'))"> - <mask> - <Group> - <Rect> - <xsl:attribute name="width"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@width" /> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="height"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@height" /> - </xsl:call-template> - </xsl:attribute> - <fill> - <SolidColor color="#ffffff" alpha="1"/> - </fill> - </Rect> - </Group> - </mask> - </xsl:if> - <xsl:apply-templates mode="forward" /> - </Graphic> -</xsl:template> - -<!-- - // inner SVG elements // - Converted to groups ---> -<xsl:template mode="forward" match="*[name(.) = 'svg']"> - <Group> - <xsl:if test="@x"> - <xsl:attribute name="x"> - <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="y"> - <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 and not(contains(@width, '%')) and @height and not(contains(@height, '%'))"> - <xsl:attribute name="maskType"><xsl:value-of select="'clip'"/></xsl:attribute> - <mask> - <Group> - <Rect> - <xsl:attribute name="width"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@width" /> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="height"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@height" /> - </xsl:call-template> - </xsl:attribute> - <fill> - <SolidColor color="#ffffff" alpha="1"/> - </fill> - </Rect> - </Group> - </mask> - </xsl:if> - <xsl:apply-templates mode="forward" /> - </Group> -</xsl:template> - -<!-- - // Groups // - (including layers) - - FXG's Group doesn't support other elements attributes (such as font-size, etc.) ---> -<xsl:template mode="forward" match="*[name(.) = 'g']"> - <xsl:variable name="object"> - <Group> - <xsl:if test="@style and contains(@style, 'display:none')"> - <xsl:attribute name="Visibility">Collapsed</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="x"> - <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="y"> - <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="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <xsl:apply-templates mode="layer_blend" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="forward" select="*" /> - </Group> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Transforms // - All the matrix, translate, rotate... stuff. - * Parse objects transform - * Object transform - * Parse gradient transform - * Gradient transform - - Not supported by FXG: - * Skew transform. - * Multiple values rotation. ---> - -<!-- - // Parse object transform // ---> -<xsl:template name="parse_object_transform"> - <xsl:param name="input" /> - <xsl:choose> - <!-- Matrix transform --> - <xsl:when test="starts-with($input, 'matrix(')"> - <transform> - <Transform> - <matrix> - <Matrix> - <xsl:variable name="matrix" select="normalize-space(translate(substring-before(substring-after($input, 'matrix('), ')'), ',', ' '))" /> - <xsl:variable name="a" select="substring-before($matrix, ' ')"/> - <xsl:variable name="ra" select="substring-after($matrix, ' ')"/> - <xsl:variable name="b" select="substring-before($ra, ' ')"/> - <xsl:variable name="rb" select="substring-after($ra, ' ')"/> - <xsl:variable name="c" select="substring-before($rb, ' ')"/> - <xsl:variable name="rc" select="substring-after($rb, ' ')"/> - <xsl:variable name="d" select="substring-before($rc, ' ')"/> - <xsl:variable name="rd" select="substring-after($rc, ' ')"/> - <xsl:variable name="tx" select="substring-before($rd, ' ')"/> - <xsl:variable name="ty" select="substring-after($rd, ' ')"/> - <xsl:attribute name="a"><xsl:value-of select="$a" /></xsl:attribute> - <xsl:attribute name="b"><xsl:value-of select="$b" /></xsl:attribute> - <xsl:attribute name="c"><xsl:value-of select="$c" /></xsl:attribute> - <xsl:attribute name="d"><xsl:value-of select="$d" /></xsl:attribute> - <xsl:attribute name="tx"><xsl:value-of select='format-number($tx, "#.##")' /></xsl:attribute> - <xsl:attribute name="ty"><xsl:value-of select='format-number($ty, "#.##")' /></xsl:attribute> - </Matrix> - </matrix> - </Transform> - </transform> - </xsl:when> - - <!-- Scale transform --> - <xsl:when test="starts-with($input, 'scale(')"> - <xsl:variable name="scale" select="normalize-space(translate(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> - </xsl:when> - - <!-- Rotate transform --> - <xsl:when test="starts-with($input, 'rotate(')"> - <xsl:variable name="rotate" select="normalize-space(translate(substring-before(substring-after($input, 'rotate('), ')'), ',', ' '))" /> - <xsl:attribute name="rotation"> - <xsl:choose> - <xsl:when test="contains($rotate, ' ')"> - <xsl:value-of select="substring-before($rotate, ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$rotate" /> - </xsl:otherwise> - </xsl:choose> - </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> - </xsl:when> - - <!-- Translate transform --> - <xsl:when test="starts-with($input, 'translate(')"> - <xsl:variable name="translate" select="normalize-space(translate(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:otherwise> - <xsl:attribute name="x"> - <xsl:value-of select="$translate" /> - </xsl:attribute> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- - // Object transform // - FXG needs a separate group for each transform type in the transform attribute (scale+translate != translate+scale) ---> -<xsl:template name="object_transform"> - <xsl:param name="object" /> - <xsl:param name="transform" /> - - <xsl:variable name="values" select="normalize-space(translate($transform, ',', ' '))" /> - <xsl:choose> - <xsl:when test="contains($values, ') ')"> - <xsl:call-template name="parse_object_transform"> - <xsl:with-param name="input" select="concat(substring-before($values, ') '), ')')" /> - </xsl:call-template> - <xsl:variable name="values2" select="substring-after($values, ') ')" /> - <Group> - <xsl:choose> - <xsl:when test="contains($values2, ') ')"> - <xsl:call-template name="parse_object_transform"> - <xsl:with-param name="input" select="concat(substring-before($values2, ') '), ')')" /> - </xsl:call-template> - <xsl:variable name="values3" select="substring-after($values2, ') ')" /> - <Group> - <xsl:call-template name="parse_object_transform"> - <xsl:with-param name="input" select="concat($values3, ')')" /> - </xsl:call-template> - <xsl:copy-of select="$object" /> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="parse_object_transform"> - <xsl:with-param name="input" select="$values2" /> - </xsl:call-template> - <xsl:copy-of select="$object" /> - </xsl:otherwise> - </xsl:choose> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="parse_object_transform"> - <xsl:with-param name="input" select="$values" /> - </xsl:call-template> - <xsl:copy-of select="$object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Parse gradient transform // ---> -<xsl:template name="parse_gradient_transform"> - <xsl:param name="input" /> - <xsl:param name="type" /> - <xsl:choose> - <!-- Scale transform --> - <xsl:when test="starts-with($input, 'scale(')"> - <xsl:variable name="scale" select="normalize-space(translate(substring-before(substring-after($input, 'scale('), ')'), ',', ' '))" /> - <xsl:choose> - <xsl:when test="$type='radial'"> - <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> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="scaleX"> - <xsl:value-of select="$scale" /> - </xsl:attribute> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - - <!-- Rotate transform --> - <xsl:when test="starts-with($input, 'rotate(')"> - <xsl:variable name="rotate" select="normalize-space(translate(substring-before(substring-after($input, 'rotate('), ')'), ',', ' '))" /> - <xsl:attribute name="rotation"> - <xsl:choose> - <xsl:when test="contains($rotate, ' ')"> - <xsl:value-of select="substring-before($rotate, ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$rotate" /> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:when> - - <!-- Translate transform --> - <xsl:when test="starts-with($input, 'translate(')"> - <xsl:variable name="translate" select="normalize-space(translate(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:otherwise> - <xsl:attribute name="x"> - <xsl:value-of select="$translate" /> - </xsl:attribute> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- - // Gradient transform // - Not implemented yet - Gradient positioning and transformation are very different in FXG ---> -<xsl:template name="gradient_transform"> - <xsl:param name="transform" /> - <xsl:param name="type" /> - - <xsl:if test="contains($transform, 'translate')"> - <xsl:call-template name="parse_gradient_transform"> - <xsl:with-param name="input" select="concat('translate(', substring-before(substring-after($transform, 'translate('), ')'), ')')" /> - <xsl:with-param name="type" select="$type" /> - </xsl:call-template> - </xsl:if> -</xsl:template> - -<!-- - // Resources (defs) // - - * Resources ids - * Generic defs template - * Defs gradients - * Layers blend mode - * Generic filters template - * Filter effects - * Linked filter effects - * Linear gradients - * Radial gradients - * Gradient stops list - * Gradient stop - * Clipping ---> - -<!-- - // Resources ids // ---> -<xsl:template mode="resources" match="*"> - <!-- should be in-depth --> - <xsl:if test="ancestor::*[name(.) = 'defs']"><xsl:attribute name="id"><xsl:value-of select="@id" /></xsl:attribute></xsl:if> -</xsl:template> - -<!-- - // Generic defs template // ---> -<xsl:template mode="forward" match="defs"> -<!-- Ignoring defs, do nothing - <xsl:apply-templates mode="forward" /> ---> -</xsl:template> - -<!-- - // Defs gradients // - ignored ---> -<xsl:template mode="forward" match="*[name(.) = 'linearGradient' or name(.) = 'radialGradient']"> - -</xsl:template> - -<!-- - // Layers blend mode // - - Partial support - Looks good with normal, multiply, and darken ---> -<xsl:template mode="layer_blend" match="*"> - <xsl:if test="@inkscape:groupmode='layer' and @style and contains(@style, 'filter:url(#')"> - <xsl:variable name="id" select="substring-before(substring-after(@style, 'filter:url(#'), ')')" /> - <xsl:for-each select="//*[@id=$id]"> - <xsl:if test="name(child::node()) = 'feBlend'"> - <xsl:attribute name="blendMode"> - <xsl:value-of select="child::node()/@mode"/> - </xsl:attribute> - </xsl:if> - </xsl:for-each> - </xsl:if> -</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> - -<!-- - // GaussianBlur filter effects // - Blur values approximated with d = floor(s * 3*sqrt(2*pi)/4 + 0.5) from: - http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement - Blur quality=2 recommended by the FXG specifications: - http://opensource.adobe.com/wiki/display/flexsdk/FXG+2.0+Specification#FXG2.0Specification-FilterEffects ---> -<xsl:template mode="forward" match="*[name(.) = 'feGaussianBlur']"> - <xsl:if test="name(.)='feGaussianBlur'"> - <filters> - <BlurFilter> - <xsl:attribute name="quality">2</xsl:attribute> - <xsl:if test="@stdDeviation"> - <xsl:variable name="blur" select="normalize-space(translate(@stdDeviation, ',', ' '))" /> - <xsl:choose> - <xsl:when test="not(contains($blur, ' '))"> - <xsl:attribute name="blurX"> - <xsl:value-of select="floor($blur * 1.88 + 0.5)" /> - </xsl:attribute> - <xsl:attribute name="blurY"> - <xsl:value-of select="floor($blur * 1.88 + 0.5)" /> - </xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="blurX"> - <xsl:value-of select="floor(substring-before($blur, ' ') * 1.88 + 0.5)" /> - </xsl:attribute> - <xsl:attribute name="blurY"> - <xsl:value-of select="floor(substring-after($blur, ' ') * 1.88 + 0.5)" /> - </xsl:attribute> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </BlurFilter> - </filters> - </xsl:if> -</xsl:template> - -<!-- - // Linked filter effect // - Only supports blurs ---> -<xsl:template mode="filter_effect" match="*"> - <xsl:variable name="id"> - <xsl:choose> - <xsl:when test="@filter and starts-with(@filter, 'url(#')"> - <xsl:value-of select="substring-before(substring-after(@filter, 'url(#'), ')')" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'filter:url(#')"> - <xsl:value-of select="substring-before(substring-after(@style, 'filter:url(#'), ')')" /> - </xsl:when> - </xsl:choose> - </xsl:variable> - - <xsl:for-each select="//*[@id=$id]"> - <xsl:apply-templates mode="forward" /> - </xsl:for-each> -</xsl:template> - -<!-- - // Linear gradient // - Full conversion to FXG would require some math. ---> -<xsl:template name="linearGradient"> - <xsl:param name="id" /> - <xsl:for-each select="//*[@id=$id]"> - <xsl:if test="@id"> - <xsl:attribute name="id"> - <xsl:value-of select="@id" /> - </xsl:attribute> - </xsl:if> - <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="@color-interpolation"> - <xsl:attribute name="interpolationMethod"> - <xsl:choose> - <xsl:when test="@color-interpolation = 'linearRGB'">linearRGB</xsl:when> - <xsl:otherwise>rgb</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <xsl:if test="@x1 and @x2 and @y1 and @y2 and function-available('math:atan')"> - <xsl:attribute name="rotation"> - <xsl:value-of select="57.3 * math:atan((@y2 - @y1) div (@x2 - @x1))" /> - </xsl:attribute> - </xsl:if> - <xsl:if test="@gradientTransform"> - <xsl:call-template name="gradient_transform"> - <xsl:with-param name="transform" select="@gradientTransform" /> - <xsl:with-param name="type" select="linear" /> - </xsl:call-template> - </xsl:if> - <xsl:choose> - <xsl:when test="@xlink:href"> - <xsl:variable name="reference_id" select="@xlink:href" /> - <xsl:call-template name="gradientStops" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-after($reference_id, '#')" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise> - </xsl:choose> - </xsl:for-each> -</xsl:template> - -<!-- - // Radial gradient // - - Full conversion to FXG would require some math. ---> -<xsl:template name="radialGradient"> - <xsl:param name="id" /> - <xsl:for-each select="//*[@id=$id]"> - <xsl:if test="@id"> - <xsl:attribute name="id"> - <xsl:value-of select="@id" /> - </xsl:attribute> - </xsl:if> - <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="@color-interpolation"> - <xsl:attribute name="interpolationMethod"> - <xsl:choose> - <xsl:when test="@color-interpolation = 'linearRGB'">linearRGB</xsl:when> - <xsl:otherwise>rgb</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <xsl:if test="@gradientTransform"> - <xsl:call-template name="gradient_transform"> - <xsl:with-param name="transform" select="@gradientTransform" /> - <xsl:with-param name="type" select="radial" /> - </xsl:call-template> - </xsl:if> - <xsl:choose> - <xsl:when test="@xlink:href"> - <xsl:variable name="reference_id" select="@xlink:href" /> - <xsl:call-template name="gradientStops" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-after($reference_id, '#')" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise> - </xsl:choose> - </xsl:for-each> -</xsl:template> - -<!-- - // Gradient stops list // - - TODO: Find a way to test the existence of the node-set ---> -<xsl:template name="gradientStops"> - <xsl:param name="id" /> - <xsl:variable name="stops"> - <xsl:for-each select="//*[@id=$id]"> - <xsl:apply-templates mode="forward" /> - </xsl:for-each> - </xsl:variable> - <xsl:choose> - <xsl:when test="not($stops)"> - <GradientEntry> - <xsl:attribute name="alpha">0</xsl:attribute> - </GradientEntry> - </xsl:when> - <xsl:otherwise><xsl:copy-of select="$stops" /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Gradient stop // ---> -<xsl:template mode="forward" match="*[name(.) = 'stop']"> - <GradientEntry> - <!--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" /> - </GradientEntry> -</xsl:template> - -<!-- - // Clipping and masking// ---> -<xsl:template mode="clip" match="*"> - <xsl:param name="object" /> - <xsl:param name="clip_type" /> - - <xsl:choose> - <xsl:when test="$clip_type='clip' and @clip-path and contains(@clip-path, 'url')"> - <Group> - <xsl:attribute name="maskType"><xsl:value-of select="'clip'"/></xsl:attribute> - <mask> - <Group> - <xsl:variable name="clip_id" select="substring-before(substring-after(@clip-path, 'url(#'), ')')"/> - <xsl:for-each select="//*[@id=$clip_id]"> - <xsl:if test="not(@clipPathUnits) or @clipPathUnits != 'objectBoundingBox'"> - <xsl:apply-templates mode="forward" /> - </xsl:if> - </xsl:for-each> - </Group> - </mask> - <xsl:copy-of select="$object"/> - </Group> - </xsl:when> - <xsl:when test="$clip_type='mask' and @mask and contains(@mask, 'url')"> - <Group> - <xsl:attribute name="maskType"><xsl:value-of select="'alpha'"/></xsl:attribute> - <mask> - <Group> - <xsl:variable name="mask_id" select="substring-before(substring-after(@mask, 'url(#'), ')')"/> - <xsl:for-each select="//*[@id=$mask_id]"> - <xsl:if test="not(@maskUnits) or @maskUnits != 'objectBoundingBox'"> - <xsl:apply-templates mode="forward" /> - </xsl:if> - </xsl:for-each> - </Group> - </mask> - <xsl:copy-of select="$object"/> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Misc templates // - - * Id converter - * Decimal to hexadecimal converter - * Unit to pixel converter - * Switch - * Unknows tags - * Object description (not supported) - * Title and description (not supported) - * Symbols (not supported) - * Use (not supported) - * RDF and foreign objects (not supported) - * Misc ignored stuff (markers, patterns, styles) ---> - -<!-- - // Id converter // - Removes "-" from the original id - (Not sure FXG really needs it) ---> -<xsl:template mode="id" match="*"> - <xsl:if test="@id"> - <xsl:attribute name="id"><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. - em, ex and % not implemented ---> -<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.333333)" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'pc')"> - <xsl:value-of select="round(translate($convert_value, 'pc', '') * 16)" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'mm')"> - <xsl:value-of select="round(translate($convert_value, 'mm', '') * 3.779527)" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'cm')"> - <xsl:value-of select="round(translate($convert_value, 'cm', '') * 37.79527)" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'in')"> - <xsl:value-of select="round(translate($convert_value, 'in', '') * 96)" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'ft')"> - <xsl:value-of select="round(translate($convert_value, 'ft', '') * 1152)" /> - </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> - -<!-- - // Switch // ---> -<xsl:template mode="forward" match="*[name(.) = 'switch']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<!-- - // Unknown tags // - With generic and mode="forward" templates ---> -<xsl:template match="*"> - <xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment> -</xsl:template> - -<xsl:template mode="forward" match="*"> - <xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment> -</xsl:template> - -<!-- - // Object description // ---> -<xsl:template mode="desc" match="*"> - -</xsl:template> - -<!-- - // Title and description // - 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> - -<!-- - // Symbols // ---> -<xsl:template mode="forward" match="*[name(.) = 'symbol']"> - -</xsl:template> - -<!-- - // Use // - Could be implemented via libraries - (but since it is not supported by Inkscape, not implemented yet) ---> -<xsl:template mode="forward" match="*[name(.) = 'use']"> - -</xsl:template> - -<!-- - // RDF and foreign objects // ---> -<xsl:template mode="forward" match="rdf:RDF | *[name(.) = 'foreignObject']"> - -</xsl:template> - -<!-- - // Misc ignored stuff (markers, patterns, styles) // ---> -<xsl:template mode="forward" match="*[name(.) = 'marker' or name(.) = 'pattern' or name(.) = 'style']"> - -</xsl:template> - -<!-- - // Colors and patterns // - - * Generic color template - * Object opacity - * Fill - * Fill opacity - * Fill rule - * Generic fill template - * Stroke - * Stroke opacity - * Generic stroke template - * Stroke width - * Stroke mitterlimit - * Stroke dasharray (not supported in FXG) - * Stroke dashoffset (not supported in FXG) - * Linejoin SVG to FxG converter - * Stroke linejoin - * Linecap SVG to FXG converter - * Stroke linecap - * Gradient stop - * Gradient stop opacity - * Gradient stop offset ---> - -<!-- - // Generic color template // ---> -<xsl:template name="template_color"> - <xsl:param name="colorspec" /> - <xsl:choose> - <xsl:when test="starts-with($colorspec, 'rgb(') and not(contains($colorspec , '%'))"> - <xsl:value-of select="'#'" /> - <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: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: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: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> - -<!-- - // Object opacity // ---> -<xsl:template mode="object_opacity" match="*"> - <xsl:if test="@opacity or (@style and (contains(@style, ';opacity:') or starts-with(@style, 'opacity:')))"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@opacity"> - <xsl:value-of select="@opacity" /> - </xsl:when> - <xsl:when test="@style and contains(@style, ';opacity:')"> - <xsl:variable name="Opacity" select="substring-after(@style, ';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="@style and starts-with(@style, 'opacity:')"> - <xsl:variable name="Opacity" select="substring-after(@style, '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="object_opacity" select="parent::*" /> - </xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:attribute name="alpha"> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Fill // ---> -<xsl:template mode="fill" match="*"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@fill"> - <xsl:value-of select="@fill" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill:')"> - <xsl:variable name="Fill" select="normalize-space(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:variable> - <xsl:if test="$value"> - <!-- Removes unwanted characters in the color link (TODO: export to a specific template)--> - <xsl:value-of select="normalize-space(translate($value, '"', ''))" /> - </xsl:if> -</xsl:template> - -<!-- - // Fill opacity // ---> -<xsl:template mode="fill_opacity" match="*"> - <xsl:variable name="value"> - <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:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </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:if test="@fill-rule = 'nonzero'"> - <xsl:attribute name="winding">nonZero</xsl:attribute> - </xsl:if> - <xsl:if test="@fill-rule = 'evenodd'"> - <xsl:attribute name="winding">evenOdd</xsl:attribute> - </xsl:if> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill-rule:')"> - <xsl:variable name="FillRule" select="normalize-space(substring-after(@style, 'fill-rule:'))" /> - <xsl:choose> - <xsl:when test="contains($FillRule, ';')"> - <xsl:if test="substring-before($FillRule, ';') = 'nonzero'"> - <xsl:attribute name="winding">nonZero</xsl:attribute> - </xsl:if> - <xsl:if test="substring-before($FillRule, ';') = 'evenodd'"> - <xsl:attribute name="winding">evenOdd</xsl:attribute> - </xsl:if> - </xsl:when> - <xsl:when test="$FillRule = 'nonzero'"> - <xsl:attribute name="winding">nonZero</xsl:attribute> - </xsl:when> - <xsl:when test=" $FillRule = 'evenodd'"> - <xsl:attribute name="winding">evenOdd</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="winding">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:choose> - <xsl:when test="$fill != '' and $fill != 'none' and not(starts-with($fill, 'url(#'))"> - <!-- Solid color --> - <fill> - <SolidColor> - <xsl:attribute name="color"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="alpha"> - <xsl:value-of select="$fill_opacity" /> - </xsl:attribute> - </SolidColor> - </fill> - </xsl:when> - <!-- Gradients --> - <xsl:when test="starts-with($fill, 'url(#')"> - <xsl:for-each select="//*[@id=substring-before(substring-after($fill, 'url(#'), ')')]"> - <xsl:if test="name(.) = 'linearGradient'"> - <fill> - <LinearGradient> - <xsl:call-template name="linearGradient" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-before(substring-after($fill, 'url(#'), ')')" /> - </xsl:with-param> - </xsl:call-template> - </LinearGradient> - </fill> - </xsl:if> - <xsl:if test="name(.) = 'radialGradient'"> - <fill> - <RadialGradient> - <xsl:call-template name="radialGradient" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-before(substring-after($fill, 'url(#'), ')')" /> - </xsl:with-param> - </xsl:call-template> - </RadialGradient> - </fill> - </xsl:if> - </xsl:for-each> - </xsl:when> - <xsl:when test="$fill = 'none'"> - </xsl:when> - <xsl:otherwise> - <fill> - <SolidColor color="#ffffff" alpha="1"/> - </fill> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Stroke // ---> -<xsl:template mode="stroke" match="*"> - <xsl:choose> - <xsl:when test="@stroke"> - <xsl:value-of select="@stroke" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke:')"> - <xsl:variable name="Stroke" select="normalize-space(substring-after(@style, 'stroke:'))" /> - <xsl:choose> - <xsl:when test="contains($Stroke, ';')"> - <xsl:value-of select="substring-before($Stroke, ';')" /> - </xsl:when> - <xsl:when test="$Stroke"> - <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:variable name="value"> - <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:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Generic stroke template // - - Not supported in FXG: - * stroke-dasharray - * stroke-dashoffset - - --> -<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:variable name="stroke_width"><xsl:apply-templates mode="stroke_width" select="." /></xsl:variable> - <xsl:variable name="stroke_miterlimit"><xsl:apply-templates mode="stroke_miterlimit" select="." /></xsl:variable> - <xsl:variable name="stroke_linejoin"><xsl:apply-templates mode="stroke_linejoin" select="." /></xsl:variable> - <xsl:variable name="stroke_linecap"><xsl:apply-templates mode="stroke_linecap" select="." /></xsl:variable> - - <!-- Solid color --> - <xsl:if test="$stroke != '' and $stroke != 'none' and not(starts-with($stroke, 'url(#'))"> - <stroke> - <SolidColorStroke> - <xsl:attribute name="color"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$stroke" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="alpha"> - <xsl:value-of select="$stroke_opacity" /> - </xsl:attribute> - <xsl:attribute name="weight"> - <xsl:value-of select="$stroke_width" /> - </xsl:attribute> - <xsl:if test="$stroke_miterlimit != ''"> - <xsl:attribute name="miterLimit"> - <xsl:value-of select="$stroke_miterlimit" /> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="joints"> - <xsl:value-of select="$stroke_linejoin" /> - </xsl:attribute> - <xsl:attribute name="caps"> - <xsl:value-of select="$stroke_linecap" /> - </xsl:attribute> - </SolidColorStroke> - </stroke> - </xsl:if> - - <!-- Gradients --> - <xsl:if test="starts-with($stroke, 'url(#')"> - <xsl:for-each select="//*[@id=substring-before(substring-after($stroke, 'url(#'), ')')]"> - <xsl:if test="name(.) = 'linearGradient'"> - <stroke> - <LinearGradientStroke> - <xsl:attribute name="weight"> - <xsl:value-of select="$stroke_width" /> - </xsl:attribute> - <xsl:if test="$stroke_miterlimit != ''"> - <xsl:attribute name="miterLimit"> - <xsl:value-of select="$stroke_miterlimit" /> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="joints"> - <xsl:value-of select="$stroke_linejoin" /> - </xsl:attribute> - <xsl:attribute name="caps"> - <xsl:value-of select="$stroke_linecap" /> - </xsl:attribute> - <xsl:call-template name="linearGradient" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-before(substring-after($stroke, 'url(#'), ')')" /> - </xsl:with-param> - </xsl:call-template> - </LinearGradientStroke> - </stroke> - </xsl:if> - <xsl:if test="name(.) = 'radialGradient'"> - <stroke> - <RadialGradientStroke> - <xsl:attribute name="weight"> - <xsl:value-of select="$stroke_width" /> - </xsl:attribute> - <xsl:if test="$stroke_miterlimit != ''"> - <xsl:attribute name="miterLimit"> - <xsl:value-of select="$stroke_miterlimit" /> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="joints"> - <xsl:value-of select="$stroke_linejoin" /> - </xsl:attribute> - <xsl:attribute name="caps"> - <xsl:value-of select="$stroke_linecap" /> - </xsl:attribute> - <xsl:call-template name="radialGradient" > - <xsl:with-param name="id"> - <xsl:value-of select="substring-before(substring-after($stroke, 'url(#'), ')')" /> - </xsl:with-param> - </xsl:call-template> - </RadialGradientStroke> - </stroke> - </xsl:if> - </xsl:for-each> - </xsl:if> -</xsl:template> - -<!-- - // Stroke width // ---> -<xsl:template mode="stroke_width" match="*"> - <xsl:choose> - <xsl:when test="@stroke-width"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value"> - <xsl:value-of select="@stroke-width" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-width:')"> - <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:when> - <xsl:when test="name(..) = 'g' or name(..) = 'svg'"> - <xsl:apply-templates mode="stroke_width" select="parent::*"/> - </xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Stroke miterlimit // - - Probably not calculated the same way in SVG and FXG (same value but different result) ---> -<xsl:template mode="stroke_miterlimit" match="*"> - <xsl:choose> - <xsl:when test="@stroke-miterlimit"> - <xsl:value-of select="@stroke-miterlimit" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-miterlimit:')"> - <xsl:variable name="miterLimit" select="substring-after(@style, 'stroke-miterlimit:')" /> - <xsl:choose> - <xsl:when test="contains($miterLimit, ';')"> - <xsl:value-of select="substring-before($miterLimit, ';')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$miterLimit" /> - </xsl:otherwise> - </xsl:choose> - </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 // - !! Not supported !! ---> -<xsl:template mode="stroke_dasharray" match="*"> - <xsl:comment>FXG does not support dasharrays</xsl:comment> -</xsl:template> - -<!-- - // Stroke dashoffset // - !! Not supported !! ---> -<xsl:template mode="stroke_dashoffset" match="*"> - <xsl:comment>FXG does not support dashoffsets</xsl:comment> -</xsl:template> - -<!-- - // Linejoin SVG to FXG converter // ---> -<xsl:template name="linejoin_svg_to_fxg"> - <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-linejoin"> - <xsl:call-template name="linejoin_svg_to_fxg"> - <xsl:with-param name="linejoin"> - <xsl:value-of select="@stroke-linejoin" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-linejoin:')"> - <xsl:variable name="joints" select="substring-after(@style, 'stroke-linejoin:')" /> - <xsl:choose> - <xsl:when test="contains($joints, ';')"> - <xsl:call-template name="linejoin_svg_to_fxg"> - <xsl:with-param name="linejoin"> - <xsl:value-of select="substring-before($joints, ';')" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="linejoin_svg_to_fxg"> - <xsl:with-param name="linejoin"> - <xsl:value-of select="$joints" /> - </xsl:with-param> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="name(..) = 'g' or name(..) = 'svg'"> - <xsl:apply-templates mode="stroke_linejoin" select="parent::*"/> - </xsl:when> - <xsl:otherwise>miter</xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Linecap SVG to FXG converter // - - Not supported in FXG: - * butt linecap ---> -<xsl:template name="linecap_svg_to_fxg"> - <xsl:param name="linecap" /> - <xsl:choose> - <xsl:when test="$linecap = 'round'">round</xsl:when> - <xsl:when test="$linecap = 'square'">square</xsl:when> - <xsl:when test="$linecap = 'butt'">round</xsl:when> - <xsl:otherwise>none</xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Stroke linecap // ---> -<xsl:template mode="stroke_linecap" match="*"> - <xsl:choose> - <xsl:when test="@stroke-linecap"> - <xsl:call-template name="linecap_svg_to_fxg"> - <xsl:with-param name="linecap"> - <xsl:value-of select="@stroke-linecap" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-linecap:')"> - <xsl:variable name="caps" select="substring-after(@style, 'stroke-linecap:')" /> - <xsl:choose> - <xsl:when test="contains($caps, ';')"> - <xsl:call-template name="linecap_svg_to_fxg"> - <xsl:with-param name="linecap"> - <xsl:value-of select="substring-before($caps, ';')" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="linecap_svg_to_fxg"> - <xsl:with-param name="linecap"> - <xsl:value-of select="$caps" /> - </xsl:with-param> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:when test="name(..) = 'g' or name(..) = 'svg'"> - <xsl:apply-templates mode="stroke_linecap" select="parent::*"/> - </xsl:when> - <xsl:otherwise>none</xsl:otherwise> - </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="normalize-space(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:value-of select="$stopcolor" /> - </xsl:attribute> - <xsl:if test="$Opacity != ''"> - <xsl:attribute name="alpha"> - <xsl:value-of select="$Opacity" /> - </xsl:attribute> - </xsl:if> -</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="ratio"> - <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="ratio"> - <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> - -<!-- - // Text specific templates // - - * Text tspan - * Text flowPara - * Text flowRegion (text frame) - * Get font size - * Font size - * Font weight - * Font family - * Font style - * Baseline shift - * Line height - * Writing mode - * Text decoration - * Text fill - * Text direction - * Text size - * Text position - * Text object - * FlowRoot object ---> - - <!-- - // Text span // - SVG: tspan, flowSpan, FXG: span - - Not supported in FXG: - * span position ---> -<xsl:template mode="forward" match="*[name(.) = 'tspan' or name(.) = 'flowSpan']"> - <span> - <xsl:if test="../@xml:space='preserve'"> - <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute> - </xsl:if> - <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="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')"> - <xsl:attribute name="color"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="textAlpha"> - <xsl:value-of select="$fill_opacity" /> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="line_height" select="." /> - <xsl:apply-templates mode="baseline_shift" select="." /> - - <xsl:if test="text()"> - <xsl:value-of select="text()" /> - </xsl:if> - </span> -</xsl:template> - - <!-- - // Text flowPara // - SVG: flowPara, flowDiv FXG: p - - Not supported in FXG: - * paragraph position ---> -<xsl:template mode="forward" match="*[name(.) = 'flowPara' or name(.) = 'flowDiv']"> - <p> - <xsl:if test="../@xml:space='preserve'"> - <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute> - </xsl:if> - <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="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')"> - <xsl:attribute name="color"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="textAlpha"> - <xsl:value-of select="$fill_opacity" /> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="line_height" select="." /> - <xsl:apply-templates mode="baseline_shift" select="." /> - - <xsl:choose> - <xsl:when test="*[name(.) = 'flowSpan']/text()"> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="@xml:space='preserve'"> - <xsl:copy-of select="translate(text(), '	

', ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="normalize-space(translate(text(), '	

', ' '))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </p> -</xsl:template> - - - <!-- - // Text flowRegion // ---> -<xsl:template mode="flow_region" match="*"> - <xsl:apply-templates mode="text_size" select="." /> - <xsl:apply-templates mode="text_position" select="." /> -</xsl:template> - -<!-- - // Get text font size // ---> -<xsl:template mode="get_font_size" match="*"> - <xsl:choose> - <xsl:when test="@font-size"> - <xsl:value-of select="@font-size" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'font-size:')"> - <xsl:variable name="font_size" select="normalize-space(substring-after(@style, 'font-size:'))" /> - <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:when> - <xsl:when test="name(..) = 'g' or name(..) = 'svg'"> - <xsl:apply-templates mode="get_font_size" select="parent::*"/> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- - // Text font size // - SVG: font-size, FXG: fontSize ---> -<xsl:template mode="font_size" match="*"> - <xsl:variable name="value"> - <xsl:apply-templates mode="get_font_size" select="." /> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="fontSize"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text font weight // - SVG: font-weight, FXG: fontWeight ---> -<xsl:template mode="font_weight" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-weight"> - <xsl:value-of select="@font-weight" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-weight:')"> - <xsl:variable name="font_weight" select="normalize-space(substring-after(@style, 'font-weight:'))" /> - <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:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="fontWeight"> - <xsl:choose> - <xsl:when test="$value='normal' or $value='bold'"> - <xsl:value-of select="$value" /> - </xsl:when> - <xsl:when test="$value < 500 or $value = 'lighter'">normal</xsl:when> - <xsl:when test="$value > 499 or $value = 'bolder'">bold</xsl:when> - <xsl:otherwise>normal</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text font family // - SVG: font-family, FXG: fontFamily ---> -<xsl:template mode="font_family" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-family"> - <xsl:value-of select="translate(@font-family, "'", '')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-family:')"> - <xsl:variable name="font_family" select="normalize-space(substring-after(@style, 'font-family:'))" /> - <xsl:choose> - <xsl:when test="contains($font_family, ';')"> - <xsl:value-of select="translate(substring-before($font_family, ';'), "'", '')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="translate($font_family, "'", '')" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="fontFamily"> - <xsl:choose> - <xsl:when test="$value='Sans'">Arial</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text font style // - SVG: font-style, FXG: fontStyle ---> -<xsl:template mode="font_style" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-style"> - <xsl:value-of select="@font-style" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-style:')"> - <xsl:variable name="font_style" select="normalize-space(substring-after(@style, 'font-style:'))" /> - <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:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="fontStyle"> - <xsl:value-of select="$value" /> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text baseline shift // - SVG: baseline-shift, FXG: baselineShift ---> -<xsl:template mode="baseline_shift" match="*"> - <xsl:variable name="value"> - <xsl:if test="@baseline-shift"> - <xsl:value-of select="@baseline-shift" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'baseline-shift:') and not(contains(substring-after(@style, 'baseline-shift:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'baseline-shift:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'baseline-shift:') and contains(substring-after(@style, 'baseline-shift:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'baseline-shift:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="baselineShift"> - <xsl:choose> - <xsl:when test="$value='baseline'">0</xsl:when> - <xsl:when test="$value='super'">superscript</xsl:when> - <xsl:when test="$value='sub'">subscript</xsl:when> - <xsl:when test="translate($value, '%', '') < -1000">-1000</xsl:when> - <xsl:when test="translate($value, '%', '') > 1000">1000</xsl:when> - <xsl:otherwise> - <xsl:value-of select="translate($value, '%', '')" /> - </xsl:otherwise> - </xsl:choose> - <xsl:if test="contains($value, '%')">%</xsl:if> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text line height // - SVG: line-height, FXG: lineHeight ---> -<xsl:template mode="line_height" match="*"> - <xsl:variable name="value"> - <xsl:if test="@line-height"> - <xsl:value-of select="@line-height" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'line-height:')"> - <xsl:variable name="line_height" select="normalize-space(substring-after(@style, 'line-height:'))" /> - <xsl:choose> - <xsl:when test="contains($line_height, ';')"> - <xsl:value-of select="substring-before($line_height, ';')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$line_height" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="lineHeight"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text writing mode // - SVG: writing-mode, FXG: blockProgression - - Values inverted in FXG... ---> -<xsl:template mode="writing_mode" match="*"> - <xsl:variable name="value"> - <xsl:if test="@writing-mode"> - <xsl:value-of select="@writing-mode" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'writing-mode:') and not(contains(substring-after(@style, 'writing-mode:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'writing-mode:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'writing-mode:') and contains(substring-after(@style, 'writing-mode:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'writing-mode:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="blockProgression"> - <xsl:choose> - <xsl:when test="$value='tb'">rl</xsl:when> - <xsl:otherwise>tb</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:if test="$value='tb'"> - <xsl:attribute name="textRotation">rotate270</xsl:attribute> - </xsl:if> - </xsl:if> -</xsl:template> - -<!-- - // Text decoration // - SVG: text-decoration, FXG: textDecoration, lineThrough ---> -<xsl:template mode="text_decoration" match="*"> - <xsl:variable name="value"> - <xsl:if test="@text-decoration"> - <xsl:value-of select="@text-decoration" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'text-decoration:') and not(contains(substring-after(@style, 'text-decoration:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'text-decoration:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'text-decoration:') and contains(substring-after(@style, 'text-decoration:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'text-decoration:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:choose> - <xsl:when test="$value='underline'"> - <xsl:attribute name="textDecoration">underline</xsl:attribute> - </xsl:when> - <xsl:when test="$value='line-through'"> - <xsl:attribute name="lineThrough">true</xsl:attribute> - </xsl:when> - </xsl:choose> - </xsl:if> -</xsl:template> - -<!-- - // Text fill // - SVG: fill, fill-opacity, FXG: color, textAlpha ---> -<xsl:template mode="text_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="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')"> - <xsl:attribute name="color"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - <xsl:attribute name="textAlpha"> - <xsl:value-of select="$fill_opacity" /> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text direction // - SVG: direction, unicode-bidi, FXG: direction ---> -<xsl:template mode="direction" match="*"> - <xsl:variable name="value"> - <xsl:if test="@direction"> - <xsl:value-of select="@direction" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'direction:') and not(contains(substring-after(@style, 'direction:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'direction:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'direction:') and contains(substring-after(@style, 'direction:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'direction:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:variable name="bidi"> - <xsl:if test="@unicode-bidi"> - <xsl:value-of select="@unicode-bidi" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'unicode-bidi:') and not(contains(substring-after(@style, 'unicode-bidi:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'unicode-bidi:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'unicode-bidi:') and contains(substring-after(@style, 'unicode-bidi:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'unicode-bidi:'), ';')" /> - </xsl:if> - </xsl:variable> - - <xsl:if test="$value != '' and ($bidi='embed' or $bidi='bidi-override')"> - <xsl:attribute name="direction"> - <xsl:choose> - <xsl:when test="$value='ltr'">ltr</xsl:when> - <xsl:when test="$value='rtl'">rtl</xsl:when> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - - <!-- - // Text size // ---> -<xsl:template mode="text_size" match="*"> - <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:template> - - <!-- - // Text position // ---> -<xsl:template mode="text_position" match="*"> - <!-- Keep the first x value only --> - <xsl:if test="@x"> - <xsl:attribute name="x"> - <xsl:choose> - <xsl:when test="contains(@x, ' ')"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="substring-before(@x, ' ')" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <!-- Keep the first y value only --> - <xsl:if test="@y"> - <xsl:attribute name="y"> - <xsl:choose> - <xsl:when test="contains(@y, ' ')"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="substring-before(@y, ' ')" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - - -<!-- - // Text objects // - SVG: text, FXG: RichText - - Not supported by FXG: - * Generic fonts. - * Embedded fonts (in defs). - * Character rotation. - * Character positioning (x and y). - * Text-anchor. - * Text stroke. - - Partial support: - * Text rotation (0, 90, 180 and 270 degrees only) -> not implemented. - * Font weight (normal and bold only) -> values under 500 are considered normal, the others bold. - * Whitespace handling, issues with xml:whitespace='preserve'. ---> -<xsl:template mode="forward" match="*[name(.) = 'text']"> - <xsl:variable name="object"> - <RichText> - <!-- Force default baseline to "ascent" --> - <xsl:attribute name="alignmentBaseline">ascent</xsl:attribute> - - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="line_height" select="." /> - <xsl:apply-templates mode="text_size" select="." /> - <xsl:apply-templates mode="text_position" select="." /> - <xsl:apply-templates mode="direction" select="." /> - <xsl:apply-templates mode="writing_mode" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <xsl:if test="not(*[name(.) = 'tspan']/text())"> - <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute> - </xsl:if> - - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <!--xsl:apply-templates mode="forward" /--> - <content> - <xsl:choose> - <xsl:when test="*[name(.) = 'tspan']/text()"> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="@xml:space='preserve'"> - <xsl:copy-of select="translate(text(), '	

', ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="normalize-space(translate(text(), '	

', ' '))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </content> - </RichText> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - - <!-- - // FlowRoot objects // - SVG: flowRoot, FXG: RichText - - Not supported by FXG: - * See text objects ---> -<xsl:template mode="forward" match="*[name(.) = 'flowRoot']"> - <xsl:variable name="object"> - <RichText> - <!-- Force default baseline to "ascent" --> - <xsl:attribute name="alignmentBaseline">ascent</xsl:attribute> - - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="line_height" select="." /> - <xsl:apply-templates mode="direction" select="." /> - <xsl:apply-templates mode="writing_mode" select="." /> - <xsl:apply-templates mode="id" select="." /> - <xsl:apply-templates mode="flow_region" select="*[name(.) = 'flowRegion']/child::node()" /> - - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <content> - <xsl:choose> - <xsl:when test="*[name(.) = 'flowPara' or name(.) = 'flowDiv']/text()"> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="@xml:space='preserve'"> - <xsl:copy-of select="translate(text(), '	

', ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="normalize-space(translate(text(), '	

', ' '))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </content> - </RichText> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Shapes // - - * Lines - * Rectangle - * Path - * Ellipse - * Circle - * Image - * Polygon (not supported) - * Polyline (not supported) ---> - -<!-- - // Line object // - SVG: line, FXG: Line ---> -<xsl:template mode="forward" match="*[name(.) = 'line']"> - <xsl:variable name="object"> - <Line> - <xsl:if test="@x1"> - <xsl:attribute name="xFrom"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x1" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:if test="@y1"> - <xsl:attribute name="yFrom"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y1" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:if test="@x2"> - <xsl:attribute name="xTo"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x2" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:if test="@y2"> - <xsl:attribute name="yTo"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y2" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <xsl:apply-templates mode="template_fill" select="." /> - <xsl:apply-templates mode="template_stroke" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <xsl:apply-templates mode="forward" /> - </Line> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Rectangle object // - SVG: rect, FXG: Rect ---> -<xsl:template mode="forward" match="*[name(.) = 'rect']"> - <xsl:variable name="object"> - <Rect> - <xsl:if test="@x"> - <xsl:attribute name="x"> - <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="y"> - <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="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <xsl:apply-templates mode="template_fill" select="." /> - <xsl:apply-templates mode="template_stroke" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <!-- <xsl:apply-templates mode="resources" select="." /> --> - <xsl:apply-templates mode="desc" select="." /> - - <xsl:apply-templates mode="forward" /> - </Rect> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Path // - SVG: path, FXG: Path - - Not supported by FXG: - * elliptical arc curve commands (workaround: convert to path first) - TODO: - * Implement an arc to curve convertor ---> -<xsl:template mode="forward" match="*[name(.) = 'path']"> - <xsl:variable name="object"> - <Path> - <!-- Path element --> - <!-- Exclude arcs in order to prevent the mxml compiler from failing --> - <xsl:if test="@d and not(contains(@d, 'a') or contains(@d, 'A'))"> - <xsl:attribute name="data"> - <xsl:value-of select="normalize-space(translate(@d , ',', ' '))" /> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="fill_rule" select="." /> - <xsl:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <!-- Child elements --> - <xsl:apply-templates mode="template_fill" select="." /> - <xsl:apply-templates mode="template_stroke" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <xsl:apply-templates mode="forward" /> - </Path> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> - <xsl:if test="contains(@d, 'a') or contains(@d, 'A')"> - <xsl:comment><xsl:value-of select="'Elliptic arc command in path data not supported, please convert to path (arcs are thus converted to curves) before exporting.'" /></xsl:comment> - </xsl:if> -</xsl:template> - -<!-- - // Ellipse object // - SVG: ellipse, FXG: Ellipse ---> -<xsl:template mode="forward" match="*[name(.) = 'ellipse']"> - <xsl:variable name="object"> - <Ellipse> - <xsl:variable name="cx"> - <xsl:choose> - <xsl:when test="@cx"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@cx" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="cy"> - <xsl:choose> - <xsl:when test="@cy"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@cy" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="rx"> - <xsl:choose> - <xsl:when test="@rx"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@rx" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="ry"> - <xsl:choose> - <xsl:when test="@ry"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@ry" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$rx != 0"> - <xsl:attribute name="x"> - <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:when> - <xsl:otherwise> - <xsl:attribute name="x"> - <xsl:value-of select='format-number($cx, "#.#")' /> - </xsl:attribute> - <xsl:attribute name="width">0</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:choose> - <xsl:when test="$ry != 0"> - <xsl:attribute name="y"> - <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:when> - <xsl:otherwise> - <xsl:attribute name="y"> - <xsl:value-of select='format-number($cy, "#.#")' /> - </xsl:attribute> - <xsl:attribute name="height">0</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <!-- Child elements --> - <xsl:apply-templates mode="template_fill" select="." /> - <xsl:apply-templates mode="template_stroke" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <xsl:apply-templates mode="forward" /> - </Ellipse> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Circle object // - SVG: circle, FXG: Ellipse ---> -<xsl:template mode="forward" match="*[name(.) = 'circle']"> - <xsl:variable name="object"> - <Ellipse> - <xsl:variable name="cx"> - <xsl:choose> - <xsl:when test="@cx"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@cx" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="cy"> - <xsl:choose> - <xsl:when test="@cy"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@cy" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="r"> - <xsl:choose> - <xsl:when test="@r"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@r" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$r != 0"> - <xsl:attribute name="x"> - <xsl:value-of select='format-number($cx - $r, "#.#")' /> - </xsl:attribute> - <xsl:attribute name="y"> - <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:when> - <xsl:otherwise> - <xsl:attribute name="x"> - <xsl:value-of select='format-number($cx, "#.#")' /> - </xsl:attribute> - <xsl:attribute name="y"> - <xsl:value-of select='format-number($cy, "#.#")' /> - </xsl:attribute> - <xsl:attribute name="width">0</xsl:attribute> - <xsl:attribute name="height">0</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <!-- Child elements --> - <xsl:apply-templates mode="template_fill" select="." /> - <xsl:apply-templates mode="template_stroke" select="." /> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - - <xsl:apply-templates mode="forward" /> - </Ellipse> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Image objects // - SVG: image, FXG: Rect+BitmapFill - - Not supported by FXG: - * Embedded images (base64). - * Preserve ratio. ---> -<xsl:template mode="forward" match="*[name(.) = 'image']"> - <xsl:variable name="object"> - <Rect> - <xsl:if test="@x"> - <xsl:attribute name="x"> - <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="y"> - <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:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="id" select="." /> - - <xsl:apply-templates mode="desc" select="." /> - - <xsl:if test="@xlink:href"> - <fill> - <BitmapFill> - <xsl:attribute name="source">@Embed('<xsl:value-of select="@xlink:href"/>')</xsl:attribute> - </BitmapFill> - </fill> - </xsl:if> - - <xsl:apply-templates mode="forward" /> - </Rect> - </xsl:variable> - - <xsl:variable name="clipped_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$object" /> - <xsl:with-param name="clip_type" select="'clip'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:variable name="masked_object"> - <xsl:apply-templates mode="clip" select="." > - <xsl:with-param name="object" select="$clipped_object" /> - <xsl:with-param name="clip_type" select="'mask'" /> - </xsl:apply-templates> - </xsl:variable> - - <xsl:choose> - <xsl:when test="@transform"> - <Group> - <xsl:call-template name="object_transform"> - <xsl:with-param name="object" select="$masked_object" /> - <xsl:with-param name="transform" select="@transform" /> - </xsl:call-template> - </Group> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$masked_object" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Polygon object // - !! Not supported !! ---> -<xsl:template mode="forward" match="*[name(.) = 'polygon']"> - <xsl:comment>FXG does not support polygons</xsl:comment> -</xsl:template> - -<!-- - // Polyline object // - !! Not supported !! ---> -<xsl:template mode="forward" match="*[name(.) = 'polyline']"> - <xsl:comment>FXG does not support polylines</xsl:comment> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/svg2xaml.inx b/share/extensions/svg2xaml.inx deleted file mode 100644 index 74b8f731a..000000000 --- a/share/extensions/svg2xaml.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>XAML Output</_name> - <id>org.inkscape.output.xaml</id> - <param name="silverlight" type="boolean" _gui-text="Silverlight compatible XAML">false</param> - <output> - <extension>.xaml</extension> - <mimetype>text/xml+xaml</mimetype> - <_filetypename>Microsoft XAML (*.xaml)</_filetypename> - <_filetypetooltip>Microsoft's GUI definition format</_filetypetooltip> - </output> - <xslt> - <file reldir="extensions">svg2xaml.xsl</file> - </xslt> -</inkscape-extension> diff --git a/share/extensions/svg2xaml.xsl b/share/extensions/svg2xaml.xsl deleted file mode 100644 index b7629901b..000000000 --- a/share/extensions/svg2xaml.xsl +++ /dev/null @@ -1,2987 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- -Copyright (c) 2005-2015 authors: -Original version: Toine de Greef (a.degreef@chello.nl) -Modified (2010-2015) by Nicolas Dufour (nicoduf@yahoo.fr) (blur support, units -conversion, 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" -xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" -exclude-result-prefixes="rdf xlink xs exsl libxslt inkscape"> - -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="UTF-8" indent="yes"/> - -<xsl:param name="silverlight_compatible" select="$silverlight" /> - -<!-- - // Containers // - - * Root templace - * Groups ---> - -<!-- - // Root template // ---> -<xsl:template match="/"> - <xsl:choose> - <xsl:when test="$silverlight_compatible = 'true'"> - <xsl:comment> - <xsl:value-of select="'This file is compatible with Silverlight'" /> - </xsl:comment> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:comment> - <xsl:value-of select="'This file is NOT compatible with Silverlight'" /> - </xsl:comment> - <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 @filter 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="filter_effect" 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:apply-templates mode="resources" select="." /> - - <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="format-number(-number(substring-before($viewBox, ' ')), '#.#')" /> - </xsl:attribute> - <xsl:attribute name="Y"> - <xsl:value-of select="format-number(-number(substring-before(substring-after($viewBox, ' '), ' ')), '#.#')" /> - </xsl:attribute> - </TranslateTransform> - </Canvas.RenderTransform> - </xsl:if> - <xsl:if test="@transform"> - <xsl:apply-templates mode="transform" select="."> - <xsl:with-param name="mapped_type" select="'Canvas'" /> - </xsl:apply-templates> - <xsl:apply-templates mode="forward" select="*" /> - </xsl:if> - - <xsl:if test="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath' or name(.) = 'filter']"> - <Canvas.Resources> - <xsl:apply-templates mode="forward" select="*[name(.) = 'linearGradient' or name(.) = 'radialGradient' or name(.) = 'defs' or name(.) = 'clipPath' or name(.) = 'filter']" /> - </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' and name(.) != 'filter']" /> - </xsl:if> - </Canvas> - </xsl:when> - <xsl:when test="not(@transform)"> - <xsl:apply-templates mode="forward" select="*" /> - </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 - * Rotation center ---> - -<!-- - // Parse transform // ---> -<xsl:template name="parse_transform"> - <xsl:param name="input" /> - <xsl:choose> - - <!-- Matrix transform --> - <xsl:when test="starts-with($input, 'matrix(')"> - <MatrixTransform> - <xsl:attribute name="Matrix"> - <xsl:value-of select="normalize-space(translate(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> - - <!-- Scale transform --> - <xsl:when test="starts-with($input, 'scale(')"> - <ScaleTransform> - <xsl:variable name="scale" select="normalize-space(translate(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> - - <!-- Rotate transform --> - <xsl:when test="starts-with($input, 'rotate(')"> - <RotateTransform> - <xsl:attribute name="Angle"> - <xsl:value-of select="normalize-space(translate(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> - - <!-- Skew transform --> - <xsl:when test="starts-with($input, 'skewX(')"> - <SkewTransform> - <xsl:attribute name="AngleX"> - <xsl:value-of select="normalize-space(translate(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="normalize-space(translate(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> - - <!-- Translate transform --> - <xsl:when test="starts-with($input, 'translate(')"> - <TranslateTransform> - <xsl:variable name="translate" select="normalize-space(translate(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: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="values" select="normalize-space(translate($transform, ',', ' '))" /> - <xsl:variable name="value1"> - <xsl:choose> - <xsl:when test="contains($values, ') ')"> - <xsl:value-of select="concat(substring-before($values, ') '), ')')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$values" /> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="value2"> - <xsl:if test="substring-after($values, $value1) != ''"> - <xsl:choose> - <xsl:when test="contains(substring-after($values, $value1), ') ')"> - <xsl:value-of select="normalize-space(concat(substring-before(substring-after($values, $value1), ') '), ')'))" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="normalize-space(substring-after($values, $value1))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - <xsl:variable name="value3"> - <xsl:if test="$value2 != '' and substring-after($values, $value2) != ''"> - <xsl:choose> - <xsl:when test="contains(substring-after($values, $value2), ') ')"> - <xsl:value-of select="normalize-space(concat(substring-before(substring-after($values, $value2), ') '), ')'))" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="normalize-space(substring-after($values, $value2))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - - <xsl:variable name="transform_nodes"> - <xsl:if test="$value3 !=''"> - <xsl:call-template name="parse_transform"> - <xsl:with-param name="input" select="$value3" /> - </xsl:call-template> - </xsl:if> - <xsl:if test="$value2 !=''"> - <xsl:call-template name="parse_transform"> - <xsl:with-param name="input" select="$value2" /> - </xsl:call-template> - </xsl:if> - <xsl:if test="$value1 !=''"> - <xsl:call-template name="parse_transform"> - <xsl:with-param name="input" select="$value1" /> - </xsl:call-template> - </xsl:if> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$mapped_type and $mapped_type != '' and not(contains($mapped_type, 'Geometry'))"> - <xsl:element name="{$mapped_type}.RenderTransform"> - <xsl:choose> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </xsl:when> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"> - <TransformGroup> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </TransformGroup> - </xsl:when> - </xsl:choose> - </xsl:element> - </xsl:when> - <xsl:when test="$mapped_type and $mapped_type != '' and contains($mapped_type, 'Geometry')"> - <xsl:element name="{$mapped_type}.Transform"> - <xsl:choose> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </xsl:when> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"> - <TransformGroup> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </TransformGroup> - </xsl:when> - </xsl:choose> - </xsl:element> - </xsl:when> - <xsl:otherwise> - <!-- For instance LinearGradient.Transform --> - <xsl:choose> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) = 1"> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </xsl:when> - <xsl:when test="count(libxslt:node-set($transform_nodes)/*) > 1"> - <TransformGroup> - <xsl:copy-of select="libxslt:node-set($transform_nodes)" /> - </TransformGroup> - </xsl:when> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </xsl:if> -</xsl:template> - -<!-- - // Rotation center // - In XAML, relative to the object's bounding box (RenderTransformOrigin="0.5,0.5" is the center) - Unfortunately, converting would require that the bounding box of all objects and groups is calculated, which is rather complex... ---> -<xsl:template mode="rotation-center" match="*"> - <xsl:if test="@inkscape:transform-center-x"> -<!-- <xsl:attribute name="RenderTransformOrigin"> - <xsl:value-of select="concat(@inkscape:transform-center-x, ',', @inkscape:transform-center-y)" /> - </xsl:attribute> --->> - </xsl:if> -</xsl:template> - -<!-- - // Resources (defs) // - - * Resources ids - * Generic defs template - * Generic filters template - * Filter effects - * Linked filter effects - * Absolute gradients - * Linear gradients - * Radial gradients - * Generic gradient stops - * Clipping ---> - -<!-- - // Resources ids // ---> -<xsl:template mode="resources" match="*"> - <!-- should be in-depth --> - <xsl:if test="parent::*[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="*[name(.) = '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> - -<!-- - // GaussianBlur filter effects // - Blur values approximated with d = floor(s * 3*sqrt(2*pi)/4 + 0.5) from: - http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement - - Not supported by XAML: - * Horizontal and vertical blur. ---> -<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:variable name="blur" select="normalize-space(translate(@stdDeviation, ',', ' '))" /> - <xsl:choose> - <xsl:when test="not(contains($blur, ' '))"> - <xsl:attribute name="Radius"> - <xsl:value-of select="floor($blur * 1.88 + 0.5)" /> - </xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="Radius"> - <xsl:value-of select="floor(substring-before($blur, ' ') * 1.88 + 0.5)" /> - </xsl:attribute> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </BlurEffect> -</xsl:template> - -<!-- - // Fake GaussianBlur filter effect // - Replaces all the other SVG effects with a zero radius blur effect. ---> -<xsl:template mode="forward" match="*[name(.) = 'feBlend' or name(.) = 'feColorMatrix' or name(.) = 'feComponentTransfer' or name(.) = 'feComposite' or name(.) = 'feConvolveMatrix' or name(.) = 'feDiffuseLighting' or name(.) = 'feDisplacementMap' or name(.) = 'feFlood' or name(.) = 'feImage' or name(.) = 'feMerge' or name(.) = 'feMorphology' or name(.) = 'feOffset' or name(.) = 'feSpecularLighting' or name(.) = 'feTile' or name(.) = 'feTurbulence']"> - <xsl:comment> - <xsl:value-of select="concat('Tag ', name(.), ' not supported, replaced with empty blur')" /> - </xsl:comment> - <BlurEffect> - <xsl:if test="../@id"><xsl:attribute name="x:Key"><xsl:value-of select="../@id" /></xsl:attribute></xsl:if> - <xsl:attribute name="Radius"> - <xsl:value-of select="0" /> - </xsl:attribute> - </BlurEffect> -</xsl:template> - -<!-- - // Linked filter effect // - Only supports blurs ---> -<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(normalize-space(substring-after(translate(@style, '"', ''), 'filter:')), 'url(#')"> - <xsl:attribute name="Effect"> - <xsl:value-of select="concat('{StaticResource ', substring-before(normalize-space(substring-after(substring-after(translate(@style, '"', ''), 'filter:'), 'url(#')), ')'), '}')" /> - </xsl:attribute> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- - // Absolute gradients // - Get the calling object position in order to substract it from the absolute gradient position. - (XAML absolute gradients values are absolute in the gradient's space). ---> -<xsl:template mode="absolute_gradient" match="*"> - <xsl:param name="position" /> - <xsl:if test="@id"> - <xsl:variable name="id" select="concat('#', @id)"/> - <xsl:variable name="value"> - <xsl:for-each select="//*[contains(@style,$id) or contains(@fill,$id) or contains(@stroke,$id)]"> - <xsl:choose> - <xsl:when test="$position = 'y' and @y"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y" /> - </xsl:call-template> - </xsl:when> - <xsl:when test="$position = 'x' and @x"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x" /> - </xsl:call-template> - </xsl:when> - </xsl:choose> - </xsl:for-each> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value != ''"> - <xsl:value-of select="$value"/> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:if> -</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:variable name="left"> - <xsl:choose> - <xsl:when test="@gradientUnits = 'userSpaceOnUse' "> - <xsl:apply-templates mode="absolute_gradient" select="."> - <xsl:with-param name="position" select="'x'" /> - </xsl:apply-templates> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="top"> - <xsl:choose> - <xsl:when test="@gradientUnits = 'userSpaceOnUse' "> - <xsl:apply-templates mode="absolute_gradient" select="."> - <xsl:with-param name="position" select="'y'" /> - </xsl:apply-templates> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <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(round(number(substring-before(@x1, '%')) div 100), ',', round(number(substring-before(@y1,'%')) div 100))" /> - </xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="StartPoint"> - <xsl:value-of select="concat(round((@x1 - $left)), ',', round((@y1 - $top)))" /> - </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(round(number(substring-before(@x2, '%')) div 100), ',', round(number(substring-before(@y2,'%')) div 100))" /> - </xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="EndPoint"> - <xsl:value-of select="concat(round((@x2 - $left)), ',', round((@y2 - $top)))" /> - </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:variable name="left"> - <xsl:choose> - <xsl:when test="@gradientUnits = 'userSpaceOnUse' "> - <xsl:apply-templates mode="absolute_gradient" select="."> - <xsl:with-param name="position" select="'x'" /> - </xsl:apply-templates> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="top"> - <xsl:choose> - <xsl:when test="@gradientUnits = 'userSpaceOnUse' "> - <xsl:apply-templates mode="absolute_gradient" select="."> - <xsl:with-param name="position" select="'y'" /> - </xsl:apply-templates> - </xsl:when> - <xsl:otherwise>0</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <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(round(number(substring-before(@cx, '%')) div 100), ',', round(number(substring-before(@cy, '%')) div 100))" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat(round(@cx - $left), ',', round(@cy - $top))" /> - </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(round(number(substring-before(@fx, '%')) div 100), ',', round(number(substring-before(@fy, '%')) div 100))" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="concat(round(@fx - $left), ',', round(@fy - $top))" /> - </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(.) = 'radialGradient' 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> - -<!-- - // Gradient stop // ---> -<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 // - - * Id converter - * Decimal to hexadecimal converter - * Unit to pixel converter - * Object description - * Title and description - * Switch - * Symbols - * Use - * RDF and foreign objects - * Misc ignored stuff (markers, patterns, styles) - * Unknows tags ---> - -<!-- - // 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. - Unknown units are kept. - em, ex and % not implemented ---> -<xsl:template name="convert_unit"> - <xsl:param name="convert_value" /> - <xsl:choose> - <xsl:when test="contains($convert_value, 'px')"> - <xsl:value-of select="translate($convert_value, 'px', '')" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'pt')"> - <xsl:value-of select="translate($convert_value, 'pt', '') * 1.333333" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'pc')"> - <xsl:value-of select="translate($convert_value, 'pc', '') * 16" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'mm')"> - <xsl:value-of select="translate($convert_value, 'mm', '') * 3.779527" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'cm')"> - <xsl:value-of select="translate($convert_value, 'cm', '') * 37.79527" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'in')"> - <xsl:value-of select="translate($convert_value, 'in', '') * 96" /> - </xsl:when> - <xsl:when test="contains($convert_value, 'ft')"> - <xsl:value-of select="translate($convert_value, 'ft', '') * 1152" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$convert_value" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // 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> - -<!-- - // Title and description // - 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> - -<!-- - // Switch // ---> -<xsl:template mode="forward" match="*[name(.) = 'switch']"> - <xsl:apply-templates mode="forward" /> -</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 // - (since it is not supported by Inkscape, not implemented yet) ---> -<xsl:template mode="forward" match="*[name(.) = 'use']"> -<!-- Errors when more than one use element share the same reference - <Canvas> - <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> - - <StaticResource> - <xsl:if test="@xlink:href"> - <xsl:attribute name="ResourceKey"> - <xsl:value-of select="substring-after(@xlink:href, '#')" /> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="forward" /> - </StaticResource> - </Canvas> - --> -</xsl:template> - -<!-- - // RDF and foreign objects // ---> -<xsl:template mode="forward" match="rdf:RDF | *[name(.) = 'foreignObject']"> - -</xsl:template> - -<!-- - // Misc ignored stuff (markers, patterns, styles) // ---> -<xsl:template mode="forward" match="*[name(.) = 'marker' or name(.) = 'pattern' or name(.) = 'style']"> - -</xsl:template> - -<!-- - // Unknown tags // - With generic and mode="forward" templates ---> -<xsl:template match="*"> - <xsl:comment> - <xsl:value-of select="concat('Unknown tag: ', name(.))" /> - </xsl:comment> -</xsl:template> - -<xsl:template mode="forward" match="*"> - <xsl:comment> - <xsl:value-of select="concat('Unknown tag: ', name(.))" /> - </xsl:comment> -</xsl:template> - -<!-- -// Colors and patterns // - -* Generic color template -* Object opacity -* 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 -* Image stretch ---> - -<!-- - // 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> - -<!-- - // Object opacity // ---> -<xsl:template mode="object_opacity" match="*"> - <xsl:if test="@opacity or (@style and (contains(@style, ';opacity:') or starts-with(@style, 'opacity:')))"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@opacity"> - <xsl:value-of select="@opacity" /> - </xsl:when> - <xsl:when test="@style and contains(@style, ';opacity:')"> - <xsl:variable name="Opacity" select="substring-after(@style, ';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="@style and starts-with(@style, 'opacity:')"> - <xsl:variable name="Opacity" select="substring-after(@style, '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="object_opacity" select="parent::*" /> - </xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:attribute name="Opacity"> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Fill // ---> -<xsl:template mode="fill" match="*"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@fill and starts-with(normalize-space(translate(@fill, '"', '')), 'url(#')"> - <!-- Removes unwanted characters in the color link (TODO: export to a specific template)--> - <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(normalize-space(translate(@fill, '"', '')), 'url(#'), ')'), '}')" /> - </xsl:when> - <xsl:when test="@fill"> - <xsl:value-of select="normalize-space(@fill)" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill:') and starts-with(normalize-space(substring-after(translate(@style, '"', ''), 'fill:')), 'url(#')"> - <xsl:value-of select="concat('{StaticResource ', substring-before(normalize-space(substring-after(substring-after(translate(@style, '"', ''), 'fill:'), 'url(#')), ')'), '}')" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill:')"> - <xsl:variable name="Fill" select="normalize-space(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:variable> - <xsl:if test="$value"> - <xsl:value-of select="$value" /> - </xsl:if> -</xsl:template> - -<!-- - // Fill opacity // ---> -<xsl:template mode="fill_opacity" match="*"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@fill-opacity"> - <xsl:value-of select="normalize-space(@fill-opacity)" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill-opacity:')"> - <xsl:variable name="Opacity" select="normalize-space(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:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - -<!-- - // Fill rule // ---> -<xsl:template mode="fill_rule" match="*"> - <xsl:choose> - <xsl:when test="@fill-rule and (@fill-rule = 'nonzero')"> - <xsl:attribute name="FillRule">NonZero</xsl:attribute> - </xsl:when> - <xsl:when test="@fill-rule and (@fill-rule = 'evenodd')"> - <xsl:attribute name="FillRule">EvenOdd</xsl:attribute> - </xsl:when> - <xsl:when test="@style and contains(@style, 'fill-rule:')"> - <xsl:variable name="FillRule" select="normalize-space(substring-after(@style, 'fill-rule:'))" /> - <xsl:choose> - <xsl:when test="contains($FillRule, ';')"> - <xsl:if test="substring-before($FillRule, ';') = 'nonzero'"> - <xsl:attribute name="FillRule">NonZero</xsl:attribute> - </xsl:if> - <xsl:if test="substring-before($FillRule, ';') = 'evenodd'"> - <xsl:attribute name="FillRule">EvenOdd</xsl:attribute> - </xsl:if> - </xsl:when> - <xsl:when test="$FillRule = 'nonzero'"> - <xsl:attribute name="FillRule">NonZero</xsl:attribute> - </xsl:when> - <xsl:when test="$FillRule = 'evenodd'"> - <xsl:attribute name="FillRule">EvenOdd</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(#')"> - <!-- Removes unwanted characters in the color link (TODO: export to a specific template)--> - <xsl:value-of select="concat('{StaticResource ', substring-before(substring-after(normalize-space(translate(@stroke, '"', '')), 'url(#'), ')'), '}')" /> - </xsl:when> - <xsl:when test="@stroke and normalize-space(@stroke) != 'none'"> - <xsl:value-of select="@stroke" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke:') and starts-with(normalize-space(substring-after(translate(@style, '"', ''), 'stroke:')), 'url(#')"> - <xsl:value-of select="concat('{StaticResource ', substring-before(normalize-space(substring-after(substring-after(translate(@style, '"', ''), 'stroke:'), 'url(#')), ')'), '}')" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke:')"> - <xsl:variable name="Stroke" select="normalize-space(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:variable name="value"> - <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:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value < 0">0</xsl:when> - <xsl:when test="$value > 1">1</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </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:variable name="stroke_width"> - <xsl:apply-templates mode="stroke_width" select="." /> - </xsl:variable> - - <xsl:if test="$stroke_width != ''"> - <xsl:attribute name="StrokeThickness"> - <xsl:value-of select="$stroke_width" /> - </xsl:attribute> - </xsl:if> - <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:call-template name="convert_unit"> - <xsl:with-param name="convert_value"> - <xsl:value-of select="@stroke-width" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-width:')"> - <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: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="normalize-space(@stroke-miterlimit)" /> - </xsl:attribute> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-miterlimit:')"> - <xsl:variable name="StrokeMiterLimit" select="normalize-space(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 normalize-space(@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="normalize-space(substring-before($StrokeDashArray, ';')) != 'none'"> - <xsl:attribute name="StrokeDashArray"> - <xsl:value-of select="substring-before($StrokeDashArray, ';')" /> - </xsl:attribute> - </xsl:if> - </xsl:when> - <xsl:when test="normalize-space($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 or (@style and contains(@style, 'stroke-dashoffset:'))"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@stroke-dashoffset"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="normalize-space(@stroke-dashoffset)" /> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stroke-dashoffset:')"> - <xsl:variable name="StrokeDashOffset" select="normalize-space(substring-after(@style, 'stroke-dashoffset:'))" /> - <xsl:attribute name="StrokeDashOffset"> - <xsl:choose> - <xsl:when test="contains($StrokeDashOffset, ';')"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="substring-before($StrokeDashOffset, ';')" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$StrokeDashOffset" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:when> - </xsl:choose> - </xsl:variable> - <xsl:if test="value != ''"> - <xsl:attribute name="StrokeDashOffset"> - <xsl:value-of select="$value" /> - </xsl:attribute> - </xsl:if> - </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-linejoin"> - <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="normalize-space(@stop-opacity)" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stop-opacity:')"> - <xsl:variable name="temp_opacity" select="normalize-space(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="normalize-space(@stop-color)" /> - </xsl:with-param> - </xsl:call-template> - </xsl:when> - <xsl:when test="@style and contains(@style, 'stop-color:')"> - <xsl:variable name="Color" select="normalize-space(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>#000000</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> - -<!-- - // Image stretch // - SVG: preserveAspectRatio, XAML: Stretch ---> -<xsl:template mode="image_stretch" match="*"> - <xsl:variable name="value"> - <xsl:choose> - <xsl:when test="@preserveAspectRatio"> - <xsl:value-of select="@preserveAspectRatio" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'preserveAspectRatio:')"> - <xsl:variable name="ratio" select="normalize-space(substring-after(@style, 'preserveAspectRatio:'))" /> - <xsl:choose> - <xsl:when test="contains($ratio, ';')"> - <xsl:value-of select="substring-before($ratio, ';')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$ratio" /> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - </xsl:choose> - </xsl:variable> - <xsl:if test="$value = 'none'"> - <xsl:attribute name="Stretch">Fill</xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text specific templates // - - * Text tspan - * Text flowPara - * Text flowRegion (text frame) - * Get font size - * Font size - * Font weight - * Font family - * Font style - * Baseline shift - * Line height - * Writing mode - * Text decoration - * Text fill - * Text direction - * Text size - * Text position - * Text object - * FlowRoot object ---> - - <!-- - // Text span // - SVG: tspan, flowSpan, XAML: Span - - Not supported in XAML: - * span position ---> -<xsl:template mode="forward" match="*[name(.) = 'tspan' or name(.) = 'flowSpan']"> - <Span> - <xsl:if test="../@xml:space='preserve'"> - <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute> - </xsl:if> - <xsl:variable name="fill"> - <xsl:apply-templates mode="fill" select="." /> - </xsl:variable> - <xsl:if test="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')"> - <xsl:attribute name="Foreground"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="line_height" select="." /> - <xsl:apply-templates mode="baseline_shift" select="." /> - - <xsl:if test="text()"> - <xsl:value-of select="text()" /> - </xsl:if> - </Span> -</xsl:template> - - <!-- - // Text flowPara // - SVG: flowPara, flowDiv XAML: ? - ---> -<xsl:template mode="forward" match="*[name(.) = 'flowPara' or name(.) = 'flowDiv']"> - <xsl:choose> - <xsl:when test="*[name(.) = 'flowSpan']/text()"> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="@xml:space='preserve'"> - <xsl:copy-of select="translate(text(), '	

', ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="normalize-space(translate(text(), '	

', ' '))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> -</xsl:template> - - - <!-- - // Text flowRegion // ---> -<xsl:template mode="flow_region" match="*"> - <xsl:apply-templates mode="text_size" select="." /> - <xsl:apply-templates mode="text_position" select="." /> -</xsl:template> - -<!-- - // Get text font size // ---> -<xsl:template mode="get_font_size" match="*"> - <xsl:choose> - <xsl:when test="@font-size"> - <xsl:value-of select="@font-size" /> - </xsl:when> - <xsl:when test="@style and contains(@style, 'font-size:')"> - <xsl:variable name="font_size" select="normalize-space(substring-after(@style, 'font-size:'))" /> - <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:when> - <xsl:when test="name(..) = 'g' or name(..) = 'svg' or name(..) = 'text' or name(..) = 'flowPara' or name(..) = 'flowRoot'"> - <xsl:apply-templates mode="get_font_size" select="parent::*"/> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- - // Text font size // - SVG: font-size, XAML: FontSize ---> -<xsl:template mode="font_size" match="*"> - <xsl:variable name="value"> - <xsl:apply-templates mode="get_font_size" select="." /> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="FontSize"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="FontSize"> - <xsl:choose> - <xsl:when test="$value != ''"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>12</xsl:otherwise> - </xsl:choose> - </xsl:attribute> -</xsl:template> - -<!-- - // Text font weight // - SVG: font-weight, XAML: FontWeight ---> -<xsl:template mode="font_weight" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-weight"> - <xsl:value-of select="@font-weight" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-weight:')"> - <xsl:variable name="font_weight" select="normalize-space(substring-after(@style, 'font-weight:'))" /> - <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:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="FontWeight"> - <xsl:choose> - <xsl:when test="$value <= 100 or $value = 'lighter'">Thin</xsl:when> - <xsl:when test="$value > 100 and $value <= 200">ExtraLight</xsl:when> - <xsl:when test="$value > 200 and $value <= 300">Light</xsl:when> - <xsl:when test="($value > 300 and $value <= 400) or $value ='normal'">Normal</xsl:when> - <xsl:when test="$value > 400 and $value <= 500">Medium</xsl:when> - <xsl:when test="$value > 500 and $value <= 600">SemiBold</xsl:when> - <xsl:when test="($value > 600 and $value <= 700) or $value ='bold'">Bold</xsl:when> - <xsl:when test="$value > 700 and $value <= 800">ExtraBold</xsl:when> - <xsl:when test="$value > 800 and $value <= 900">Black</xsl:when> - <xsl:when test="$value > 900 or $value = 'bolder'">ExtraBlack</xsl:when> - <xsl:otherwise>normal</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text font family // - SVG: font-family, XAML: FontFamily ---> -<xsl:template mode="font_family" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-family"> - <xsl:value-of select="translate(@font-family, "'", '')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-family:')"> - <xsl:variable name="font_family" select="normalize-space(substring-after(@style, 'font-family:'))" /> - <xsl:choose> - <xsl:when test="contains($font_family, ';')"> - <xsl:value-of select="translate(substring-before($font_family, ';'), "'", '')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="translate($font_family, "'", '')" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="FontFamily"> - <xsl:choose> - <xsl:when test="$value='Sans'">Arial</xsl:when> - <xsl:otherwise> - <xsl:value-of select="$value" /> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text font style // - SVG: font-style, XAML: FontStyle ---> -<xsl:template mode="font_style" match="*"> - <xsl:variable name="value"> - <xsl:if test="@font-style"> - <xsl:value-of select="@font-style" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'font-style:')"> - <xsl:variable name="font_style" select="normalize-space(substring-after(@style, 'font-style:'))" /> - <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:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="FontStyle"> - <xsl:value-of select="$value" /> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text baseline shift // - SVG: baseline-shift, XAML: BaselineAlignment ---> -<xsl:template mode="baseline_shift" match="*"> - <xsl:variable name="value"> - <xsl:if test="@baseline-shift"> - <xsl:value-of select="@baseline-shift" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'baseline-shift:') and not(contains(substring-after(@style, 'baseline-shift:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'baseline-shift:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'baseline-shift:') and contains(substring-after(@style, 'baseline-shift:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'baseline-shift:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value = 'baseline' or $value='super' or $value='sub'"> - <xsl:attribute name="BaselineAlignment"> - <xsl:choose> - <xsl:when test="$value='baseline'">Normal</xsl:when> - <xsl:when test="$value='super'">Superscript</xsl:when> - <xsl:when test="$value='sub'">Subscript</xsl:when> - </xsl:choose> - <xsl:if test="contains($value, '%')">%</xsl:if> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text line height // - SVG: line-height, FXG: lineHeight ---> -<xsl:template mode="line_height" match="*"> - <xsl:variable name="value"> - <xsl:if test="@line-height"> - <xsl:value-of select="@line-height" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'line-height:')"> - <xsl:variable name="line_height" select="normalize-space(substring-after(@style, 'line-height:'))" /> - <xsl:choose> - <xsl:when test="contains($line_height, ';')"> - <xsl:value-of select="substring-before($line_height, ';')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$line_height" /> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="lineHeight"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text writing mode // - SVG: writing-mode, FXG: blockProgression - - Values inverted in FXG... ---> -<xsl:template mode="writing_mode" match="*"> - <xsl:variable name="value"> - <xsl:if test="@writing-mode"> - <xsl:value-of select="@writing-mode" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'writing-mode:') and not(contains(substring-after(@style, 'writing-mode:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'writing-mode:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'writing-mode:') and contains(substring-after(@style, 'writing-mode:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'writing-mode:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="blockProgression"> - <xsl:choose> - <xsl:when test="$value='tb'">rl</xsl:when> - <xsl:otherwise>tb</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:if test="$value='tb'"> - <xsl:attribute name="textRotation">rotate270</xsl:attribute> - </xsl:if> - </xsl:if> -</xsl:template> - -<!-- - // Text decoration // - SVG: text-decoration, XAML: TextDecorations ---> -<xsl:template mode="text_decoration" match="*"> - <xsl:variable name="value"> - <xsl:if test="@text-decoration"> - <xsl:value-of select="@text-decoration" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'text-decoration:') and not(contains(substring-after(@style, 'text-decoration:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'text-decoration:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'text-decoration:') and contains(substring-after(@style, 'text-decoration:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'text-decoration:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:if test="$value != ''"> - <xsl:attribute name="TextDecorations"> - <xsl:choose> - <xsl:when test="$value='underline'">Underline</xsl:when> - <xsl:when test="$value='line-through'">Strikethrough</xsl:when> - <xsl:when test="$value='overline'">Overline</xsl:when> - <xsl:otherwise>None</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text fill // - SVG: fill, fill-opacity, XAML: Foreground ---> -<xsl:template mode="text_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="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')"> - <xsl:attribute name="Foreground"> - <xsl:call-template name="template_color"> - <xsl:with-param name="colorspec"> - <xsl:value-of select="$fill" /> - </xsl:with-param> - <xsl:with-param name="opacityspec"> - <xsl:choose> - <xsl:when test="$fill_opacity"> - <xsl:value-of select="$fill_opacity" /> - </xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:with-param> - </xsl:call-template> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Text direction // - SVG: direction, unicode-bidi, XAML: FlowDirection ---> -<xsl:template mode="direction" match="*"> - <xsl:variable name="value"> - <xsl:if test="@direction"> - <xsl:value-of select="@direction" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'direction:') and not(contains(substring-after(@style, 'direction:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'direction:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'direction:') and contains(substring-after(@style, 'direction:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'direction:'), ';')" /> - </xsl:if> - </xsl:variable> - <xsl:variable name="bidi"> - <xsl:if test="@unicode-bidi"> - <xsl:value-of select="@unicode-bidi" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'unicode-bidi:') and not(contains(substring-after(@style, 'unicode-bidi:'), ';'))"> - <xsl:value-of select="substring-after(@style, 'unicode-bidi:')" /> - </xsl:if> - <xsl:if test="@style and contains(@style, 'unicode-bidi:') and contains(substring-after(@style, 'unicode-bidi:'), ';')"> - <xsl:value-of select="substring-before(substring-after(@style, 'unicode-bidi:'), ';')" /> - </xsl:if> - </xsl:variable> - - <xsl:if test="$value != '' and ($bidi='embed' or $bidi='bidi-override')"> - <xsl:attribute name="FlowDirection"> - <xsl:choose> - <xsl:when test="$value='ltr'">LeftToRight</xsl:when> - <xsl:when test="$value='rtl'">RightToLeft</xsl:when> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - - <!-- - // Text size // ---> -<xsl:template mode="text_size" match="*"> - <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:template> - - <!-- - // Text position // ---> -<xsl:template mode="text_position" match="*"> - <!-- Keep the first x value only --> - <xsl:if test="@x"> - <xsl:attribute name="Canvas.Left"> - <xsl:choose> - <xsl:when test="contains(@x, ' ')"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="substring-before(@x, ' ')" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <!-- Keep the first y value only --> - <xsl:if test="@y"> - <xsl:attribute name="Canvas.Top"> - <xsl:variable name="top_val"> - <xsl:choose> - <xsl:when test="contains(@y, ' ')"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="substring-before(@y, ' ')" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="size_val"> - <xsl:variable name="value"> - <xsl:apply-templates mode="get_font_size" select="." /> - </xsl:variable> - <xsl:choose> - <xsl:when test="$value != ''"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="$value" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise>12</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:if test="$top_val != '' and $size_val != ''"> - <xsl:value-of select='format-number($top_val - $size_val, "#.#")' /> - </xsl:if> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<!-- - // Objects // - - * Text - * Lines - * Rectangle - * Polygon - * Polyline - * Path - * Ellipse - * Circle - * Image ---> - -<!-- - // Text objects // - SVG: text, XAML: TextBlock ---> -<xsl:template mode="forward" match="*[name(.) = 'text' or name(.) = 'flowRoot']"> - <TextBlock> - <xsl:apply-templates mode="font_size" select="." /> - <xsl:apply-templates mode="font_weight" select="." /> - <xsl:apply-templates mode="font_family" select="." /> - <xsl:apply-templates mode="font_style" select="." /> - <xsl:apply-templates mode="text_fill" select="." /> - <xsl:apply-templates mode="text_size" select="." /> - <xsl:apply-templates mode="text_decoration" select="." /> - <xsl:apply-templates mode="direction" select="." /> - <xsl:apply-templates mode="text_position" select="." /> - <xsl:if test="name(.) = 'flowRoot'"> - <xsl:attribute name="TextWrapping"> - <xsl:value-of select="'Wrap'" /> - </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:apply-templates mode="object_opacity" select="." /> - - <xsl:apply-templates mode="id" select="." /> - <xsl:if test="name(.) = 'flowRoot'"> - <xsl:apply-templates mode="flow_region" select="*[name(.) = 'flowRegion']/child::node()" /> - </xsl:if> - <xsl:apply-templates mode="filter_effect" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" select="." /> - <xsl:apply-templates mode="clip" select="." /> - <!--xsl:apply-templates mode="transform" select="." /--> - <!--xsl:apply-templates mode="forward" /--> - - <xsl:choose> - <xsl:when test="*[name(.) = 'tspan' or name(.) = 'flowPara' or name(.) = 'flowDiv']/text()"> - <xsl:apply-templates mode="forward" /> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="@xml:space='preserve'"> - <xsl:copy-of select="translate(text(), '	

', ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="normalize-space(translate(text(), '	

', ' '))" /> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - - </TextBlock> -</xsl:template> - -<!-- - // Line object // - SVG: line, XAML: Line ---> -<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_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="object_opacity" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" 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 object // - SVG: rect, XAML: 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_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="object_opacity" 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 object // - SVG: polygon, XAML: 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_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="object_opacity" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" 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 object // - SVG: polyline, XAML: 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_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="object_opacity" 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 // - SVG: path, XAML: 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_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="object_opacity" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" select="." /> - <xsl:apply-templates mode="clip" select="." /> - - <xsl:if test="@d"> - <xsl:choose> - <xsl:when test="$silverlight_compatible = 'true'"> - <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 object // - SVG: ellipse, XAML: 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_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="object_opacity" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" 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 object // - SVG: circle, XAML: Ellipse ---> -<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_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="object_opacity" select="." /> - <xsl:apply-templates mode="desc" select="." /> - <xsl:apply-templates mode="resources" 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> - -<!-- - // Image object// - SVG: image, FXG: 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="image_stretch" select="." /> - <xsl:apply-templates mode="object_opacity" select="." /> - <xsl:apply-templates mode="resources" select="." /> - - <xsl:apply-templates mode="transform" select="."> - <xsl:with-param name="mapped_type" select="'Image'" /> - </xsl:apply-templates> - <xsl:apply-templates mode="forward" /> - </Image> -</xsl:template> - -<!-- -// Geometry // -* Generic clip path template -* Geometry for path -* Geometry for circle -* Geometry for rectangle ---> - -<!-- - // Generic clip path template // ---> -<xsl:template mode="forward" match="*[name(.) = 'clipPath']"> - <xsl:apply-templates mode="geometry" /> -</xsl:template> - -<!-- - // Clip Geometry for path // - TODO: PathGeometry is positioned in the object's space, and thus needs to be translated. ---> -<xsl:template mode="geometry" match="*[name(.) = 'path']"> - <PathGeometry> - <xsl:if test="../@id"> - <xsl:attribute name="x:Key"> - <xsl:value-of select="../@id" /> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="Figures"> - <xsl:value-of select="translate(@d , ',', ' ')" /> - </xsl:attribute> - <xsl:apply-templates mode="fill_rule" select="." /> - <xsl:apply-templates mode="transform" select="."> - <xsl:with-param name="mapped_type" select="'PathGeometry'" /> - </xsl:apply-templates> - </PathGeometry> -</xsl:template> - -<!-- - // Clip Geometry for circle // ---> -<xsl:template mode="geometry" match="*[name(.) = 'circle' or name(.) = 'ellipse']"> - <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> - <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:apply-templates mode="transform" select="."> - <xsl:with-param name="mapped_type" select="'EllipseGeometry'" /> - </xsl:apply-templates> - </EllipseGeometry> -</xsl:template> - -<!-- - // Clip 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:variable name="x"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@x" /> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="y"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@y" /> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="width"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@width" /> - </xsl:call-template> - </xsl:variable> - <xsl:variable name="height"> - <xsl:call-template name="convert_unit"> - <xsl:with-param name="convert_value" select="@height" /> - </xsl:call-template> - </xsl:variable> - <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:attribute name="Rect"><xsl:value-of select="concat($x, ', ', $y, ', ', $width, ', ', $height)" /></xsl:attribute> - <xsl:apply-templates mode="transform" select="."> - <xsl:with-param name="mapped_type" select="'RectangleGeometry'" /> - </xsl:apply-templates> - </RectangleGeometry> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/svg_and_media_zip_output.inx b/share/extensions/svg_and_media_zip_output.inx deleted file mode 100644 index f8a4c02f4..000000000 --- a/share/extensions/svg_and_media_zip_output.inx +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Compressed Inkscape SVG with media export</_name> - <id>org.inkscape.output.ZIP</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">svg_and_media_zip_output.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="image_dir" type="string" _gui-text="Image zip directory:">images</param> - <param name="font_list" type="boolean" _gui-text="Add font list">false</param> - <output> - <extension>.zip</extension> - <mimetype>application/x-zip</mimetype> - <_filetypename>Compressed Inkscape SVG with media (*.zip)</_filetypename> - <_filetypetooltip>Inkscape's native file format compressed with Zip and including all media files</_filetypetooltip> - <dataloss>false</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">svg_and_media_zip_output.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/svg_and_media_zip_output.py b/share/extensions/svg_and_media_zip_output.py deleted file mode 100755 index 4e991e91c..000000000 --- a/share/extensions/svg_and_media_zip_output.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env python -''' -svg_and_media_zip_output.py -An extension which collects all images to the documents directory and -creates a zip archive containing all images and the document - -Copyright (C) 2005 Pim Snel, pim@lingewoud.com -Copyright (C) 2008 Aaron Spike, aaron@ekips.org -Copyright (C) 2011 Nicolas Dufour, nicoduf@yahoo.fr - * Fix for a bug related to special caracters in the path (LP #456248). - * Fix for Windows support (LP #391307 ). - * Font list and image directory features. - -this is the first Python script ever created -its based on embedimage.py - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -TODOs -- fix bug: not saving existing .zip after a Collect for Output is run - this bug occurs because after running an effect extension the inkscape:output_extension is reset to svg.inkscape - the file name is still xxx.zip. after saving again the file xxx.zip is written with a plain .svg which - looks like a corrupt zip -- maybe add better extension -- consider switching to lzma in order to allow cross platform compression with no encoding problem... -''' -# standard library -import urlparse -import urllib -import os, os.path -import string -import zipfile -import shutil -import sys -import tempfile -import locale -# local library -import inkex -import simplestyle - -locale.setlocale(locale.LC_ALL, '') -inkex.localize() # TODO: test if it's still needed now that localize is called from inkex. - -class CompressedMediaOutput(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - if os.name == 'nt': - self.encoding = "cp437" - else: - self.encoding = "latin-1" - self.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'] - self.OptionParser.add_option("--image_dir", - action="store", type="string", - dest="image_dir", default="", - help="Image directory") - self.OptionParser.add_option("--font_list", - action="store", type="inkbool", - dest="font_list", default=False, - help="Add font list") - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab", - help="The selected UI-tab when OK was pressed") - - def output(self): - ''' - Writes the temporary compressed file to its destination - and removes the temporary directory. - ''' - out = open(self.zip_file,'rb') - if os.name == 'nt': - try: - import msvcrt - msvcrt.setmode(1, os.O_BINARY) - except: - pass - sys.stdout.write(out.read()) - out.close() - shutil.rmtree(self.tmp_dir) - - def collect_images(self, docname, z): - ''' - Collects all images in the document - and copy them to the temporary directory. - ''' - if locale.getpreferredencoding(): - dir_locale = locale.getpreferredencoding() - else: - dir_locale = "UTF-8" - dir = unicode(self.options.image_dir, dir_locale) - for node in self.document.xpath('//svg:image', namespaces=inkex.NSS): - xlink = node.get(inkex.addNS('href',u'xlink')) - if (xlink[:4] != 'data'): - absref = node.get(inkex.addNS('absref',u'sodipodi')) - url = urlparse.urlparse(xlink) - href = urllib.url2pathname(url.path) - - if (href != None and os.path.isfile(href)): - absref = os.path.realpath(href) - - absref = unicode(absref, "utf-8") - image_path = os.path.join(dir, os.path.basename(absref)) - - if (os.path.isfile(absref)): - shutil.copy(absref, self.tmp_dir) - z.write(absref, image_path.encode(self.encoding)) - elif (os.path.isfile(os.path.join(self.tmp_dir, absref))): - # TODO: please explain why this clause is necessary - shutil.copy(os.path.join(self.tmp_dir, absref), self.tmp_dir) - z.write(os.path.join(self.tmp_dir, absref), image_path.encode(self.encoding)) - else: - inkex.errormsg(_('Could not locate file: %s') % absref) - - node.set(inkex.addNS('href',u'xlink'), image_path) - #node.set(inkex.addNS('absref',u'sodipodi'), image_path) - - def collect_SVG(self, docstripped, z): - ''' - Copy SVG document to the temporary directory - and add it to the temporary compressed file - ''' - dst_file = os.path.join(self.tmp_dir, docstripped) - stream = open(dst_file,'w') - self.document.write(stream) - stream.close() - z.write(dst_file,docstripped.encode(self.encoding)+'.svg') - - def is_text(self, node): - ''' - Returns true if the tag in question is an element that - can hold text. - ''' - return node.tag in self.text_tags - - def get_fonts(self, node): - ''' - Given a node, returns a list containing all the fonts that - the node is using. - ''' - fonts = [] - s = '' - if 'style' in node.attrib: - s = simplestyle.parseStyle(node.attrib['style']) - if not s: - return fonts - - if s.has_key('font-family'): - if s.has_key('font-weight'): - fonts.append(s['font-family'] + ' ' + s['font-weight']) - else: - fonts.append(s['font-family']) - elif s.has_key('-inkscape-font-specification'): - fonts.append(s['-inkscape-font-specification']) - return fonts - - def list_fonts(self, z): - ''' - Walks through nodes, building a list of all fonts found, then - reports to the user with that list. - Based on Craig Marshall's replace_font.py - ''' - items = [] - nodes = [] - items = self.document.getroot().getiterator() - nodes.extend(filter(self.is_text, items)) - fonts_found = [] - for node in nodes: - for f in self.get_fonts(node): - if not f in fonts_found: - fonts_found.append(f) - findings = sorted(fonts_found) - # Write list to the temporary compressed file - filename = 'fontlist.txt' - dst_file = os.path.join(self.tmp_dir, filename) - stream = open(dst_file,'w') - if len(findings) == 0: - stream.write(_("Didn't find any fonts in this document/selection.")) - else: - if len(findings) == 1: - stream.write(_("Found the following font only: %s") % findings[0]) - else: - stream.write(_("Found the following fonts:\n%s") % '\n'.join(findings)) - stream.close() - z.write(dst_file, filename) - - - def effect(self): - docroot = self.document.getroot() - docname = docroot.get(inkex.addNS('docname',u'sodipodi')) - #inkex.errormsg(_('Locale: %s') % locale.getpreferredencoding()) - if docname is None: - docname = self.args[-1] - # TODO: replace whatever extension - docstripped = os.path.basename(docname.replace('.zip', '')) - docstripped = docstripped.replace('.svg', '') - docstripped = docstripped.replace('.svgz', '') - # Create os temp dir - self.tmp_dir = tempfile.mkdtemp() - # Create destination zip in same directory as the document - self.zip_file = os.path.join(self.tmp_dir, docstripped) + '.zip' - z = zipfile.ZipFile(self.zip_file, 'w') - - self.collect_images(docname, z) - self.collect_SVG(docstripped, z) - if self.options.font_list == True: - self.list_fonts(z) - z.close() - - -if __name__ == '__main__': #pragma: no cover - e = CompressedMediaOutput() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/svgcalendar.inx b/share/extensions/svgcalendar.inx deleted file mode 100644 index bda2466c0..000000000 --- a/share/extensions/svgcalendar.inx +++ /dev/null @@ -1,140 +0,0 @@ -<?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="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="show-week-number" type="boolean" _gui-text="Show week number">false</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> - <param name="color-weeknr" type="string" _gui-text="Week number color:">#787878</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="weeknr-name" type="string" _gui-text="Week number column name:" xml:space="preserve">Wk</_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 deleted file mode 100755 index 29dee262b..000000000 --- a/share/extensions/svgcalendar.py +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env python - -''' -calendar.py -A calendar generator plugin for Inkscape, but also can be used as a standalone -command line application. - -Copyright (C) 2008 Aurelio A. Heckert <aurium(a)gmail.com> -Week number option added by Olav Vitters and Nicolas Dufour (2012) - -More on ISO week number calculation on: -http://en.wikipedia.org/wiki/ISO_week_date -(The first week of a year is the week that contains the first Thursday -of the year.) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -__version__ = "0.3" - -import calendar -import re -from datetime import * - -import inkex -import simplestyle - - -class SVGCalendar (inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab") - self.OptionParser.add_option("--month", - action="store", type="int", - dest="month", default=0, - help="Month to be generated. If 0, then the entry year will be generated.") - self.OptionParser.add_option("--year", - action="store", type="int", - dest="year", default=0, - help="Year to be generated. If 0, then the current year will be generated.") - self.OptionParser.add_option("--fill-empty-day-boxes", - action="store", type="inkbool", - dest="fill_edb", default=True, - help="Fill empty day boxes with next month days.") - self.OptionParser.add_option("--show-week-number", - action="store", type="inkbool", - dest="show_weeknr", default=False, - help="Include a week number column.") - self.OptionParser.add_option("--start-day", - action="store", type="string", - dest="start_day", default="sun", - help='Week start day. ("sun" or "mon")') - self.OptionParser.add_option("--weekend", - action="store", type="string", - dest="weekend", default="sat+sun", - help='Define the weekend days. ("sat+sun" or "sat" or "sun")') - self.OptionParser.add_option("--auto-organize", - action="store", type="inkbool", - dest="auto_organize", default=True, - help='Automatically set the size and positions.') - self.OptionParser.add_option("--months-per-line", - action="store", type="int", - dest="months_per_line", default=3, - help='Number of months side by side.') - self.OptionParser.add_option("--month-width", - action="store", type="string", - dest="month_width", default="6cm", - help='The width of the month days box.') - self.OptionParser.add_option("--month-margin", - action="store", type="string", - dest="month_margin", default="1cm", - help='The space between the month boxes.') - self.OptionParser.add_option("--color-year", - action="store", type="string", - dest="color_year", default="#888", - help='Color for the year header.') - self.OptionParser.add_option("--color-month", - action="store", type="string", - dest="color_month", default="#666", - help='Color for the month name header.') - self.OptionParser.add_option("--color-day-name", - action="store", type="string", - dest="color_day_name", default="#999", - help='Color for the week day names header.') - self.OptionParser.add_option("--color-day", - action="store", type="string", - dest="color_day", default="#000", - help='Color for the common day box.') - self.OptionParser.add_option("--color-weekend", - action="store", type="string", - dest="color_weekend", default="#777", - help='Color for the weekend days.') - self.OptionParser.add_option("--color-nmd", - action="store", type="string", - dest="color_nmd", default="#BBB", - help='Color for the next month day, in enpty day boxes.') - self.OptionParser.add_option("--color-weeknr", - action="store", type="string", - dest="color_weeknr", default="#808080", - help='Color for the week numbers.') - self.OptionParser.add_option("--month-names", - action="store", type="string", - dest="month_names", default='January February March ' + \ - 'April May June '+ \ - 'July August September ' + \ - 'October November December', - help='The month names for localization.') - self.OptionParser.add_option("--day-names", - action="store", type="string", - dest="day_names", default='Sun Mon Tue Wed Thu Fri Sat', - help='The week day names for localization.') - self.OptionParser.add_option("--weeknr-name", - action="store", type="string", - dest="weeknr_name", default='Wk', - help='The week number column name for localization.') - self.OptionParser.add_option("--encoding", - action="store", type="string", - dest="input_encode", default='utf-8', - help='The input encoding of the names.') - - def validate_options(self): - #inkex.errormsg( self.options.input_encode ) - # Convert string names lists in real lists - m = re.match('\s*(.*[^\s])\s*', self.options.month_names) - self.options.month_names = re.split('\s+', m.group(1)) - m = re.match('\s*(.*[^\s])\s*', self.options.day_names) - self.options.day_names = re.split('\s+', m.group(1)) - # Validate names lists - if len(self.options.month_names) != 12: - inkex.errormsg('The month name list "' + \ - str(self.options.month_names) + \ - '" is invalid. Using default.') - self.options.month_names = ['January', 'February', 'March', - 'April', 'May', 'June', - 'July', 'August', 'September', - 'October', 'November', 'December'] - if len(self.options.day_names) != 7: - inkex.errormsg('The day name list "'+ - str(self.options.day_names)+ - '" is invalid. Using default.') - 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) - else: - calendar.setfirstweekday(0) - # Convert string numbers with unit to user space float numbers - self.options.month_width = self.unittouu( self.options.month_width ) - self.options.month_margin = self.unittouu( self.options.month_margin ) - - # initial values - month_x_pos = 0 - month_y_pos = 0 - weeknr = 0 - - def calculate_size_and_positions(self): - #month_margin month_width months_per_line auto_organize - self.doc_w = self.unittouu(self.document.getroot().get('width')) - self.doc_h = self.unittouu(self.document.getroot().get('height')) - if self.options.show_weeknr: - self.cols_before = 1 - else: - self.cols_before = 0 - if self.options.auto_organize: - if self.doc_h > self.doc_w: - self.months_per_line = 3 - else: - self.months_per_line = 4 - else: - self.months_per_line = self.options.months_per_line - #self.month_w = self.doc_w / self.months_per_line - if self.options.auto_organize: - self.month_w = (self.doc_w * 0.8) / self.months_per_line - self.month_margin = self.month_w / 10 - else: - self.month_w = self.options.month_width - self.month_margin = self.options.month_margin - self.day_w = self.month_w / (7 + self.cols_before) - self.day_h = self.month_w / 9 - self.month_h = self.day_w * 7 - if self.options.month == 0: - self.year_margin = ((self.doc_w + self.day_w - \ - (self.month_w * self.months_per_line) - \ - (self.month_margin * \ - (self.months_per_line - 1))) / 2) #- self.month_margin - else: - self.year_margin = (self.doc_w - self.month_w) / 2 - self.style_day = { - 'font-size': str(self.day_w / 2), - 'font-family': 'arial', - 'text-anchor': 'middle', - 'text-align': 'center', - 'fill': self.options.color_day - } - self.style_weekend = self.style_day.copy() - self.style_weekend['fill'] = self.options.color_weekend - self.style_nmd = self.style_day.copy() - self.style_nmd['fill'] = self.options.color_nmd - self.style_month = self.style_day.copy() - self.style_month['fill'] = self.options.color_month - self.style_month['font-size'] = str(self.day_w / 1.5) - self.style_month['font-weight'] = 'bold' - self.style_day_name = self.style_day.copy() - self.style_day_name['fill'] = self.options.color_day_name - self.style_day_name['font-size'] = str(self.day_w / 3 ) - self.style_year = self.style_day.copy() - self.style_year['fill'] = self.options.color_year - self.style_year['font-size'] = str(self.day_w * 2) - self.style_year['font-weight'] = 'bold' - self.style_weeknr = self.style_day.copy() - self.style_weeknr['fill'] = self.options.color_weeknr - self.style_weeknr['font-size'] = str(self.day_w / 3) - - def is_weekend(self, pos): - # weekend values: "sat+sun" or "sat" or "sun" - if self.options.start_day == 'sun': - if self.options.weekend == 'sat+sun' and pos == 0: return True - if self.options.weekend == 'sat+sun' and pos == 6: return True - if self.options.weekend == 'sat' and pos == 6: return True - if self.options.weekend == 'sun' and pos == 0: return True - else: - if self.options.weekend == 'sat+sun' and pos == 5: return True - if self.options.weekend == 'sat+sun' and pos == 6: return True - if self.options.weekend == 'sat' and pos == 5: return True - if self.options.weekend == 'sun' and pos == 6: return True - return False - - def in_line_month(self, cal): - cal2 = [] - for week in cal: - for day in week: - if day != 0: - cal2.append(day) - return cal2 - - def write_month_header(self, g, m): - txt_atts = {'style': simplestyle.formatStyle(self.style_month), - 'x': str((self.month_w - self.day_w) / 2), - 'y': str(self.day_h / 5 )} - try: - inkex.etree.SubElement(g, 'text', txt_atts).text = unicode( - self.options.month_names[m-1], - self.options.input_encode) - except: - inkex.errormsg(_('You must select a correct system encoding.')) - exit(1) - gw = inkex.etree.SubElement(g, 'g') - week_x = 0 - if self.options.start_day=='sun': - day_names = self.options.day_names[:] - else: - day_names = self.options.day_names[1:] - day_names.append(self.options.day_names[0]) - - if self.options.show_weeknr: - day_names.insert(0, self.options.weeknr_name) - - for wday in day_names: - txt_atts = {'style': simplestyle.formatStyle(self.style_day_name), - 'x': str( self.day_w * week_x ), - 'y': str( self.day_h ) } - try: - inkex.etree.SubElement(gw, 'text', txt_atts).text = unicode( - wday, - self.options.input_encode) - except: - inkex.errormsg(_('You must select a correct system encoding.')) - exit(1) - week_x += 1 - - def create_month(self, m): - txt_atts = { - 'transform': 'translate(' + - str(self.year_margin + \ - (self.month_w + self.month_margin) * \ - self.month_x_pos) + \ - ',' + \ - str((self.day_h * 4) + \ - (self.month_h * self.month_y_pos)) + \ - ')', - 'id': 'month_' + \ - str(m) + \ - '_' + \ - str(self.options.year)} - g = inkex.etree.SubElement(self.year_g, 'g', txt_atts) - self.write_month_header(g, m) - gdays = inkex.etree.SubElement(g, 'g') - cal = calendar.monthcalendar(self.options.year,m) - if m == 1: - 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)) - if m == 12: - next_month = \ - self.in_line_month(calendar.monthcalendar(self.options.year + 1, 1)) - else: - next_month = \ - self.in_line_month(calendar.monthcalendar(self.options.year, m + 1)) - if len(cal) < 6: - # add a line after the last week - cal.append([0, 0, 0, 0, 0, 0, 0]) - if len(cal) < 6: - # add a line before the first week (Feb 2009) - cal.reverse() - cal.append([0, 0, 0, 0, 0, 0, 0]) - cal.reverse() - # How mutch before month days will be showed: - bmd = cal[0].count(0) + cal[1].count(0) - before = True - week_y = 0 - for week in cal: - if (self.weeknr != 0 and \ - ((self.options.start_day == 'mon' and week[0] != 0) or \ - (self.options.start_day == 'sun' and week[1] != 0))) or \ - (self.weeknr == 0 and \ - ((self.options.start_day == 'mon' and week[3] > 0) or \ - (self.options.start_day == 'sun' and week[4] > 0))): - self.weeknr += 1 - week_x = 0 - if self.options.show_weeknr: - # Remove leap week (starting previous year) and empty weeks - if self.weeknr != 0 and not (week[0] == 0 and week[6] == 0): - style = self.style_weeknr - txt_atts = {'style': simplestyle.formatStyle(style), - 'x': str(self.day_w * week_x), - 'y': str(self.day_h * (week_y + 2))} - inkex.etree.SubElement(gdays, 'text', txt_atts).text = str(self.weeknr) - week_x += 1 - else: - week_x += 1 - for day in week: - style = self.style_day - if self.is_weekend(week_x - self.cols_before): style = self.style_weekend - if day == 0: style = self.style_nmd - txt_atts = {'style': simplestyle.formatStyle(style), - '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: - if before: - inkex.etree.SubElement(gdays, 'text', txt_atts).text = str(before_month[-bmd]) - bmd -= 1 - else: - inkex.etree.SubElement(gdays, 'text', txt_atts).text = str(next_month[bmd]) - bmd += 1 - else: - inkex.etree.SubElement(gdays, 'text', txt_atts).text = str(day) - before = False - week_x += 1 - week_y += 1 - self.month_x_pos += 1 - if self.month_x_pos >= self.months_per_line: - self.month_x_pos = 0 - self.month_y_pos += 1 - - def effect(self): - self.validate_options() - self.calculate_size_and_positions() - parent = self.document.getroot() - txt_atts = {'id': 'year_'+str(self.options.year) } - self.year_g = inkex.etree.SubElement(parent, 'g', txt_atts) - txt_atts = {'style': simplestyle.formatStyle(self.style_year), - 'x': str(self.doc_w / 2 ), - 'y': str(self.day_w * 1.5)} - inkex.etree.SubElement(self.year_g, 'text', txt_atts).text = str(self.options.year) - if self.options.month == 0: - for m in range(1, 13): - self.create_month(m) - else: - self.create_month(self.options.month) - - -if __name__ == '__main__': #pragma: no cover - e = SVGCalendar() - e.affect() diff --git a/share/extensions/svgfont2layers.inx b/share/extensions/svgfont2layers.inx deleted file mode 100644 index 5d66af341..000000000 --- a/share/extensions/svgfont2layers.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Convert SVG Font to Glyph Layers</_name> - <id>org.inkscape.typography.svgfont2layers</id> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">simplepath.py</dependency> - <dependency type="executable" location="extensions">svgfont2layers.py</dependency> - <param name="limitglyphs" type="boolean" _gui-text="Load only the first 30 glyphs (Recommended)"></param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Typography"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">svgfont2layers.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/svgfont2layers.py b/share/extensions/svgfont2layers.py deleted file mode 100755 index 1a392c72c..000000000 --- a/share/extensions/svgfont2layers.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2011 Felipe Correa da Silva Sanches <juca@members.fsf.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import sys -import simplepath - -class SVGFont2Layers(inkex.Effect): - def __init__(self): - self.count=0 - inkex.Effect.__init__(self) - self.OptionParser.add_option("--limitglyphs", - action="store", type="inkbool", - dest="limitglyphs", default=True, - help="Load only the first 30 glyphs from the SVGFont (otherwise the loading process may take a very long time)") - - def create_horiz_guideline(self, label, y): - namedview = self.svg.find(inkex.addNS('namedview', 'sodipodi')) - guide = inkex.etree.SubElement(namedview, inkex.addNS('guide', 'sodipodi')) - guide.set(inkex.addNS('label', 'inkscape'), label) - guide.set("orientation", "0,1") - guide.set("position", "0,"+str(y)) - - def get_or_create(self, parentnode, nodetype): - node = parentnode.find(nodetype) - if node is None: - node = inkex.etree.SubElement(parentnode, nodetype) - return node - - def flip_cordinate_system(self, d, emsize, baseline): - pathdata = simplepath.parsePath(d) - simplepath.scalePath(pathdata, 1,-1) - simplepath.translatePath(pathdata, 0, int(emsize) - int(baseline)) - return simplepath.formatPath(pathdata) - - def effect(self): - # Get access to main SVG document element - self.svg = self.document.getroot() - self.defs = self.svg.find(inkex.addNS('defs', 'svg')) - - #TODO: detect files with multiple svg fonts declared. - # Current code only reads the first svgfont instance - font = self.defs.find(inkex.addNS('font', 'svg')) - setwidth = font.get("horiz-adv-x") - baseline = font.get("horiz-origin-y") - if baseline is None: - baseline = 0 - - fontface = font.find(inkex.addNS('font-face', 'svg')) - - #TODO: where should we save the font family name? - #fontfamily = fontface.get("font-family") - emsize = fontface.get("units-per-em") - - #TODO: should we guarantee that <svg:font horiz-adv-x> equals <svg:font-face units-per-em> ? - caps = fontface.get("cap-height") - xheight = fontface.get("x-height") - ascender = fontface.get("ascent") - descender = fontface.get("descent") - - self.svg.set("width", emsize) - self.create_horiz_guideline("baseline", int(baseline)) - self.create_horiz_guideline("ascender", int(baseline) + int(ascender)) - self.create_horiz_guideline("caps", int(baseline) + int(caps)) - self.create_horiz_guideline("xheight", int(baseline) + int(xheight)) - self.create_horiz_guideline("descender", int(baseline) - int(descender)) - - #TODO: missing-glyph - glyphs = font.findall(inkex.addNS('glyph', 'svg')) - first_glyph = True - for glyph in glyphs: - unicode_char = glyph.get("unicode") - if unicode_char is None: - continue - - layer = inkex.etree.SubElement(self.svg, inkex.addNS('g', 'svg')) - layer.set(inkex.addNS('label', 'inkscape'), "GlyphLayer-" + unicode_char) - layer.set(inkex.addNS('groupmode', 'inkscape'), "layer") - - #glyph layers (except the first one) are innitially hidden - if not first_glyph: - layer.set("style", "display:none") - first_glyph = False - - #TODO: interpret option 1 - - ############################ - #Option 1: - # Using clone (svg:use) as childnode of svg:glyph - - #use = self.get_or_create(glyph, inkex.addNS('use', 'svg')) - #use.set(inkex.addNS('href', 'xlink'), "#"+group.get("id")) - #TODO: This code creates <use> nodes but they do not render on svg fonts dialog. why? - - ############################ - #Option 2: - # Using svg:paths as childnodes of svg:glyph - - paths = glyph.findall(inkex.addNS('path', 'svg')) - for path in paths: - d = path.get("d") - if d is None: - continue - d = self.flip_cordinate_system(d, emsize, baseline) - new_path = inkex.etree.SubElement(layer, inkex.addNS('path', 'svg')) - new_path.set("d", d) - - ############################ - #Option 3: - # Using curve description in d attribute of svg:glyph - - d = glyph.get("d") - if d is None: - continue - d = self.flip_cordinate_system(d, emsize, baseline) - path = inkex.etree.SubElement(layer, inkex.addNS('path', 'svg')) - path.set("d", d) - - self.count+=1 - if self.options.limitglyphs and self.count>=30: - break - -if __name__ == '__main__': - e = SVGFont2Layers() - e.affect() - diff --git a/share/extensions/synfig_fileformat.py b/share/extensions/synfig_fileformat.py deleted file mode 100755 index 6c93e6b87..000000000 --- a/share/extensions/synfig_fileformat.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env python -""" -synfig_fileformat.py -Synfig file format utilities - -Copyright (C) 2011 Nikita Kitaev - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -###### Constants ########################################## -kux = 60.0 # Number of SVG units (pixels) per Synfig "unit" -gamma = 2.2 -tangent_scale = 3.0 # Synfig tangents are scaled by a factor of 3 - - - -###### Layer parameters, types, and default values ######## -layers = {} - -# Layer_Composite is the parent of most layers -default_composite = { - "z_depth": ["real", 0.0], - "amount": ["real", 1.0], - "blend_method": ["integer", 0], - } - -layers["PasteCanvas"] = default_composite.copy() -layers["PasteCanvas"].update({ - "origin": ["vector", [0.0, 0.0]], - "canvas": ["canvas", None], - "zoom": ["real", 0.0], - "time_offset": ["time", "0s"], - "children_lock": ["bool", False], - "focus": ["vector", [0.0, 0.0]] - }) - - -## Layers in mod_geometry - -layers["circle"] = default_composite.copy() -layers["circle"].update({ - "color": ["color", [0,0,0,1]], - "radius": ["real", 1.0], - "feather": ["real", 0.0], - "origin": ["vector", [0.0, 0.0]], - "invert": ["bool", False], - "falloff": ["integer", 2] - }) - -layers["rectangle"] = default_composite.copy() -layers["rectangle"].update({ - "color": ["color", [0,0,0,1]], - "point1": ["vector", [0,0]], - "point2": ["vector", [1,1]], - "expand": ["real", 0.0], - "invert": ["bool", False] - }) - -default_shape = default_composite.copy() -default_shape.update({ - "color": ["color", [0,0,0,1]], - "origin": ["vector", [0.0, 0.0]], - "invert": ["bool", False], - "antialias": ["bool", True], - "feather": ["real", 0.0], - "blurtype": ["integer", 1], - "winding_style": ["integer", 0] - }) - -layers["region"] = default_shape.copy() -layers["region"].update({ - "bline": ["bline", None] - }) - -layers["outline"] = default_shape.copy() -layers["outline"].update({ - "bline": ["bline", None], - "round_tip[0]": ["bool", True], - "round_tip[1]": ["bool", True], - "sharp_cusps": ["bool", True], - "width": ["real", 1.0], - "loopyness": ["real", 1.0], - "expand": ["real", 0.0], - "homogeneous_width": ["bool", True] - }) - - -## Layers in mod_gradient - -layers["linear_gradient"] = default_composite.copy() -layers["linear_gradient"].update({ - "p1": ["vector", [0,0]], - "p2": ["vector", [1,1]], - "gradient": ["gradient", {0.0:[0,0,0,1], 1.0:[1,1,1,1]} ], - "loop": ["bool", False], - "zigzag": ["bool", False] - }) - -layers["radial_gradient"] = default_composite.copy() -layers["radial_gradient"].update({ - "gradient": ["gradient", {0.0:[0,0,0,1], 1.0:[1,1,1,1]} ], - "center": ["vector", [0,0]], - "radius": ["real", 1.0], - "loop": ["bool", False], - "zigzag": ["bool", False] - }) - - -## Layers in lyr_std - -layers["import"] = default_composite.copy() -layers["import"].update({ - "tl": ["vector", [-1,1]], - "br": ["vector", [1,-1]], - "c": ["integer", 1], - "gamma_adjust": ["real", 1.0], - "filename": ["string", ""], # <string>foo</string> - "time_offset": ["time", "0s"] - }) - -# transforms are not blending -layers["warp"] = { - "src_tl": ["vector", [-1,1]], - "src_br": ["vector", [1,-1]], - "dest_tl": ["vector", [-1,1]], - "dest_tr": ["vector", [1,1]], - "dest_br": ["vector", [1,-1]], - "dest_bl": ["vector", [-1,-1]], - "clip": ["bool", False], - "horizon": ["real", 4.0] - } - -layers["rotate"] = { - "origin": ["vector", [0.0, 0.0]], - "amount": ["angle", 0] # <angle value=.../> - } - -layers["translate"] = { - "origin": ["vector", [0.0, 0.0]] - } - -## Layers in mod_filter -layers["blur"] = default_composite.copy() -layers["blur"].update({ - "size": ["vector", [1,1]], - "type": ["integer", 3] # 1 is fast gaussian, 3 is regular - }) - - -###### Layer versions ##################################### -layer_versions = { - "outline" : "0.2", - "rectangle" : "0.2", - "linear_gradient" : "0.0", - "blur" : "0.2", - None : "0.1" # default - } - -###### Blend Methods ###################################### -blend_method_names = { - 0 : "composite", - 1 : "straight", - 13 : "onto", - 21 : "straight onto", - 12 : "behind", - 16 : "screen", - 20 : "overlay", - 17 : "hand light", - 6 : "multiply", - 7 : "divide", - 4 : "add", - 5 : "subtract", - 18 : "difference", - 2 : "brighten", - 3 : "darken", - 8 : "color", - 9 : "hue", - 10 : "saturation", - 11 : "luminance", - 14 : "alpha brighten", #deprecated - 15 : "alpha darken", #deprecated - 19 : "alpha over" #deprecated - } - -blend_methods = dict((v, k) for (k, v) in blend_method_names.iteritems()) - -###### Functions ########################################## -def paramType(layer, param, value=None): - if layer in layers.keys(): - layer_params = layers[layer] - if param in layer_params.keys(): - return layer_params[param][0] - else: - raise Exception, "Invalid parameter type for layer" - else: - # Unknown layer, try to determine parameter type based on value - if value is None: - raise Exception, "No information for given layer" - if type(value) == int: - return "integer" - elif type(value) == float: - return "real" - elif type(value) == bool: - return "bool" - elif type(value) == dict: - if "points" in value.keys(): - return "bline" - elif 0.0 in value.keys(): - return "gradient" - else: - raise Exception, "Could not automatically determine parameter type" - elif type(value) == list: - if len(value) == 2: - return "vector" - elif len(value) == 3 or len(value) == 4: - return "color" - else: - # The first two could also be canvases - return "canvas" - elif type(value) == str: - return "string" - -def defaultLayerVersion(layer): - if layer in layer_versions.keys(): - return layer_versions[layer] - else: - return layer_versions[None] - -def defaultLayerParams(layer): - if layer in layers.keys(): - return layers[layer].copy() - else: - return {} diff --git a/share/extensions/synfig_output.inx b/share/extensions/synfig_output.inx deleted file mode 100644 index e947567b7..000000000 --- a/share/extensions/synfig_output.inx +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Synfig Output</_name> - <id>org.inkscape.output.sif</id> - <dependency type="executable" location="extensions">synfig_fileformat.py</dependency> - <dependency type="executable" location="extensions">synfig_output.py</dependency> - <dependency type="executable" location="extensions">synfig_prepare.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.sif</extension> - <mimetype>image/sif</mimetype> - <_filetypename>Synfig Animation (*.sif)</_filetypename> - <_filetypetooltip>Synfig Animation written using the sif-file exporter extension</_filetypetooltip> - <dataloss>true</dataloss> - </output> - <script> - <command reldir="extensions" - interpreter="python">synfig_output.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/synfig_output.py b/share/extensions/synfig_output.py deleted file mode 100755 index a69981bc8..000000000 --- a/share/extensions/synfig_output.py +++ /dev/null @@ -1,1347 +0,0 @@ -#!/usr/bin/env python -""" -synfig_output.py -An Inkscape extension for exporting Synfig files (.sif) - -Copyright (C) 2011 Nikita Kitaev - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" -import sys -import math -import uuid -from copy import deepcopy - -import inkex -from inkex import NSS, addNS, etree, errormsg -import simplepath, simplestyle, simpletransform -import cubicsuperpath - -from synfig_prepare import SynfigPrep, MalformedSVGError, get_dimension -import synfig_fileformat as sif - -###### Utility Classes #################################### -class UnsupportedException(Exception): - """When part of an element is not supported, this exception is raised to invalidate the whole element""" - pass - -class SynfigDocument(object): - """A synfig document, with commands for adding layers and layer parameters""" - def __init__(self, width=1024, height=768, name="Synfig Animation 1"): - self.root_canvas = etree.fromstring( - """ -<canvas - version="0.5" - width="%f" - height="%f" - xres="2834.645752" - yres="2834.645752" - view-box="0 0 0 0" - > - <name>%s</name> -</canvas> -""" % (width, height, name) - ) - - self._update_viewbox() - - self.gradients = {} - self.filters = {} - - ### Properties - - def get_root_canvas(self): - return self.root_canvas - - def get_root_tree(self): - return self.root_canvas.getroottree() - - def _update_viewbox(self): - """Update the viewbox to match document width and height""" - attr_viewbox = "%f %f %f %f" % ( - -self.width/2.0/sif.kux, - self.height/2.0/sif.kux, - self.width/2.0/sif.kux, - -self.height/2.0/sif.kux - ) - self.root_canvas.set("view-box", attr_viewbox) - - def get_width(self): - return float(self.root_canvas.get("width", "0")) - - def set_width(self, value): - self.root_canvas.set("width", str(value)) - self._update_viewbox() - - def get_height(self): - return float(self.root_canvas.get("height", "0")) - - def set_height(self, value): - self.root_canvas.set("height", str(value)) - self._update_viewbox() - - def get_name(self): - return self.root_canvas.get("name", "") - - def set_name(self, value): - self.root_canvas.set("name", value) - self._update_viewbox() - - width = property(get_width, set_width) - height = property(get_height, set_height) - name = property(get_name, set_name) - - ### Public utility functions - - def new_guid(self): - """Generate a new GUID""" - return uuid.uuid4().hex - - ### Coordinate system conversions - - def distance_svg2sif(self, distance): - """Convert distance from SVG to Synfig units""" - return distance/sif.kux - - def distance_sif2svg(self, distance): - """Convert distance from Synfig to SVG units""" - return distance*sif.kux - - def coor_svg2sif(self, vector): - """Convert SVG coordinate [x, y] to Synfig units""" - x = vector[0] - y = self.height - vector[1] - - x -= self.width/2.0 - y -= self.height/2.0 - x /= sif.kux - y /= sif.kux - - return [x, y] - - def coor_sif2svg(self, vector): - """Convert Synfig coordinate [x, y] to SVG units""" - x = vector[0] * sif.kux + self.width/2.0 - y = vector[1] * sif.kux + self.height/2.0 - - y = self.height - y - - assert self.coor_svg2sif([x, y]) == vector, "sif to svg coordinate conversion error" - - return [x, y] - - def list_coor_svg2sif(self, l): - """Scan a list for coordinate pairs and convert them to Synfig units""" - # If list has two numerical elements, - # treat it as a coordinate pair - if type(l) == list and len(l) == 2: - if type(l[0]) == int or type(l[0]) == float: - if type(l[1]) == int or type(l[1]) == float: - l_sif = self.coor_svg2sif(l) - l[0] = l_sif[0] - l[1] = l_sif[1] - return - - # Otherwise recursively iterate over the list - for x in l: - if type(x) == list: - self.list_coor_svg2sif(x) - - def list_coor_sif2svg(self, l): - """Scan a list for coordinate pairs and convert them to SVG units""" - # If list has two numerical elements, - # treat it as a coordinate pair - if type(l) == list and len(l) == 2: - if type(l[0]) == int or type(l[0]) == float: - if type(l[1]) == int or type(l[1]) == float: - l_sif = self.coor_sif2svg(l) - l[0] = l_sif[0] - l[1] = l_sif[1] - return - - # Otherwise recursively iterate over the list - for x in l: - if type(x) == list: - self.list_coor_sif2svg(x) - - def bline_coor_svg2sif(self, b): - """Convert a BLine from SVG to Synfig coordinate units""" - self.list_coor_svg2sif(b["points"]) - - def bline_coor_sif2svg(self, b): - """Convert a BLine from Synfig to SVG coordinate units""" - self.list_coor_sif2svg(b["points"]) - - ### XML Builders -- private - ### used to create XML elements in the Synfig document - - def build_layer(self, layer_type, desc, canvas=None, active=True, version="auto"): - """Build an empty layer""" - if canvas is None: - layer = self.root_canvas.makeelement("layer") - else: - layer = etree.SubElement(canvas, "layer") - - layer.set("type", layer_type) - layer.set("desc", desc) - if active: - layer.set("active", "true") - else: - layer.set("active", "false") - - if version == "auto": - version = sif.defaultLayerVersion(layer_type) - - if type(version) == float: - version = str(version) - - layer.set("version", version) - - return layer - - - def _calc_radius(self, p1x, p1y, p2x, p2y): - """Calculate radius of a tangent given two points""" - # Synfig tangents are scaled by a factor of 3 - return sif.tangent_scale * math.sqrt( (p2x-p1x)**2 + (p2y-p1y)**2 ) - - def _calc_angle(self, p1x, p1y, p2x, p2y): - """Calculate angle (in radians) of a tangent given two points""" - dx = p2x-p1x - dy = p2y-p1y - if dx > 0 and dy > 0: - ag = math.pi + math.atan(dy/dx) - elif dx > 0 and dy < 0: - ag = math.pi + math.atan(dy/dx) - elif dx < 0 and dy < 0: - ag = math.atan(dy/dx) - elif dx < 0 and dy > 0: - ag = 2*math.pi + math.atan(dy/dx) - elif dx == 0 and dy > 0: - ag = -1*math.pi/2 - elif dx == 0 and dy < 0: - ag = math.pi/2 - elif dx == 0 and dy == 0: - ag = 0 - elif dx < 0 and dy == 0: - ag = 0 - elif dx > 0 and dy == 0: - ag = math.pi - - return (ag*180)/math.pi - - def build_param(self, layer, name, value, param_type="auto", guid=None): - """Add a parameter node to a layer""" - if layer is None: - param = self.root_canvas.makeelement("param") - else: - param = etree.SubElement(layer, "param") - param.set("name", name) - - #Automatically detect param_type - if param_type == "auto": - if layer is not None: - layer_type = layer.get("type") - param_type = sif.paramType(layer_type, name) - else: - param_type = sif.paramType(None, name, value) - - if param_type == "real": - el = etree.SubElement(param, "real") - el.set("value", str(float(value))) - elif param_type == "integer": - el = etree.SubElement(param, "integer") - el.set("value", str(int(value))) - elif param_type == "vector": - el = etree.SubElement(param, "vector") - x = etree.SubElement(el, "x") - x.text = str(float(value[0])) - y = etree.SubElement(el, "y") - y.text = str(float(value[1])) - elif param_type == "color": - el = etree.SubElement(param, "color") - r = etree.SubElement(el, "r") - r.text = str(float(value[0])) - g = etree.SubElement(el, "g") - g.text = str(float(value[1])) - b = etree.SubElement(el, "b") - b.text = str(float(value[2])) - a = etree.SubElement(el, "a") - a.text = str(float(value[3])) if len(value) > 3 else "1.0" - elif param_type == "gradient": - el = etree.SubElement(param, "gradient") - # Value is a dictionary of color stops - # see get_gradient() - for pos in value.keys(): - color = etree.SubElement(el, "color") - color.set("pos", str(float(pos))) - - c = value[pos] - - r = etree.SubElement(color, "r") - r.text = str(float(c[0])) - g = etree.SubElement(color, "g") - g.text = str(float(c[1])) - b = etree.SubElement(color, "b") - b.text = str(float(c[2])) - a = etree.SubElement(color, "a") - a.text = str(float(c[3])) if len(c) > 3 else "1.0" - elif param_type == "bool": - el = etree.SubElement(param, "bool") - if value: - el.set("value", "true") - else: - el.set("value", "false") - elif param_type == "time": - el = etree.SubElement(param, "time") - if type(value) == int: - el.set("value", "%ds" % value) - elif type(value) == float: - el.set("value", "%fs" % value) - elif type(value) == str: - el.set("value", value) - elif param_type == "bline": - el = etree.SubElement(param, "bline") - el.set("type", "bline_point") - - # value is a bline (dictionary type), see path_to_bline_list - if value["loop"] == True: - el.set("loop", "true") - else: - el.set("loop", "false") - - for vertex in value["points"]: - x = float(vertex[1][0]) - y = float(vertex[1][1]) - - tg1x = float(vertex[0][0]) - tg1y = float(vertex[0][1]) - - tg2x = float(vertex[2][0]) - tg2y = float(vertex[2][1]) - - tg1_radius = self._calc_radius(x, y, tg1x, tg1y) - tg1_angle = self._calc_angle(x, y, tg1x, tg1y) - - tg2_radius = self._calc_radius(x, y, tg2x, tg2y) - tg2_angle = self._calc_angle(x, y, tg2x, tg2y)-180.0 - - if vertex[3]: - split = "true" - else: - split = "false" - - entry = etree.SubElement(el, "entry") - composite = etree.SubElement(entry, "composite") - composite.set("type", "bline_point") - - point = etree.SubElement(composite, "point") - vector = etree.SubElement(point, "vector") - etree.SubElement(vector, "x").text = str(x) - etree.SubElement(vector, "y").text = str(y) - - width = etree.SubElement(composite, "width") - etree.SubElement(width, "real").set("value", "1.0") - - origin = etree.SubElement(composite, "origin") - etree.SubElement(origin, "real").set("value", "0.5") - - split_el = etree.SubElement(composite, "split") - etree.SubElement(split_el, "bool").set("value", split) - - t1 = etree.SubElement(composite, "t1") - t2 = etree.SubElement(composite, "t2") - - t1_rc = etree.SubElement(t1, "radial_composite") - t1_rc.set("type", "vector") - - t2_rc = etree.SubElement(t2, "radial_composite") - t2_rc.set("type", "vector") - - t1_r = etree.SubElement(t1_rc, "radius") - t2_r = etree.SubElement(t2_rc, "radius") - t1_radius = etree.SubElement(t1_r, "real") - t2_radius = etree.SubElement(t2_r, "real") - t1_radius.set("value", str(tg1_radius)) - t2_radius.set("value", str(tg2_radius)) - - t1_t = etree.SubElement(t1_rc, "theta") - t2_t = etree.SubElement(t2_rc, "theta") - t1_angle = etree.SubElement(t1_t, "angle") - t2_angle = etree.SubElement(t2_t, "angle") - t1_angle.set("value", str(tg1_angle)) - t2_angle.set("value", str(tg2_angle)) - elif param_type == "canvas": - el = etree.SubElement(param, "canvas") - el.set("xres", "10.0") - el.set("yres", "10.0") - - # "value" is a list of layers - if value is not None: - for layer in value: - el.append(layer) - else: - raise AssertionError, "Unsupported param type %s" % (param_type) - - if guid: - el.set("guid", guid) - else: - el.set("guid", self.new_guid()) - - return param - - ### Public layer API - ### Should be used by outside functions to create layers and set layer parameters - - def create_layer(self, layer_type, desc, params={}, guids={}, canvas=None, active=True, version="auto"): - """Create a new layer - - Keyword arguments: - layer_type -- layer type string used internally by Synfig - desc -- layer description - params -- a dictionary of parameter names and their values - guids -- a dictionary of parameter types and their guids (optional) - active -- set to False to create a hidden layer - """ - layer = self.build_layer(layer_type, desc, canvas, active, version) - default_layer_params = sif.defaultLayerParams(layer_type) - - for param_name in default_layer_params.keys(): - param_type = default_layer_params[param_name][0] - if param_name in params.keys(): - param_value = params[param_name] - else: - param_value = default_layer_params[param_name][1] - - if param_name in guids.keys(): - param_guid = guids[param_name] - else: - param_guid = None - - if param_value is not None: - self.build_param(layer, param_name, param_value, param_type, guid=param_guid) - - return layer - - def set_param(self, layer, name, value, param_type="auto", guid=None, modify_linked=False): - """Set a layer parameter - - Keyword arguments: - layer -- the layer to set the parameter for - name -- parameter name - value -- parameter value - param_type -- parameter type (default "auto") - guid -- guid of the parameter value - """ - if modify_linked: - raise AssertionError, "Modifying linked parameters is not supported" - - layer_type = layer.get("type") - assert layer_type, "Layer does not have a type" - - if param_type == "auto": - param_type = sif.paramType(layer_type, name) - - # Remove existing parameters with this name - existing = [] - for param in layer.iterchildren(): - if param.get("name") == name: - existing.append(param) - - if len(existing) == 0: - self.build_param(layer, name, value, param_type, guid) - elif len(existing) > 1: - raise AssertionError, "Found multiple parameters with the same name" - else: - new_param = self.build_param(None, name, value, param_type, guid) - layer.replace(existing[0], new_param) - - def set_params(self, layer, params={}, guids={}, modify_linked=False): - """Set layer parameters - - Keyword arguments: - layer -- the layer to set the parameter for - params -- a dictionary of parameter names and their values - guids -- a dictionary of parameter types and their guids (optional) - """ - for param_name in params.keys(): - if param_name in guids.keys(): - self.set_param(layer, param_name, params[param_name], guid=guids[param_name], modify_linked=modify_linked) - else: - self.set_param(layer, param_name, params[param_name], modify_linked=modify_linked) - - def get_param(self, layer, name, param_type="auto"): - """Get the value of a layer parameter - - Keyword arguments: - layer -- the layer to get the parameter from - name -- param name - param_type -- parameter type (default "auto") - - NOT FULLY IMPLEMENTED - """ - layer_type = layer.get("type") - assert layer_type, "Layer does not have a type" - - if param_type == "auto": - param_type = sif.paramType(layer_type, name) - - for param in layer.iterchildren(): - if param.get("name") == name: - if param_type == "real": - return float(param[0].get("value", "0")) - elif param_type == "integer": - return int(param[0].get("integer", "0")) - else: - raise Exception, "Getting this type of parameter not yet implemented" - - ### Global defs, and related - - # SVG Filters - def add_filter(self, filter_id, f): - """Register a filter""" - self.filters[filter_id] = f - - # SVG Gradients - def add_linear_gradient(self, gradient_id, p1, p2, mtx=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], stops=[], link="", spread_method="pad"): - """Register a linear gradient definition""" - gradient = { - "type" : "linear", - "p1" : p1, - "p2" : p2, - "mtx" : mtx, - "spreadMethod": spread_method - } - if stops != []: - gradient["stops"] = stops - gradient["stops_guid"] = self.new_guid() - elif link != "": - gradient["link"] = link - else: - raise MalformedSVGError, "Gradient has neither stops nor link" - self.gradients[gradient_id] = gradient - - def add_radial_gradient(self, gradient_id, center, radius, focus, mtx=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], stops=[], link="", spread_method="pad"): - """Register a radial gradient definition""" - gradient = { - "type" : "radial", - "center" : center, - "radius" : radius, - "focus" : focus, - "mtx" : mtx, - "spreadMethod": spread_method - } - if stops != []: - gradient["stops"] = stops - gradient["stops_guid"] = self.new_guid() - elif link != "": - gradient["link"] = link - else: - raise MalformedSVGError, "Gradient has neither stops nor link" - self.gradients[gradient_id] = gradient - - def get_gradient(self, gradient_id): - """ - Return a gradient with a given id - - Linear gradient format: - { - "type" : "linear", - "p1" : [x, y], - "p2" : [x, y], - "mtx" : mtx, - "stops" : color stops, - "stops_guid": color stops guid, - "spreadMethod": "pad", "reflect", or "repeat" - } - - Radial gradient format: - { - "type" : "radial", - "center" : [x, y], - "radius" : r, - "focus" : [x, y], - "mtx" : mtx, - "stops" : color stops, - "stops_guid": color stops guid, - "spreadMethod": "pad", "reflect", or "repeat" - } - - Color stops format - { - 0.0 : color ([r,g,b,a] or [r,g,b]) at start, - [a number] : color at that position, - 1.0 : color at end - } - """ - - if gradient_id not in self.gradients.keys(): - return None - - gradient = self.gradients[gradient_id] - - # If the gradient has no link, we are done - if "link" not in gradient.keys() or gradient["link"] == "": - return gradient - - # If the gradient does have a link, find the color stops recursively - if gradient["link"] not in self.gradients.keys(): - raise MalformedSVGError, "Linked gradient ID not found" - - linked_gradient = self.get_gradient(gradient["link"]) - gradient["stops"] = linked_gradient["stops"] - gradient["stops_guid"] = linked_gradient["stops_guid"] - del gradient["link"] - - # Update the gradient in our listing - # (so recursive lookup only happens once) - self.gradients[gradient_id] = gradient - - return gradient - - def gradient_to_params(self, gradient): - """Transform gradient to a list of parameters to pass to a Synfig layer""" - # Create a copy of the gradient - g = gradient.copy() - - # Set synfig-only attribs - if g["spreadMethod"] == "repeat": - g["loop"] = True - elif g["spreadMethod"] == "reflect": - g["loop"] = True - # Reflect the gradient - # Original: 0.0 [A . B . C] 1.0 - # New: 0.0 [A . B . C . B . A] 1.0 - # (with gradient size doubled) - new_stops = {} - - # reflect the stops - for pos in g["stops"]: - val = g["stops"][pos] - if pos == 1.0: - new_stops[pos/2.0] = val - else: - new_stops[pos/2.0] = val - new_stops[1 - pos/2.0] = val - g["stops"] = new_stops - - # double the gradient size - if g["type"] == "linear": - g["p2"] = [ g["p1"][0]+2.0*(g["p2"][0]-g["p1"][0]), - g["p1"][1]+2.0*(g["p2"][1]-g["p1"][1]) ] - if g["type"] == "radial": - g["radius"]= 2.0*g["radius"] - - # Rename "stops" to "gradient" - g["gradient"] = g["stops"] - - # Convert coordinates - if g["type"] == "linear": - g["p1"] = self.coor_svg2sif(g["p1"]) - g["p2"] = self.coor_svg2sif(g["p2"]) - - if g["type"] == "radial": - g["center"] = self.coor_svg2sif(g["center"]) - g["radius"] = self.distance_svg2sif(g["radius"]) - - # Delete extra attribs - removed_attribs = ["type", - "stops", - "stops_guid", - "mtx", - "focus", - "spreadMethod"] - for x in removed_attribs: - if x in g.keys(): - del g[x] - return g - - ### Public operations API - # Operations act on a series of layers, and (optionally) on a series of named parameters - # The "is_end" attribute should be set to true when the layers are at the end of a canvas - # (i.e. when adding transform layers on top of them does not require encapsulation) - - def op_blur(self, layers, x, y, name="Blur", is_end=False): - """Gaussian blur the given layers by the given x and y amounts - - Keyword arguments: - layers -- list of layers - x -- x-amount of blur - y -- x-amount of blur - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - blur = self.create_layer("blur", name, params={ - "blend_method" : sif.blend_methods["straight"], - "size" : [x, y] - }) - - if is_end: - return layers + [blur] - else: - return self.op_encapsulate(layers + [blur]) - - def op_color(self, layers, overlay, is_end=False): - """Apply a color overlay to the given layers - - Should be used to apply a gradient or pattern to a shape - - Keyword arguments: - layers -- list of layers - overlay -- color layer to apply - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - if layers == []: - return layers - if overlay is None: - return layers - - overlay_enc = self.op_encapsulate([overlay]) - self.set_param(overlay_enc[0], "blend_method", sif.blend_methods["straight onto"]) - ret = layers + overlay_enc - - if is_end: - return ret - else: - return self.op_encapsulate(ret) - - def op_encapsulate(self, layers, name="Inline Canvas", is_end=False): - """Encapsulate the given layers - - Keyword arguments: - layers -- list of layers - name -- Name of the PasteCanvas layer that is created - is_end -- set to True if layers are at the end of a canvas - - Returns: list of one layer - """ - - if layers == []: - return layers - - layer = self.create_layer("PasteCanvas", name, params={"canvas":layers}) - return [layer] - - def op_fade(self, layers, opacity, is_end=False): - """Increase the opacity of the given layers by a certain amount - - Keyword arguments: - layers -- list of layers - opacity -- the opacity to apply (float between 0.0 to 1.0) - name -- name of the Transform layer that is added - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - # If there is blending involved, first encapsulate the layers - for layer in layers: - if self.get_param(layer, "blend_method") != sif.blend_methods["composite"]: - return self.op_fade(self.op_encapsulate(layers), opacity, is_end) - - # Otherwise, set their amount - for layer in layers: - amount = self.get_param(layer, "amount") - self.set_param(layer, "amount", amount*opacity) - - return layers - - - def op_filter(self, layers, filter_id, is_end=False): - """Apply a filter to the given layers - - Keyword arguments: - layers -- list of layers - filter_id -- id of the filter - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - if filter_id not in self.filters.keys(): - raise MalformedSVGError, "Filter %s not found" % filter_id - - try: - ret = self.filters[filter_id](self, layers, is_end) - assert type(ret) == list - return ret - except UnsupportedException: - # If the filter is not supported, ignore it. - return layers - - def op_set_blend(self, layers, blend_method, is_end=False): - """Set the blend method of the given group of layers - - If more than one layer is supplied, they will be encapsulated. - - Keyword arguments: - layers -- list of layers - blend_method -- blend method to give the layers - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - if layers == []: - return layers - if blend_method == "composite": - return layers - - layer = layers[0] - if len(layers) > 1 or self.get_param(layers[0], "amount") != 1.0: - layer = self.op_encapsulate(layers)[0] - - layer = deepcopy(layer) - - self.set_param(layer, "blend_method", sif.blend_methods[blend_method]) - - return [layer] - - def op_transform(self, layers, mtx, name="Transform", is_end=False): - """Apply a matrix transformation to the given layers - - Keyword arguments: - layers -- list of layers - mtx -- transformation matrix - name -- name of the Transform layer that is added - is_end -- set to True if layers are at the end of a canvas - - Returns: list of layers - """ - if layers == []: - return layers - if mtx is None or mtx == [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]: - return layers - - src_tl = [100, 100] - src_br = [200, 200] - - dest_tl = [100, 100] - dest_tr = [200, 100] - dest_br = [200, 200] - dest_bl = [100, 200] - - simpletransform.applyTransformToPoint(mtx, dest_tl) - simpletransform.applyTransformToPoint(mtx, dest_tr) - simpletransform.applyTransformToPoint(mtx, dest_br) - simpletransform.applyTransformToPoint(mtx, dest_bl) - - warp = self.create_layer("warp", name, params={ - "src_tl": self.coor_svg2sif(src_tl), - "src_br": self.coor_svg2sif(src_br), - "dest_tl": self.coor_svg2sif(dest_tl), - "dest_tr": self.coor_svg2sif(dest_tr), - "dest_br": self.coor_svg2sif(dest_br), - "dest_bl": self.coor_svg2sif(dest_bl) - } ) - - if is_end: - return layers + [warp] - else: - return self.op_encapsulate(layers + [warp]) - -###### Utility Functions ################################## - -### Path related - -def path_to_bline_list(path_d, nodetypes=None, mtx=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - """ - Convert a path to a BLine List - - bline_list format: - - Vertex: - [[tg1x, tg1y], [x,y], [tg2x, tg2y], split = T/F] - Vertex list: - [ vertex, vertex, vertex, ...] - Bline: - { - "points" : vertex_list, - "loop" : True / False - } - """ - - # Exit on empty paths - if not path_d: - return [] - - # Parse the path - path = simplepath.parsePath(path_d) - - # Append (more than) enough c's to the nodetypes - if nodetypes is None: - nt = "" - else: - nt = nodetypes - - for _ in range(len(path)): - nt += "c" - - # Create bline list - # borrows code from cubicsuperpath.py - - # bline_list := [bline, bline, ...] - # bline := { - # "points":[vertex, vertex, ...], - # "loop":True/False, - # } - - bline_list = [] - - subpathstart = [] - last = [] - lastctrl = [] - lastsplit = True - for s in path: - cmd, params = s - if cmd != "M" and bline_list == []: - raise MalformedSVGError, "Bad path data: path doesn't start with moveto, %s, %s" % (s, path) - elif cmd == "M": - # Add previous point to subpath - if last: - bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit]) - # Start a new subpath - bline_list.append({"nodetypes":"", "loop":False, "points":[]}) - # Save coordinates of this point - subpathstart = params[:] - last = params[:] - lastctrl = params[:] - lastsplit = False if nt[0] == "z" else True - nt = nt[1:] - elif cmd == 'L': - bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit]) - last = params[:] - lastctrl = params[:] - lastsplit = False if nt[0] == "z" else True - nt = nt[1:] - elif cmd == 'C': - bline_list[-1]["points"].append([lastctrl[:], last[:], params[:2], lastsplit]) - last = params[-2:] - lastctrl = params[2:4] - lastsplit = False if nt[0] == "z" else True - nt = nt[1:] - elif cmd == 'Q': - q0 = last[:] - q1 = params[0:2] - q2 = params[2:4] - x0 = q0[0] - x1 = 1./3*q0[0]+2./3*q1[0] - x2 = 2./3*q1[0]+1./3*q2[0] - x3 = q2[0] - y0 = q0[1] - y1 = 1./3*q0[1]+2./3*q1[1] - y2 = 2./3*q1[1]+1./3*q2[1] - y3 = q2[1] - bline_list[-1]["points"].append([lastctrl[:], [x0, y0], [x1, y1], lastsplit]) - last = [x3, y3] - lastctrl = [x2, y2] - lastsplit = False if nt[0] == "z" else True - nt = nt[1:] - elif cmd == 'A': - arcp = cubicsuperpath.ArcToPath(last[:], params[:]) - arcp[ 0][0] = lastctrl[:] - last = arcp[-1][1] - lastctrl = arcp[-1][0] - lastsplit = False if nt[0] == "z" else True - nt = nt[1:] - for el in arcp[:-1]: - el.append(True) - bline_list[-1]["points"].append(el) - elif cmd == "Z": - if len(bline_list[-1]["points"]) == 0: - # If the path "loops" after only one point - # e.g. "M 0 0 Z" - bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], False]) - elif last == subpathstart: - # If we are back to the original position - # merge our tangent into the first point - bline_list[-1]["points"][0][0] = lastctrl[:] - else: - # Otherwise draw a line to the starting point - bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit]) - - # Clear the variables (no more points need to be added) - last = [] - lastctrl = [] - lastsplit = True - - # Loop the subpath - bline_list[-1]["loop"] = True - - - # Append final superpoint, if needed - if last: - bline_list[-1]["points"].append([lastctrl[:], last[:], last[:], lastsplit]) - - # Apply the transformation - if mtx != [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]: - for bline in bline_list: - for vertex in bline["points"]: - for pt in vertex: - if type(pt) != bool: - simpletransform.applyTransformToPoint(mtx, pt) - - return bline_list - -### Style related - -def extract_style(node, style_attrib="style"): - #return simplestyle.parseStyle(node.get("style")) - - # Work around a simplestyle bug in older versions of Inkscape - # that leaves spaces at the beginning and end of values - s = node.get(style_attrib) - if s is None: - return {} - else: - return dict([[x.strip() for x in i.split(":")] for i in s.split(";") if len(i)]) - -def extract_color(style, color_attrib, *opacity_attribs): - if color_attrib in style.keys(): - if style[color_attrib] == "none": - return [1, 1, 1, 0] - c = simplestyle.parseColor(style[color_attrib]) - else: - c = (0, 0, 0) - - # Convert color scales and adjust gamma - color = [pow(c[0]/255.0, sif.gamma), pow(c[1]/255.0, sif.gamma), pow(c[2]/255.0, sif.gamma), 1.0] - - for opacity in opacity_attribs: - if opacity in style.keys(): - color[3] = color[3] * float(style[opacity]) - return color - -def extract_opacity(style, *opacity_attribs): - ret = 1.0 - for opacity in opacity_attribs: - if opacity in style.keys(): - ret = ret * float(style[opacity]) - return ret - -def extract_width(style, width_attrib, mtx): - if width_attrib in style.keys(): - width = get_dimension(style[width_attrib]) - else: - width = 1 - - area_scale_factor = mtx[0][0]*mtx[1][1] - mtx[0][1]*mtx[1][0] - linear_scale_factor = math.sqrt(abs(area_scale_factor)) - - return width*linear_scale_factor/sif.kux - - -###### Main Class ######################################### -class SynfigExport(SynfigPrep): - def __init__(self): - SynfigPrep.__init__(self) - - def effect(self): - # Prepare the document for exporting - SynfigPrep.effect(self) - svg = self.document.getroot() - width = get_dimension(svg.get("width", 1024)) - height = get_dimension(svg.get("height", 768)) - - title = svg.xpath("svg:title", namespaces=NSS) - if len(title) == 1: - name = title[0].text - else: - name = svg.get(addNS("docname", "sodipodi"), "Synfig Animation 1") - - d = SynfigDocument(width, height, name) - - layers = [] - for node in svg.iterchildren(): - layers += self.convert_node(node, d) - - root_canvas = d.get_root_canvas() - for layer in layers: - root_canvas.append(layer) - - d.get_root_tree().write(sys.stdout) - - def convert_node(self, node, d): - """Convert an SVG node to a list of Synfig layers""" - # Parse tags that don't draw any layers - if node.tag == addNS("namedview", "sodipodi"): - return [] - elif node.tag == addNS("defs", "svg"): - self.parse_defs(node, d) - return [] - elif node.tag == addNS("metadata", "svg"): - return [] - elif node.tag not in [ - addNS("g", "svg"), - addNS("a", "svg"), - addNS("switch", "svg"), - addNS("path", "svg")]: - # An unsupported element - return [] - - layers = [] - if node.tag == addNS("g", "svg"): - for subnode in node: - layers += self.convert_node(subnode, d) - if node.get(addNS("groupmode", "inkscape")) == "layer": - name = node.get(addNS("label", "inkscape"), "Inline Canvas") - layers = d.op_encapsulate(layers, name=name) - - elif (node.tag == addNS("a", "svg") - or node.tag == addNS("switch", "svg")): - # Treat anchor and switch as a group - for subnode in node: - layers += self.convert_node(subnode, d) - elif node.tag == addNS("path", "svg"): - layers = self.convert_path(node, d) - - style = extract_style(node) - if "filter" in style.keys() and style["filter"].startswith("url"): - filter_id = style["filter"][5:].split(")")[0] - layers = d.op_filter(layers, filter_id) - - opacity = extract_opacity(style, "opacity") - if opacity != 1.0: - layers = d.op_fade(layers, opacity) - - return layers - - def parse_defs(self, node, d): - for child in node.iterchildren(): - if child.tag == addNS("linearGradient", "svg"): - self.parse_gradient(child, d) - elif child.tag == addNS("radialGradient", "svg"): - self.parse_gradient(child, d) - elif child.tag == addNS("filter", "svg"): - self.parse_filter(child, d) - - def parse_gradient(self, node, d): - if node.tag == addNS("linearGradient", "svg"): - gradient_id = node.get("id", str(id(node))) - x1 = float(node.get("x1", "0.0")) - x2 = float(node.get("x2", "0.0")) - y1 = float(node.get("y1", "0.0")) - y2 = float(node.get("y2", "0.0")) - - mtx = simpletransform.parseTransform(node.get("gradientTransform")) - - link = node.get(addNS("href", "xlink"), "#")[1:] - spread_method = node.get("spreadMethod", "pad") - if link == "": - stops = self.parse_stops(node, d) - d.add_linear_gradient(gradient_id, [x1, y1], [x2, y2], mtx, stops=stops, spread_method=spread_method) - else: - d.add_linear_gradient(gradient_id, [x1, y1], [x2, y2], mtx, link=link, spread_method=spread_method) - elif node.tag == addNS("radialGradient", "svg"): - gradient_id = node.get("id", str(id(node))) - cx = float(node.get("cx", "0.0")) - cy = float(node.get("cy", "0.0")) - r = float(node.get("r", "0.0")) - fx = float(node.get("fx", "0.0")) - fy = float(node.get("fy", "0.0")) - - mtx = simpletransform.parseTransform(node.get("gradientTransform")) - - link = node.get(addNS("href", "xlink"), "#")[1:] - spread_method = node.get("spreadMethod", "pad") - if link == "": - stops = self.parse_stops(node, d) - d.add_radial_gradient(gradient_id, [cx, cy], r, [fx, fy], mtx, stops=stops, spread_method=spread_method) - else: - d.add_radial_gradient(gradient_id, [cx, cy], r, [fx, fy], mtx, link=link, spread_method=spread_method) - - def parse_stops(self, node, d): - stops = {} - for stop in node.iterchildren(): - if stop.tag == addNS("stop", "svg"): - offset = float(stop.get("offset")) - style = extract_style(stop) - stops[offset] = extract_color(style, "stop-color", "stop-opacity") - else: - raise MalformedSVGError, "Child of gradient is not a stop" - - return stops - - def parse_filter(self, node, d): - filter_id = node.get("id", str(id(node))) - - # A filter is just like an operator (the op_* functions), - # except that it's created here - def the_filter(d, layers, is_end=False): - refs = { None : layers, #default - "SourceGraphic" : layers } - encapsulate_result = not is_end - - for child in node.iterchildren(): - if child.get("in") not in refs: - # "SourceAlpha", "BackgroundImage", - # "BackgroundAlpha", "FillPaint", "StrokePaint" - # are not supported - raise UnsupportedException - l_in = refs[child.get("in")] - l_out = [] - if child.tag == addNS("feGaussianBlur", "svg"): - std_dev = child.get("stdDeviation", "0") - std_dev = std_dev.replace(",", " ").split() - x = float(std_dev[0]) - if len(std_dev) > 1: - y = float(std_dev[1]) - else: - y = x - - if x == 0 and y == 0: - l_out = l_in - else: - x = d.distance_svg2sif(x) - y = d.distance_svg2sif(y) - l_out = d.op_blur(l_in, x, y, is_end=True) - elif child.tag == addNS("feBlend", "svg"): - # Note: Blend methods are not an exact match - # because SVG uses alpha channel in places where - # Synfig does not - mode = child.get("mode", "normal") - if mode == "normal": - blend_method = "composite" - elif mode == "multiply": - blend_method = "multiply" - elif mode == "screen": - blend_method = "screen" - elif mode == "darken": - blend_method = "darken" - elif mode == "lighten": - blend_method = "brighten" - else: - raise MalformedSVGError, "Invalid blend method" - - if child.get("in2") == "BackgroundImage": - encapsulate_result = False - l_out = d.op_set_blend(l_in, blend_method) + d.op_set_blend(l_in, "behind") - elif child.get("in2") not in refs: - raise UnsupportedException - else: - l_in2 = refs[child.get("in2")] - l_out = l_in2 + d.op_set_blend(l_in, blend_method) - - else: - # This filter element is currently unsupported - raise UnsupportedException - - # Output the layers - if child.get("result"): - refs[child.get("result")] = l_out - - # Set the default for the next filter element - refs[None] = l_out - - # Return the output from the last element - if len(refs[None]) > 1 and encapsulate_result: - return d.op_encapsulate(refs[None]) - else: - return refs[None] - - d.add_filter(filter_id, the_filter) - - def convert_path(self, node, d): - """Convert an SVG path node to a list of Synfig layers""" - layers = [] - - node_id = node.get("id", str(id(node))) - style = extract_style(node) - mtx = simpletransform.parseTransform(node.get("transform")) - - blines = path_to_bline_list(node.get("d"), node.get(addNS("nodetypes", "sodipodi")), mtx) - for bline in blines: - d.bline_coor_svg2sif(bline) - bline_guid = d.new_guid() - - if style.setdefault("fill", "#000000") != "none": - if style["fill"].startswith("url"): - # Set the color to black, so we can later overlay - # the shape with a gradient or pattern - color = [0, 0, 0, 1] - else: - color = extract_color(style, "fill", "fill-opacity") - - layer = d.create_layer("region", node_id, { - "bline": bline, - "color": color, - "winding_style": 1 if style.setdefault("fill-rule", "nonzero") == "evenodd" else 0, - }, guids={ - "bline":bline_guid - } ) - - if style["fill"].startswith("url"): - color_layer = self.convert_url(style["fill"][5:].split(")")[0], mtx, d)[0] - layer = d.op_color([layer], overlay=color_layer)[0] - layer = d.op_fade([layer], extract_opacity(style, "fill-opacity"))[0] - - layers.append(layer) - - if style.setdefault("stroke", "none") != "none": - if style["stroke"].startswith("url"): - # Set the color to black, so we can later overlay - # the shape with a gradient or pattern - color = [0, 0, 0, 1] - else: - color = extract_color(style, "stroke", "stroke-opacity") - - layer = d.create_layer("outline", node_id, { - "bline": bline, - "color": color, - "width": extract_width(style, "stroke-width", mtx), - "sharp_cusps": True if style.setdefault("stroke-linejoin", "miter") == "miter" else False, - "round_tip[0]": False if style.setdefault("stroke-linecap", "butt") == "butt" else True, - "round_tip[1]": False if style.setdefault("stroke-linecap", "butt") == "butt" else True - }, guids={ - "bline":bline_guid - } ) - - if style["stroke"].startswith("url"): - color_layer = self.convert_url(style["stroke"][5:].split(")")[0], mtx, d)[0] - layer = d.op_color([layer], overlay=color_layer)[0] - layer = d.op_fade([layer], extract_opacity(style, "stroke-opacity"))[0] - - layers.append(layer) - - return layers - - def convert_url(self, url_id, mtx, d): - """Return a list Synfig layers that represent the gradient with the given id""" - gradient = d.get_gradient(url_id) - if gradient is None: - # Patterns and other URLs not supported - return [None] - - if gradient["type"] == "linear": - layer = d.create_layer("linear_gradient", url_id, - d.gradient_to_params(gradient), - guids={"gradient" : gradient["stops_guid"]} ) - - if gradient["type"] == "radial": - layer = d.create_layer("radial_gradient", url_id, - d.gradient_to_params(gradient), - guids={"gradient" : gradient["stops_guid"]} ) - - return d.op_transform([layer], simpletransform.composeTransform(mtx, gradient["mtx"])) - - -if __name__ == '__main__': - try: - e = SynfigExport() - e.affect(output=False) - except MalformedSVGError, e: - errormsg(e) - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/synfig_prepare.py b/share/extensions/synfig_prepare.py deleted file mode 100755 index ebc50fd8e..000000000 --- a/share/extensions/synfig_prepare.py +++ /dev/null @@ -1,501 +0,0 @@ -#!/usr/bin/env python -""" -synfig_prepare.py -Simplifies SVG files in preparation for sif export. - -Copyright (C) 2011 Nikita Kitaev - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import os, tempfile - -import inkex -from inkex import NSS, addNS, etree, errormsg -import simplepath, simplestyle, simpletransform - -###### Utility Classes #################################### - -class MalformedSVGError(Exception): - """Raised when the SVG document is invalid or contains unsupported features""" - def __init__(self, value): - self.value = value - def __str__(self): - return """SVG document is invalid or contains unsupported features - -Error message: %s - -The SVG to Synfig converter is designed to handle SVG files that were created using Inkscape. Unsupported features are most likely to occur in SVG files written by other programs. -""" % repr(self.value) - -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False - -class InkscapeActionGroup(object): - """A class for calling Inkscape to perform operations on a document""" - def __init__(self, svg_document=None): - self.command = "" - self.init_args = "" - self.has_selection = False - self.has_action = False - self.svg_document = svg_document - - def set_svg_document(self, svg_document): - """Set the SVG document that Inkscape will operate on""" - self.svg_document = svg_document - - def set_init_args(self, cmd): - """Set the initial arguments to Inkscape subprocess - - Can be used to pass additional arguments to Inkscape, or an initializer - command (e.g. unlock all objects before proceeding). - """ - self.init_args = cmd - - def clear(self): - """Clear all actions""" - self.command = "" - self.has_action = False - self.has_selection = False - - def verb(self, verb): - """Run an Inkscape verb - - For a list of verbs, run `inkscape --verb-list` - """ - if self.has_selection: - self.command += "--verb=%s " % (verb) - - if not self.has_action: - self.has_action = True - - def select_id(self, object_id): - """Select object with given id""" - self.command += "--select=%s " % (object_id) - if not self.has_selection: - self.has_selection = True - - def select_node(self, node): - """Select the object represented by the SVG node - - Selection will fail if node has no id attribute - """ - node_id = node.get("id", None) - if node_id is None: - raise MalformedSVGError, "Node has no id" - self.select_id(node_id) - - def select_nodes(self, nodes): - """Select objects represented by SVG nodes - - Selection will fail if any node has no id attribute - """ - for node in nodes: - self.select_node(node) - - def select_xpath(self, xpath, namespaces=NSS): - """Select objects matching a given XPath expression - - Selection will fail if any matching node has no id attribute - """ - nodes = self.svg_document.xpath(xpath, namespaces=namespaces) - - self.select_nodes(nodes) - - def deselect(self): - """Deselect all objects""" - if self.has_selection: - self.verb("EditDeselect") - self.has_selection = False - - def run_file(self, filename): - """Run the actions on a specific file""" - if not self.has_action: - return - - cmd = self.init_args + " " + self.command + "--verb=FileSave --verb=FileQuit" - if bsubprocess: - p = Popen('inkscape "%s" %s' % (filename, cmd), shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - f = p.stdout - err = p.stderr - else: - _, f, err = os.popen3( "inkscape %s %s" % ( filename, cmd ) ) - - f.close() - err.close() - - def run_document(self): - """Run the actions on the svg xml tree""" - if not self.has_action: - return self.svg_document - - # First save the document - svgfile = tempfile.mktemp(".svg") - self.svg_document.write(svgfile) - - # Run the action on the document - self.run_file(svgfile) - - # Open the resulting file - stream = open(svgfile, 'r') - new_svg_doc = etree.parse(stream) - stream.close() - - # Clean up. - try: - os.remove(svgfile) - except Exception: - pass - - # Set the current SVG document - self.svg_document = new_svg_doc - - # Return the new document - return new_svg_doc - -class SynfigExportActionGroup(InkscapeActionGroup): - """An action group with stock commands designed for Synfig exporting""" - def __init__(self, svg_document=None): - InkscapeActionGroup.__init__(self, svg_document) - self.set_init_args("--verb=UnlockAllInAllLayers") - self.objects_to_paths() - self.unlink_clones() - - def objects_to_paths(self): - """Convert unsupported objects to paths""" - # Flow roots contain rectangles inside them, so they need to be - # converted to paths separately from other shapes - self.select_xpath("//svg:flowRoot", namespaces=NSS) - self.verb("ObjectToPath") - self.deselect() - - non_paths = [ - "svg:rect", - "svg:circle", - "svg:ellipse", - "svg:line", - "svg:polyline", - "svg:polygon", - "svg:text" - ] - - # Build an xpath command to select these nodes - xpath_cmd = " | ".join(["//" + np for np in non_paths]) - - # Select all of these elements - # Note: already selected elements are not deselected - self.select_xpath(xpath_cmd, namespaces=NSS) - - # Convert them to paths - self.verb("ObjectToPath") - self.deselect() - - def unlink_clones(self): - """Unlink clones (remove <svg:use> elements)""" - self.select_xpath("//svg:use", namespaces=NSS) - self.verb("EditUnlinkClone") - self.deselect() - -###### Utility Functions ################################## - -### Path related - -def fuse_subpaths(path_node): - """Fuse subpaths of a path. Should only be used on unstroked paths""" - path_d = path_node.get("d", None) - path = simplepath.parsePath(path_d) - - if len(path) == 0: - return - - i = 0 - initial_point = [ path[i][1][-2], path[i][1][-1] ] - return_stack = [] - while i < len(path): - # Remove any terminators: they are redundant - if path[i][0] == "Z": - path.remove(["Z", []]) - continue - - # Skip all elements that do not begin a new path - if i == 0 or path[i][0] != "M": - i += 1 - continue - - # This element begins a new path - it should be a moveto - assert(path[i][0] == 'M') - - # Swap it for a lineto - path[i][0] = 'L' - - # If the old subpath has not been closed yet, close it - if path[i-1][1][-2] != initial_point[0] or path[i-1][1][-2] != initial_point[1]: - path.insert(i, ['L', initial_point]) - i += 1 - - # Set the initial point of this subpath - initial_point = [ path[i-1][1][-2], path[i-1][1][-1] ] - - # Append this point to the return stack - return_stack.append(initial_point) - #end while - - # Now pop the entire return stack - while return_stack != []: - el = ['L', return_stack.pop()] - path.insert(i, el) - i += 1 - - - path_d = simplepath.formatPath(path) - path_node.set("d", path_d) - -def split_fill_and_stroke(path_node): - """Split a path into two paths, one filled and one stroked - - Returns a the list [fill, stroke], where each is the XML element of the - fill or stroke, or None. - """ - style = simplestyle.parseStyle(path_node.get("style", "")) - - # If there is only stroke or only fill, don't split anything - if "fill" in style.keys() and style["fill"] == "none": - if "stroke" not in style.keys() or style["stroke"] == "none": - return [None, None] # Path has neither stroke nor fill - else: - return [None, path_node] - if "stroke" not in style.keys() or style["stroke"] == "none": - return [path_node, None] - - group = path_node.makeelement(addNS("g", "svg")) - fill = etree.SubElement(group, addNS("path", "svg")) - stroke = etree.SubElement(group, addNS("path", "svg")) - - attribs = path_node.attrib - - if "d" in attribs.keys(): - d = attribs["d"] - del attribs["d"] - else: - raise AssertionError, "Cannot split stroke and fill of non-path element" - - if addNS("nodetypes", "sodipodi") in attribs.keys(): - nodetypes = attribs[addNS("nodetypes", "sodipodi")] - del attribs[addNS("nodetypes", "sodipodi")] - else: - nodetypes = None - - if "id" in attribs.keys(): - path_id = attribs["id"] - del attribs["id"] - else: - path_id = str(id(path_node)) - - if "style" in attribs.keys(): - del attribs["style"] - - if "transform" in attribs.keys(): - transform = attribs["transform"] - del attribs["transform"] - else: - transform = None - - # Pass along all remaining attributes to the group - for attrib_name in attribs.keys(): - group.set(attrib_name, attribs[attrib_name]) - - group.set("id", path_id) - - # Next split apart the style attribute - style_group = {} - style_fill = {"stroke":"none", "fill":"#000000"} - style_stroke = {"fill":"none", "stroke":"none"} - - for key in style.keys(): - if key.startswith("fill"): - style_fill[key] = style[key] - elif key.startswith("stroke"): - style_stroke[key] = style[key] - elif key.startswith("marker"): - style_stroke[key] = style[key] - elif key.startswith("filter"): - style_group[key] = style[key] - else: - style_fill[key] = style[key] - style_stroke[key] = style[key] - - if len(style_group) != 0: - group.set("style", simplestyle.formatStyle(style_group)) - - fill.set("style", simplestyle.formatStyle(style_fill)) - stroke.set("style", simplestyle.formatStyle(style_stroke)) - - # Finalize the two paths - fill.set("d", d) - stroke.set("d", d) - if nodetypes is not None: - fill.set(addNS("nodetypes", "sodipodi"), nodetypes) - stroke.set(addNS("nodetypes", "sodipodi"), nodetypes) - fill.set("id", path_id+"-fill") - stroke.set("id", path_id+"-stroke") - if transform is not None: - fill.set("transform", transform) - stroke.set("transform", transform) - - - # Replace the original node with the group - path_node.getparent().replace(path_node, group) - - return [fill, stroke] - -### Object related - -def propagate_attribs(node, parent_style={}, parent_transform=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - """Propagate style and transform to remove inheritance""" - - # Don't enter non-graphical portions of the document - if (node.tag == addNS("namedview", "sodipodi") - or node.tag == addNS("defs", "svg") - or node.tag == addNS("metadata", "svg") - or node.tag == addNS("foreignObject", "svg")): - return - - - # Compose the transformations - if node.tag == addNS("svg", "svg") and node.get("viewBox"): - vx, vy, vw, vh = [get_dimension(x) for x in node.get("viewBox").split()] - dw = get_dimension(node.get("width", vw)) - dh = get_dimension(node.get("height", vh)) - t = "translate(%f, %f) scale(%f, %f)" % (-vx, -vy, dw/vw, dh/vh) - this_transform = simpletransform.parseTransform(t, parent_transform) - this_transform = simpletransform.parseTransform(node.get("transform"), this_transform) - del node.attrib["viewBox"] - else: - this_transform = simpletransform.parseTransform(node.get("transform"), parent_transform) - - # Compose the style attribs - this_style = simplestyle.parseStyle(node.get("style", "")) - remaining_style = {} # Style attributes that are not propagated - - non_propagated = ["filter"] # Filters should remain on the topmost ancestor - for key in non_propagated: - if key in this_style.keys(): - remaining_style[key] = this_style[key] - del this_style[key] - - # Create a copy of the parent style, and merge this style into it - parent_style_copy = parent_style.copy() - parent_style_copy.update(this_style) - this_style = parent_style_copy - - # Merge in any attributes outside of the style - style_attribs = ["fill", "stroke"] - for attrib in style_attribs: - if node.get(attrib): - this_style[attrib] = node.get(attrib) - del node.attrib[attrib] - - if (node.tag == addNS("svg", "svg") - or node.tag == addNS("g", "svg") - or node.tag == addNS("a", "svg") - or node.tag == addNS("switch", "svg")): - # Leave only non-propagating style attributes - if len(remaining_style) == 0: - if "style" in node.keys(): - del node.attrib["style"] - else: - node.set("style", simplestyle.formatStyle(remaining_style)) - - # Remove the transform attribute - if "transform" in node.keys(): - del node.attrib["transform"] - - # Continue propagating on subelements - for c in node.iterchildren(): - propagate_attribs(c, this_style, this_transform) - else: - # This element is not a container - - # Merge remaining_style into this_style - this_style.update(remaining_style) - - # Set the element's style and transform attribs - node.set("style", simplestyle.formatStyle(this_style)) - node.set("transform", simpletransform.formatTransform(this_transform)) - -### Style related - -def get_dimension(s="1024"): - """Convert an SVG length string from arbitrary units to pixels""" - if s == "": - return 0 - try: - last = int(s[-1]) - except: - last = None - - if type(last) == int: - return float(s) - elif s[-1] == "%": - return 1024 - elif s[-2:] == "px": - return float(s[:-2]) - elif s[-2:] == "pt": - return float(s[:-2])*1.333 - elif s[-2:] == "em": - return float(s[:-2])*16 - elif s[-2:] == "mm": - return float(s[:-2])*3.779 - elif s[-2:] == "pc": - return float(s[:-2])*16 - elif s[-2:] == "cm": - return float(s[:-2])*37.79 - elif s[-2:] == "in": - return float(s[:-2])*96 - else: - return 1024 - -###### Main Class ######################################### -class SynfigPrep(inkex.Effect): - def effect(self): - """Transform document in preparation for exporting it into the Synfig format""" - - a = SynfigExportActionGroup(self.document) - self.document = a.run_document() - - # Remove inheritance of attributes - propagate_attribs(self.document.getroot()) - - # Fuse multiple subpaths in fills - for node in self.document.xpath('//svg:path', namespaces=NSS): - if node.get("d", "").lower().count("m") > 1: - # There are multiple subpaths - fill = split_fill_and_stroke(node)[0] - if fill is not None: - fuse_subpaths(fill) - -if __name__ == '__main__': - try: - e = SynfigPrep() - e.affect() - except MalformedSVGError, e: - errormsg(e) - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/tar_layers.inx b/share/extensions/tar_layers.inx deleted file mode 100644 index d70fb3ae9..000000000 --- a/share/extensions/tar_layers.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Collection of SVG files One per root layer</_name> - <id>org.inkscape.output.LAYERS</id> - <dependency type="extension">org.inkscape.output.svg.inkscape</dependency> - <dependency type="executable" location="extensions">tar_layers.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <output> - <extension>.tar</extension> - <mimetype>application/tar</mimetype> - <_filetypename>Layers as Separate SVG (*.tar)</_filetypename> - <_filetypetooltip>Each layer split into it's own svg file and collected as a tape archive (tar file)</_filetypetooltip> - <dataloss>false</dataloss> - </output> - <script> - <command reldir="extensions" interpreter="python">tar_layers.py</command> - <helper_extension>org.inkscape.output.svg.inkscape</helper_extension> - </script> -</inkscape-extension> diff --git a/share/extensions/tar_layers.py b/share/extensions/tar_layers.py deleted file mode 100755 index 3ba5aa55e..000000000 --- a/share/extensions/tar_layers.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2014 Martin Owens, email@doctormo.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -""" -An extension to export multiple svg files from a single svg file containing layers. - -Each defs is duplicated for each svg outputed. -""" -import os -import sys -import copy -import tarfile -import StringIO -import calendar -import time - -# Inkscape Libraries -import inkex -import simplestyle - -GROUP = "{http://www.w3.org/2000/svg}g" -LABEL = "{http://www.inkscape.org/namespaces/inkscape}label" -GROUPMODE = "{http://www.inkscape.org/namespaces/inkscape}groupmode" - - -def oprint(item): - """DEBUG print an object""" - for name in dir(item): - value = getattr(item, name) - if callable(value): - yield "%s()" % name - else: - yield "%s = %s" % (name, str(value)) - -def fprint(data): - """DEBUG print something""" - if isinstance(data, basestring): - sys.stderr.write("DEBUG: %s\n" % data) - else: - return fprint("%s(%s)\n " % (str(data), type(data).__name__) \ - + "\n ".join(oprint(data))) - - -class LayersOutput(inkex.Effect): - """Entry point to our layers export""" - def __init__(self): - inkex.Effect.__init__(self) - if os.name == 'nt': - self.encoding = "cp437" - else: - self.encoding = "latin-1" - - def make_template(self): - """Returns the current document as a new empty document with the same defs""" - newdoc = copy.deepcopy(self.document) - for (name, layer) in self.layers(newdoc): - layer.getparent().remove(layer) - return newdoc - - def layers(self, document): - for node in document.getroot().iterchildren(): - if self.is_layer(node): - name = node.attrib.get(LABEL, None) - if name: - yield (name, node) - - def is_layer(self, node): - return node.tag == GROUP and node.attrib.get(GROUPMODE,'').lower() == 'layer' - - def io_document(self, name, doc): - string = StringIO.StringIO() - doc.write(string) - string.seek(0) - info = tarfile.TarInfo(name=name+'.svg') - info.mtime = calendar.timegm(time.gmtime()) - info.size = len(string.buf) - return dict(tarinfo=info, fileobj=string) - - def effect(self): - # open output tar file as a stream (to stdout) - tar = tarfile.open(fileobj=sys.stdout, mode='w|') - - # Switch stdout to binary on Windows. - if sys.platform == "win32": - import msvcrt - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - - template = self.make_template() - - previous = None - for (name, _layer) in self.layers(self.document): - layer = copy.deepcopy(_layer) - if previous != None: - template.getroot().replace(previous, layer) - else: - template.getroot().append(layer) - previous = layer - - tar.addfile(**self.io_document(name, template)) - - -if __name__ == '__main__': #pragma: no cover - e = LayersOutput() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/test/addnodes.test.py b/share/extensions/test/addnodes.test.py deleted file mode 100755 index a12f1d73c..000000000 --- a/share/extensions/test/addnodes.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../addnodes.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from addnodes import * - -class SplitItBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = SplitIt() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/chardataeffect.test.py b/share/extensions/test/chardataeffect.test.py deleted file mode 100755 index 780eef80a..000000000 --- a/share/extensions/test/chardataeffect.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../chardataeffect.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from chardataeffect import * - -class CharDataEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = CharDataEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/color_randomize.test.py b/share/extensions/test/color_randomize.test.py deleted file mode 100755 index 2887b96aa..000000000 --- a/share/extensions/test/color_randomize.test.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../color_randomize.py --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import os -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from color_randomize import * - -def extract_hsl(e,rgb): - r = int(rgb[:2], 16) - g = int(rgb[2:4], 16) - b = int(rgb[4:6], 16) - return e.rgb_to_hsl(r/255.0, g/255.0, b/255.0) - - -class ColorRandomizeBasicTest(unittest.TestCase): - def setUp(self): - self.e=C() - - def test_default_values(self): - """ The default ranges are set to 0, and thus the color and opacity should not change. """ - args = ['svg/empty-SVG.svg'] - self.e.affect(args, False) - col = self.e.colmod(128, 128, 255) - self.assertEqual("8080ff", col) - opac = self.e.opacmod(5) - self.assertEqual(5, opac) - - -class ColorRandomizeColorModificationTest(unittest.TestCase): - def setUp(self): - self.e=C() - - def test_no_change(self): - """ The user selected 0% values, and thus the color should not change. """ - args = ['-y 0', '-t 0', '-m 0', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - col = self.e.colmod(128, 128, 255) - self.assertEqual("8080ff", col) - - def test_random_hue(self): - """ Random hue only. Saturation and lightness not changed. """ - args = ['-y 50','-t 0','-m 0','svg/empty-SVG.svg'] - self.e.affect(args, False) - hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200)) - self.assertEqual([0.47, 0.59], [round(hsl[1], 2), round(hsl[2], 2)]) - - @unittest.skip("Inaccurate conversion") - def test_random_lightness(self): - """ Random lightness only. Hue and saturation not changed. """ - args = ['-y 0', '-t 0', '-m 50', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200)) - # Lightness change also affects hue and saturation... - #self.assertEqual(0.75, round(hsl[0], 2)) - #self.assertEqual(0.48, round(hsl[1], 2)) - - def test_random_saturation(self): - """ Random saturation only. Hue and lightness not changed. """ - args = ['-y 0', '-t 50', '-m 0', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200)) - self.assertEqual([0.75, 0.59], [round(hsl[0], 2), round(hsl[2], 2)]) - - def test_range_limits(self): - """ The maximum hsl values should be between 0 and 100% of their maximum """ - args = ['-y 100', '-t 100', '-m 100', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - hsl = extract_hsl(self.e, self.e.colmod(156, 156, 156)) - self.assertLessEqual([hsl[0], hsl[1], hsl[2]], [1, 1, 1]) - self.assertGreaterEqual([hsl[0], hsl[1], hsl[2]], [0, 0, 0]) - - -class ColorRandomizeOpacityModificationTest(unittest.TestCase): - def setUp(self): - self.e=C() - - def test_no_change(self): - """ The user selected 0% opacity range, and thus the opacity should not change. """ - args = ['-o 0', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - opac = self.e.opacmod(0.15) - self.assertEqual(0.15, opac) - - def test_range_min_limit(self): - """ The opacity value should be greater than 0 """ - args = ['-o 100', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - opac = self.e.opacmod(0) - self.assertGreaterEqual(opac, "0") - - def test_range_max_limit(self): - """ The opacity value should be lesser than 1 """ - args = ['-o 100', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - opac = self.e.opacmod(1) - self.assertLessEqual(opac, "1") - - def test_non_float_opacity(self): - """ Non-float opacity value not changed """ - args = ['-o 100', 'svg/empty-SVG.svg'] - self.e.affect(args, False) - opac = self.e.opacmod("toto") - self.assertLessEqual(opac, "toto") - -if __name__ == '__main__': - #unittest.main() - suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeBasicTest) - unittest.TextTestRunner(verbosity=2).run(suite) - suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeColorModificationTest) - unittest.TextTestRunner(verbosity=2).run(suite) - suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeOpacityModificationTest) - unittest.TextTestRunner(verbosity=2).run(suite) - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/test/coloreffect.test.py b/share/extensions/test/coloreffect.test.py deleted file mode 100755 index 61a83713a..000000000 --- a/share/extensions/test/coloreffect.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../coloreffect.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from coloreffect import * - -class ColorEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = ColorEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/create_test_from_template.sh b/share/extensions/test/create_test_from_template.sh deleted file mode 100755 index d424f4b72..000000000 --- a/share/extensions/test/create_test_from_template.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -exFile="$1" - -if test -z "$exFile" -o \! -f "$exFile"; then - echo " - This script is a dummy help for the creation of a - extension unity test file. - - Usage: - $( basename "$0" ) ../extenion.py - " - exit 0 -fi - -module=$( echo "$exFile" | sed -r 's/^.*\/([^\/.]+)..*$/\1/' ) - -num=0 -testFile="$module.test.py" -while test -e "$testFile"; do - let num++ - testFile="$module.test$num.py" -done - -if grep -q '^\s*class .*[( ]inkex.Effect[ )]' $exFile; then - pyClass=$( grep '^\s*class .*[( ]inkex.Effect[ )]' $exFile | sed -r 's/^\s*class\s+([^ ]+)\s*\(.*$/\1/' ) -else - echo " - ERROR: Incompatible Format or Inheritance. - At this time this script only knows how to make unit tests - for Python effects based on inkex.Effect. - The $testFile will not be created. - " - exit 1 -fi - -echo ">> Creating $testFile" - -exFileRE="$( echo "$exFile" | sed -r 's/\./\\./g; s/\//\\\//g' )" - -sed -r "s/%MODULE%/$module/g; s/%CLASS%/$pyClass/g; s/%FILE%/$exFileRE/g" \ - test_template.py.txt > "$testFile" - -chmod +x "$testFile"
\ No newline at end of file diff --git a/share/extensions/test/dots.test.py b/share/extensions/test/dots.test.py deleted file mode 100755 index 4f4c3074d..000000000 --- a/share/extensions/test/dots.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../dots.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from dots import * - -class DotsBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Dots() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/draw_from_triangle.test.py b/share/extensions/test/draw_from_triangle.test.py deleted file mode 100755 index c5da0c2a4..000000000 --- a/share/extensions/test/draw_from_triangle.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../draw_from_triangle.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from draw_from_triangle import * - -class Draw_From_TriangleBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Draw_From_Triangle() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/dxf_outlines.test.py b/share/extensions/test/dxf_outlines.test.py deleted file mode 100755 index e3b64e1cd..000000000 --- a/share/extensions/test/dxf_outlines.test.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../dxf_outlines.py -Revision history: - * 2012-01-25 (jazzynico): first working version (only checks the extension - with the default parameters). - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from dxf_outlines import * - -class DFXOutlineBasicTest(unittest.TestCase): - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = MyEffect() - e.affect(args, False) - - -if __name__ == '__main__': - unittest.main() - #suite = unittest.TestLoader().loadTestsFromTestCase(DFXOutlineBasicTest) - #unittest.TextTestRunner(verbosity=2).run(suite) - diff --git a/share/extensions/test/edge3d.test.py b/share/extensions/test/edge3d.test.py deleted file mode 100755 index 93871a4ad..000000000 --- a/share/extensions/test/edge3d.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../edge3d.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from edge3d import * - -class Edge3dBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Edge3d() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/embedimage.test.py b/share/extensions/test/embedimage.test.py deleted file mode 100755 index 378c3f045..000000000 --- a/share/extensions/test/embedimage.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../embedimage.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from embedimage import * - -class EmbedderBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Embedder() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/eqtexsvg.test.py b/share/extensions/test/eqtexsvg.test.py deleted file mode 100755 index 2c16cc05c..000000000 --- a/share/extensions/test/eqtexsvg.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../eqtexsvg.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from eqtexsvg import * - -class EQTEXSVGBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = EQTEXSVG() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/extractimage.test.py b/share/extensions/test/extractimage.test.py deleted file mode 100755 index 4f00f2075..000000000 --- a/share/extensions/test/extractimage.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../extractimage.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from extractimage import * - -class MyEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = MyEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/extrude.test.py b/share/extensions/test/extrude.test.py deleted file mode 100755 index 21c350e93..000000000 --- a/share/extensions/test/extrude.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../extrude.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from extrude import * - -class ExtrudeBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Extrude() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/flatten.test.py b/share/extensions/test/flatten.test.py deleted file mode 100755 index fc4459668..000000000 --- a/share/extensions/test/flatten.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../flatten.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from flatten import * - -class MyEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = MyEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/foldablebox.test.py b/share/extensions/test/foldablebox.test.py deleted file mode 100755 index 63906c6a5..000000000 --- a/share/extensions/test/foldablebox.test.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from foldablebox import * - -class FoldableBoxArguments(unittest.TestCase): - - #def setUp(self): - - def test_basic_box_elements(self): - args = [ 'minimal-blank.svg' ] - e = FoldableBox() - e.affect( args, False ) - self.assertEqual( e.box.tag, 'g', 'The box group must be created.' ) - self.assertEqual( len( e.box.getchildren() ), 13, 'The box group must have 13 childs.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/fractalize.test.py b/share/extensions/test/fractalize.test.py deleted file mode 100755 index c2a99969f..000000000 --- a/share/extensions/test/fractalize.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../fractalize.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from fractalize import * - -class PathFractalizeBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = PathFractalize() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/frame_test.py b/share/extensions/test/frame_test.py deleted file mode 100755 index 3d686ab25..000000000 --- a/share/extensions/test/frame_test.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python - -""" -An Inkscape frame extension test class. - -Copyright (C) 2016 Richard White, rwhite8282@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 -""" - -import sys -sys.path.append('/usr/share/inkscape/extensions') -sys.path.append('..') # this line allows to import the extension code - -import unittest -import inkex -from frame import * - - -class Frame_Test(unittest.TestCase): - - - def get_frame(self, document): - return document.xpath('//svg:g[@id="layer1"]//svg:path[@inkscape:label="Frame"]' - , namespaces=inkex.NSS)[0] - - - def test_empty_no_parameters(self): - args = [ 'svg/empty-SVG.svg' ] - uut = Frame() - uut.affect( args, False ) - - - def test_single_frame(self): - args = [ - '--corner_radius=20' - , '--fill_color=-16777124' - , '--id=rect3006' - , '--position=inside' - , '--stroke_color=255' - , '--tab="stroke"' - , '--width=10' - , 'svg/single_box.svg'] - uut = Frame() - uut.affect( args, False ) - new_frame = self.get_frame(uut.document) - self.assertIsNotNone(new_frame) - self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) - new_frame_style = new_frame.attrib['style'].lower() - self.assertTrue('fill-opacity:0.36' in new_frame_style - , 'Invalid fill-opacity in "' + new_frame_style + '".') - self.assertTrue('stroke:#000000' in new_frame_style - , 'Invalid stroke in "' + new_frame_style + '".') - self.assertTrue('stroke-width:10.0' in new_frame_style - , 'Invalid stroke-width in "' + new_frame_style + '".') - self.assertTrue('stroke-opacity:1.00' in new_frame_style - , 'Invalid stroke-opacity in "' + new_frame_style + '".') - self.assertTrue('fill:#ff0000' in new_frame_style - , 'Invalid fill in "' + new_frame_style + '".') - - - def test_single_frame_grouped(self): - args = [ - '--corner_radius=20' - , '--fill_color=-16777124' - , '--group=True' - , '--id=rect3006' - , '--position=inside' - , '--stroke_color=255' - , '--tab="stroke"' - , '--width=10' - , 'svg/single_box.svg'] - uut = Frame() - uut.affect( args, False ) - new_frame = self.get_frame(uut.document) - self.assertIsNotNone(new_frame) - self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) - group = new_frame.getparent() - self.assertEqual('{http://www.w3.org/2000/svg}g', group.tag) - self.assertEqual('{http://www.w3.org/2000/svg}rect', group[0].tag) - self.assertEqual('{http://www.w3.org/2000/svg}path', group[1].tag) - self.assertEqual("Frame", group[1].xpath('@inkscape:label', namespaces=inkex.NSS)[0]) - - - def test_single_frame_clipped(self): - args = [ - '--clip=True' - , '--corner_radius=20' - , '--fill_color=-16777124' - , '--id=rect3006' - , '--position=inside' - , '--stroke_color=255' - , '--tab="stroke"' - , '--width=10' - , 'svg/single_box.svg'] - uut = Frame() - uut.affect( args, False ) - new_frame = self.get_frame(uut.document) - self.assertIsNotNone(new_frame) - self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) - group = new_frame.getparent() - self.assertEqual('url(#clipPath)', group[0].get('clip-path')) - clip_path = uut.document.xpath('//svg:defs/svg:clipPath', namespaces=inkex.NSS)[0] - self.assertEqual('{http://www.w3.org/2000/svg}clipPath', clip_path.tag) - - -if __name__ == '__main__': - unittest.main()
\ No newline at end of file diff --git a/share/extensions/test/funcplot.test.py b/share/extensions/test/funcplot.test.py deleted file mode 100755 index daa49a4c8..000000000 --- a/share/extensions/test/funcplot.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../funcplot.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from funcplot import * - -class FuncPlotBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = FuncPlot() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/gimp_xcf.test.py b/share/extensions/test/gimp_xcf.test.py deleted file mode 100755 index de2498ec8..000000000 --- a/share/extensions/test/gimp_xcf.test.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../gimp_xcf.py -Revision history: - * 2012-01-26 (jazzynico): checks defaulf parameters and file handling. - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import os -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from gimp_xcf import * - -class GimpXCFBasicTest(unittest.TestCase): - def setUp(self): - sys.stdout = open(os.devnull, 'w') - - def test_expected_file(self): - # multilayered-test.svg provides 3 layers and a sublayer - # (all non empty). - args = [ 'svg/multilayered-test.svg' ] - e = MyEffect() - e.affect(args, False) - #self.assertRaises(GimpXCFExpectedIOError, e.affect, args, False) - - def test_empty_file(self): - # empty-SVG.svg contains an emply svg element (no layer, no object). - # The file must have at least one non empty layer and thus the - # extension rejects it and send an error message. - args = [ 'svg/empty-SVG.svg' ] - e = MyEffect() - e.affect(args, False) - self.assertEqual(e.valid, 0) - - def test_empty_layer_file(self): - # default-inkscape-SVG.svg is a copy of the default Inkscape - # template, with one empty layer. - # The file must have at least one non empty layer and thus the - # extension rejects it and send an error message. - args = [ 'svg/default-inkscape-SVG.svg' ] - e = MyEffect() - e.affect(args, False) - self.assertEqual(e.valid, 0) - - -if __name__ == '__main__': - #unittest.main() - suite = unittest.TestLoader().loadTestsFromTestCase(GimpXCFBasicTest) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/grid_cartesian.test.py b/share/extensions/test/grid_cartesian.test.py deleted file mode 100755 index 6f5881d4d..000000000 --- a/share/extensions/test/grid_cartesian.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../grid_cartesian.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from grid_cartesian import * - -class Grid_PolarBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Grid_Polar() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/grid_polar.test.py b/share/extensions/test/grid_polar.test.py deleted file mode 100755 index b871e6077..000000000 --- a/share/extensions/test/grid_polar.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../grid_polar.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from grid_polar import * - -class Grid_PolarBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Grid_Polar() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/guides_creator.test.py b/share/extensions/test/guides_creator.test.py deleted file mode 100755 index d6f97c6c8..000000000 --- a/share/extensions/test/guides_creator.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../guides_creator.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from guides_creator import * - -class Guides_CreatorBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Guides_Creator() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/handles.test.py b/share/extensions/test/handles.test.py deleted file mode 100755 index 69153a403..000000000 --- a/share/extensions/test/handles.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../handles.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from handles import * - -class HandlesBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Handles() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/hpgl_output.test.py b/share/extensions/test/hpgl_output.test.py deleted file mode 100755 index 19fdeb661..000000000 --- a/share/extensions/test/hpgl_output.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../hpgl_output.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from hpgl_output import * - -class HPGLOuputBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = HpglOutput() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/inkex.test.py b/share/extensions/test/inkex.test.py deleted file mode 100755 index ed2256ae7..000000000 --- a/share/extensions/test/inkex.test.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -Unit test file for ../inkex.py -Revision history: - * 2012-01-27 (jazzynico): check errormsg function. - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from inkex import errormsg - -class InkexBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_ascii(self): - #Parse ABCabc - errormsg('ABCabc') - - def test_nonunicode_latin1(self): - #Parse Àûïàèé - errormsg('Àûïàèé') - - def test_unicode_latin1(self): - #Parse Àûïàèé (unicode) - errormsg(u'Àûïàèé') - -if __name__ == '__main__': - #unittest.main() - suite = unittest.TestLoader().loadTestsFromTestCase(InkexBasicTest) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/inkweb-debug.js b/share/extensions/test/inkweb-debug.js deleted file mode 100644 index 3fd24e3c2..000000000 --- a/share/extensions/test/inkweb-debug.js +++ /dev/null @@ -1,368 +0,0 @@ -/* -** InkWeb Debuger - help the development with InkWeb. -** -** Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot com -** -** ********* Bugs and New Fetures ************************************* -** If you found any bug on this script or if you want to propose a -** new feature, please report it in the inkscape bug traker -** https://bugs.launchpad.net/inkscape/+filebug -** and assign that to Aurium. -** ******************************************************************** -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU Lesser General Public License as published -** by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. -** -** You should have received a copy of the GNU Lesser General Public License -** along with this program. If not, see <http://www.gnu.org/licenses/>. -** -** ******************************************************************** -** -** This script extends InkWeb with methods like log() and viewProperties(). -** So, you must to call this script after the inkweb.js load. -*/ - -InkWeb.debugVersion = 0.1; - -// Prepare InkWeb Debug: -(function (bli, xyz) { - // Add logging calls to all InkWeb methods: - for ( var att in InkWeb ) { - if ( typeof(InkWeb[att]) == "function" ) { - var code = InkWeb[att].toString() - beforeCode = 'this.log(this.__callMethodInfo("'+att+'", arguments));\ntry {'; - afterCode = '} catch(e) { this.log( e, "Ups... There is a problem in InkWeb.'+att+'()" ) }'; - code = code - .replace( /^(function [^{]+[{])/, "$1\n"+ beforeCode +"\n" ) - .replace( /[}]$/, ";\n"+ afterCode +"\n}" ); - eval( "InkWeb."+att+" = "+ code ); - //alert( InkWeb[att] ) - } - } -})(123,456); - -InkWeb.__callMethodInfo = function (funcName, arg) { - var func = arg.callee; - var str = 'Called InkWeb.'+funcName+'() with:' - if ( ! func.argList ) { - func.argList = func.toString() - .replace( /^function [^(]*\(([^)]*)\)(.|\s)*$/, "$1" ) - .split( /,\s*/ ); - } - for ( var a,i=0; a=func.argList[i]; i++ ) { - str += "\n"+ a +" = "+ this.serialize( arg[i], {recursionLimit:2} ); - } - return str; -} - - -InkWeb.copySerializeConf = function (conf) { - return { - recursionStep: conf.recursionStep, - recursionLimit: conf.recursionLimit, - showTagElements: conf.showTagElements - } -} - -InkWeb.serialize = function (v, conf) { - try { - if ( ! conf ) { conf = {} } - if ( ! conf.showTagElements ) { conf.showTagElements = false } - if ( ! conf.recursionLimit ) { conf.recursionLimit = 10 } - if ( ! conf.recursionStep ) { conf.recursionStep = 0 } - if ( conf.recursionLimit == 0 ) { - return '"<<recursion limit>>"'; - } - conf.recursionLimit--; - conf.recursionStep++; - switch ( typeof(v) ) { - case "undefined": - v = "undefined"; - break; - case "string": - v = '"'+ v - .replace( /\n/g, "\\n" ) - .replace( /\r/g, "\\r" ) - .replace( /\t/g, "\\t" ) - .replace( /"/g, '"' ) + - '"'; - break; - case "boolean": - case "number": - case "function": - v = v.toString(); - break; - case "object": - if ( v == null ) { - v = "null"; - } else { - if ( v.constructor == Array ) { - try { - v = this.__serializeArray(v, conf); - } catch(e) { - this.log( e, "InkWeb.serialize(): Forced recursion limit in" + - " recursionLimit="+ conf.recursionLimit + - " and recursionStep="+ conf.recursionStep - ); - v += '"<<forced recursion limit>>"' - } - } else { - // A Hash Object - if ( v.tagName && ! conf.showTagElements ) { - // Tags are not allowed. - v = '"<'+ v.tagName +' id=\\"'+ v.id +'\\">"'; - } else { - // Ok, serialize this object: - try { - v = this.__serializeObject(v, conf); - } catch(e) { - this.log( e, "InkWeb.serialize(): Forced recursion limit in" + - " recursionLimit="+ conf.recursionLimit + - " and recursionStep="+ conf.recursionStep - ); - v += '"<<forced recursion limit>>"' - } - } - } - } - break; - default: - v = '"<<unknown type '+typeof(v)+' : '+v+'>>"'; - } - return v; - } catch(e) { - this.log( e, "Ups... There is a problem in InkWeb.serialize()." ); - } -} - -InkWeb.__serializeArray = function (v, conf) { - try { - var vStr = "[ "; - var size = v.length; - for ( var i=0; i<size; i++ ) { - if ( i>0 ) { vStr += ", " } - vStr += this.serialize(v[i], this.copySerializeConf(conf)); - } - return vStr +" ]"; - } catch(e) { - this.log( e, "Ups... There is a problem in InkWeb.__serializeArray()." ); - } -} - -InkWeb.__serializeObject = function (obj, conf) { - try { - var vStr = "{ "; - var first = true; - for ( var att in obj ) { - if ( !first ) { vStr += ", " } - vStr += this.serialize(att) +':'+ - this.serialize( obj[att], this.copySerializeConf(conf) ); - first = false; - } - return vStr +" }"; - } catch(e) { - this.log( e, "Ups... There is a problem in InkWeb.__serializeObject()." ); - } -} - -// Allow log configuration: -InkWeb.mustLog = { - error: true, - warning: true, - sequence: true - }; - -// This will keep the log information: -InkWeb.__log__ = []; - -InkWeb.log = function (type, msg) { - /* This method register what was happen with InkWeb - ** ( if mustLog allows that ) - ** - ** --- Usage --- - ** this.log( <"sequence"|"warning"|"warn"|errorObject>, <"logMessage"> ); - ** this.log( <"logMessage"> ); // only for sequences - ** - ** --- Examples --- - ** Sequence log: - ** function foo (bar) { - ** InkWeb.log( 'Call function foo with argument bar="'+bar+'"' ); - ** - ** Warning log: - ** if ( foo == bar ) { - ** foo = other; - ** InkWeb.log( "warn", "foo must not be bar." ); - ** - ** Error log: - ** try { ... some hard thing ... } - ** catch (e) { InkWeb.log( e, "Trying to do some hard thing." ) } - */ - if ( this.mustLog ) { - if( type.constructor == ReferenceError ) { - // in a error loging the type argument is the error object. - var error = type; - type = "error"; - this.addViewLogBt(); - } - if( type == "warn" ) { - // that allows a little simplify in the log call. - type = "warning"; - } - if( msg == undefined ) { - // that allows to log a sequence without tos say the type. - msg = type; - type = "sequence"; - } - var logSize = this.__log__.length - if ( logSize > 0 && - this.__log__[logSize-1].type == type && - this.__log__[logSize-1].msg == msg ) { - this.__log__[logSize-1].happens++ - } else { - if ( type == "error" && this.mustLog.error ) { - this.__log__[logSize] = this.__logError( error, msg ) - } - if ( type == "warning" && this.mustLog.warning ) { - this.__log__[logSize] = this.__logWarning( msg ) - } - if ( type == "sequence" && this.mustLog.sequence ) { - this.__log__[logSize] = this.__logSequence( msg ) - } - } - } -} - -InkWeb.__logError = function ( error, msg ) { - return { type:"error", date:new Date(), msg:msg, error:error, happens:1 }; -} - -InkWeb.__logWarning = function ( msg ) { - return { type:"warning", date:new Date(), msg:msg, happens:1 }; -} - -InkWeb.__logSequence = function ( msg ) { - return { type:"sequence", date:new Date(), msg:msg, happens:1 }; -} - -InkWeb.logToString = function (conf) { - /* Show the log in a formatted string. - ** conf attributes: - ** format: a string to format the log itens. - ** formatError: to format the error log itens. - ** sep: the log itens separator string. - ** format variables: - ** $F: the item date in the format YYYY-MM-DD - ** $T: the item time in the format HH:MM:SS - ** $type: the log type - ** $logmsg: the text argument in the log call - ** $times: how much times this item happens in sequence - ** $error: the error text (if this is a error item) - ** $index: the position of the item in the log list - ** $oddeven: return odd or even based in the index. - */ - if (!conf) { conf = {} } - if (!conf.sep) { conf.sep = "\n\n" } - if (!conf.format) { conf.format = "$F $T - $type - $logmsg - Happens $times." } - if (!conf.formatError) { conf.formatError = "$F $T - ERROR - $logmsg - Happens $times.\n$error" } - /* * * Helper * * */ - function _2d(num) { - return ( ( num < 10 )? "0"+num : ""+num ) - } - function _2dMonth(date) { - var m = date.getMonth() + 1; - return _2d( m ) - } - var str = ""; - var logSize = this.__log__.length; - if ( logSize == 0 ) { - str = "There are no errors."; - } - // View all itens to mount the log string: - for ( var item,pos=0; item=this.__log__[pos]; pos++ ) { - var d = item.date; - // Add log line, converting variables: - var line = ( (item.type=="error")? conf.formatError : conf.format ); - str += line - .replace( /\$index/g, pos ) - .replace( /\$oddeven/g, (pos%2 == 1)? "odd" : "even" ) - .replace( /\$type/g, item.type ) - .replace( /\$logmsg/g, item.msg ) - .replace( /\$error/g, (item.error)? item.error.message : "" ) - .replace( /\$times/g, (item.happens>1)? item.happens+" times" : "one time" ) - .replace( /\$F/g, d.getFullYear() +"-"+ _2dMonth(d) +"-"+ _2d(d.getDate()) ) - .replace( /\$T/g, _2d(d.getHours()) +":"+ _2d(d.getMinutes()) +":"+ _2d(d.getSeconds()) ) - // Add separator: - if ( pos < (logSize-1) ) { str += conf.sep } - } - return str; -} - -InkWeb.addViewLogBt = function () { - var svg = document.getElementsByTagName("svg")[0]; - if ( this.__viewLogBt ) { - svg.appendChild( this.__viewLogBt ); - } else { - var g = this.el( "g", { onclick: "InkWeb.openLogWindow()", parent: svg } ); - var rect = this.el( "rect", { x: 10, y: 10, width: 60, height: 17, ry: 5, - style: "fill:#C00; stroke:#800; stroke-width:2", - parent: g } ); - var text = this.el( "text", { x: 40, y: 22, text: "View Log", - style: "fill:#FFF; font-size:10px;" + - "font-family:sans-serif;" + - "text-anchor:middle; text-align:center", - parent: g } ); - this.__viewLogBt = g; - } -} - -InkWeb.__openFormatedWindow = function (bodyHTML) { - var win = window.open("","_blank","width=500,height=500,scrollbars=yes"); - var html = - '<html><head><title>InkWeb</title>' + - '<style type="text/css">' + - 'body { font-family:sans-serif; font-size:12px; padding:5px; margin:0px; }' + - 'h1 { font-size:13px; text-align:center; }' + - '.error { color: #C00 }' + - '.warning { color: #B90 }' + - '.sequence { color: #06A }' + - 'table { border: 2px solid #ABC }' + - 'th, td { padding:1px 2px; font-size:12px }' + - 'th { text-align:center; background:#CCC; color:#FFF }' + - '.odd { background: #F0F0F0 }' + - '.even { background: #F8F8F8 }' + - '</style><body>'+ bodyHTML +'</body></html>'; - win.document.write(html); - win.document.close(); - return win; -} - -InkWeb.openLogWindow = function () { - var html = '<h1>InkWeb Log</h1>\n' + - '<table border="0" width="100%" cellpadding="2" cellspacing="0"><tr>\n' + - '<tr><th>Time</th><th>Message</th><th><small>Happens</small></th><tr>\n' + - this.logToString({ - format: '<tr class="$type $oddeven" title="$type">' + - '<td>$T</td><td>$logmsg</td><td align="right">$times</td></tr>', - formatError: '<tr class="error $oddeven" title="ERROR">' + - '<td>$T</td><td>$logmsg</td><td align="right">$times</td></tr>\n'+ - '<tr class="error $oddeven"><td colspan="3"><code>$error</code></td></tr>', - sep: '\n</tr><tr>\n' - }) + - '\n</tr></table>' - var win = this.__openFormatedWindow( html ); - win.document.title = "InkWeb Log" -} - - -InkWeb.viewProperties = function () { - // Display object properties. - this.__openFormatedWindow( "coming soon..." ); -} - diff --git a/share/extensions/test/inkwebeffect.test.py b/share/extensions/test/inkwebeffect.test.py deleted file mode 100755 index 6fd59a008..000000000 --- a/share/extensions/test/inkwebeffect.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../inkwebeffect.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from inkwebeffect import * - -class InkWebEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = InkWebEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/inkwebjs-move.test.svg b/share/extensions/test/inkwebjs-move.test.svg deleted file mode 100644 index b4aa50fc9..000000000 --- a/share/extensions/test/inkwebjs-move.test.svg +++ /dev/null @@ -1,128 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="800" height="450"> - <style type="text/css"> - text { font-family:sans-serif; font-size:11px; text-anchor:middle; text-align:center } - .title tspan { font-weight: bold } - .pos { opacity: 0.3 } - .started { fill:#C80 } - </style> - <script type="text/javascript" xlink:href="../inkweb.js" /> - <script type="text/javascript" xlink:href="inkweb-debug.js" /> - <rect x="0%" y="0%" width="100%" height="100%" style="fill:#EEE; stroke:#999; stroke-width:4px" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-1" x="125" y="26" class="title"> - <tspan>Test 1</tspan> - from left to right </text> - <text class="pos" x="80" y="80"> Start </text> - <circle id="t1-start" cx="80" cy="50" r="20" fill="#C00" opacity="0.2" /> - <text class="pos" x="170" y="80"> End </text> - <circle id="t1-end" cx="170" cy="50" r="20" fill="#C00" opacity="0.2" /> - <!-- The element to move --> - <circle id="t1-elem" cx="80" cy="50" r="20" fill="#C00" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-2" x="325" y="26" class="title"> - <tspan>Test 2</tspan> - from right to left</text> - <text class="pos" x="370" y="80"> Start </text> - <circle id="t2-start" cx="370" cy="50" r="20" fill="#0A0" opacity="0.2" /> - <text class="pos" x="280" y="80"> End </text> - <circle id="t2-end" cx="280" cy="50" r="20" fill="#0A0" opacity="0.2" /> - <!-- The element to move --> - <circle id="t2-elem" cx="370" cy="50" r="20" fill="#0A0" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-3" x="125" y="120" class="title"> - <tspan>Test 3</tspan> - pre-translated </text> - <text class="pos" x="80" y="190"> Start </text> - <path id="t3-start" fill="#C00" opacity="0.2" transform="translate(30,10)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <text class="pos" x="170" y="190"> End </text> - <path id="t3-end" fill="#C00" opacity="0.2" transform="translate(120,10)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <!-- The element to move --> - <path id="t3-elem" fill="#C00" transform="translate(30,10)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-4" x="350" y="120" class="title"> - <tspan>Test 4</tspan> - pre-translated and scaled </text> - <text class="pos" x="300" y="190"> Start </text> - <path id="t4-start" fill="#C00" opacity="0.2" - transform="translate(235,-45) scale(1.4)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <text class="pos" x="400" y="190"> End </text> - <path id="t4-end" fill="#C00" opacity="0.2" - transform="translate(335,-45) scale(1.4)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <!-- The element to move --> - <path id="t4-elem" fill="#C00" - transform="translate(235,-45) scale(1.4)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-5" x="600" y="120" class="title"> - <tspan>Test 5</tspan> - pre-translated and rotated </text> - <text class="pos" x="550" y="190"> Start </text> - <path id="t5-start" fill="#C00" opacity="0.2" - transform="translate(500,0) rotate(-15 90 140)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <text class="pos" x="650" y="190"> End </text> - <path id="t5-end" fill="#C00" opacity="0.2" - transform="translate(600,0) rotate(-15 90 140)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <!-- The element to move --> - <path id="t5-elem" fill="#C00" - transform="translate(500,0) rotate(-15 90 140)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <text id="test-6" x="125" y="220" class="title"> - <tspan>Test 6</tspan> - with a transformation matrix </text> - <text class="pos" x="80" y="290"> Start </text> - <path id="t6-start" fill="#C00" opacity="0.2" - transform="matrix(1.2 0 -0.5 1.2 95 80)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <text class="pos" x="170" y="290"> End </text> - <path id="t6-end" fill="#C00" opacity="0.2" - transform="matrix(1.2 0 -0.5 1.2 185 80)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - <!-- The element to move --> - <path id="t6-elem" fill="#C00" - transform="matrix(1.2 0 -0.5 1.2 95 80)" - d="M30,130 L60,130 L60,120 L70,140 L60,160 L60,150 L30,150" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <script type="text/javascript"> - - var titles = document.getElementsByClassName("title") - for ( var title,i=0; title=titles[i]; i++ ) { - title.className.baseVal += " started"; - testeNum = title.id.replace( /^.*-/, "" ); - var el = document.getElementById( "t"+testeNum+"-elem" ); - var start = document.getElementById( "t"+testeNum+"-start" ).getBBox(); - var end = document.getElementById( "t"+testeNum+"-end" ).getBBox(); - InkWeb.moveElTo( { el:el, x:end.x, y:end.y } ); - } - - function testLog() { - try{ foo.lalala() } - catch(e){ InkWeb.log(e, "foo.lalala() is wrong?") } - - InkWeb.log("This is a sequence log."); - - InkWeb.log("warn", "Warning! Warning!!!"); - } - setTimeout("testLog()", 2000); - - </script> - -</svg> diff --git a/share/extensions/test/interp.test.py b/share/extensions/test/interp.test.py deleted file mode 100755 index 85849fe69..000000000 --- a/share/extensions/test/interp.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../interp.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from interp import * - -class InterpBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Interp() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/interp_att_g.test.py b/share/extensions/test/interp_att_g.test.py deleted file mode 100755 index d7cec126c..000000000 --- a/share/extensions/test/interp_att_g.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../interp-att-g.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from interp_att_g import * - -class InterpAttGBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = InterpAttG() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/jitternodes.test.py b/share/extensions/test/jitternodes.test.py deleted file mode 100755 index 699752af2..000000000 --- a/share/extensions/test/jitternodes.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../jitternodes.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from jitternodes import * - -class JitterNodesBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = JitterNodes() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/lindenmayer.test.py b/share/extensions/test/lindenmayer.test.py deleted file mode 100755 index 21f42b4b7..000000000 --- a/share/extensions/test/lindenmayer.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../lindenmayer.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from lindenmayer import * - -class LSystemBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = LSystem() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/lorem_ipsum.test.py b/share/extensions/test/lorem_ipsum.test.py deleted file mode 100755 index 19e3c7b47..000000000 --- a/share/extensions/test/lorem_ipsum.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../lorem_ipsum.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from lorem_ipsum import * - -class MyEffectBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = MyEffect() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/markers_strokepaint.test.py b/share/extensions/test/markers_strokepaint.test.py deleted file mode 100755 index 386166bce..000000000 --- a/share/extensions/test/markers_strokepaint.test.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../markers_strokepaint.py -Revision history: - * 2012-01-27 (jazzynico): checks defaulf parameters and file handling. - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from markers_strokepaint import * - -class StrokeColorBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_no_defs(self): - args = ['svg/empty-SVG.svg'] - e = MyEffect() - e.affect(args, False) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - - def test_empty_defs(self): - args = ['svg/default-plain-SVG.svg'] - e = MyEffect() - e.affect(args, False) -''' - def test_markers(self): - args = ['svg/markers.svg'] -''' - -if __name__ == '__main__': - #unittest.main() - suite = unittest.TestLoader().loadTestsFromTestCase(StrokeColorBasicTest) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/measure.test.py b/share/extensions/test/measure.test.py deleted file mode 100755 index f92b625ae..000000000 --- a/share/extensions/test/measure.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../measure.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from measure import * - -class LengthBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Length() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/minimal-blank.svg b/share/extensions/test/minimal-blank.svg deleted file mode 100644 index 1fc27fb32..000000000 --- a/share/extensions/test/minimal-blank.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="100" height="100"></svg> diff --git a/share/extensions/test/motion.test.py b/share/extensions/test/motion.test.py deleted file mode 100755 index dda474804..000000000 --- a/share/extensions/test/motion.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../motion.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from motion import * - -class MotionBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Motion() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/pathmodifier.test.py b/share/extensions/test/pathmodifier.test.py deleted file mode 100755 index 2a3ba2f66..000000000 --- a/share/extensions/test/pathmodifier.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../pathmodifier.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from pathmodifier import * - -class PathModifierBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = PathModifier() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/perfectboundcover.test.py b/share/extensions/test/perfectboundcover.test.py deleted file mode 100755 index 26ca0ad00..000000000 --- a/share/extensions/test/perfectboundcover.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../perfectboundcover.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from perfectboundcover import * - -class PerfectBoundCoverBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = PerfectBoundCover() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/perspective.test.py b/share/extensions/test/perspective.test.py deleted file mode 100755 index a10297507..000000000 --- a/share/extensions/test/perspective.test.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../perspective.py -Revision history: - * 2012-01-28 (jazzynico): first working version (only checks the extension - with the default parameters). - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from perspective import * - -class PerspectiveBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = ['minimal-blank.svg'] - e = Project() - self.assertRaises(SystemExit, e.affect, args) - -if __name__ == '__main__': - unittest.main() - #suite = unittest.TestLoader().loadTestsFromTestCase(PerspectiveBasicTest) - #unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/polyhedron_3d.test.py b/share/extensions/test/polyhedron_3d.test.py deleted file mode 100755 index c150a5323..000000000 --- a/share/extensions/test/polyhedron_3d.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../polyhedron_3d.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from polyhedron_3d import * - -class Poly_3DBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Poly_3D() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/printing_marks.test.py b/share/extensions/test/printing_marks.test.py deleted file mode 100755 index 8e4bcc31c..000000000 --- a/share/extensions/test/printing_marks.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../printing-marks.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from printing_marks import * - -class PrintingMarksBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Printing_Marks() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/render_alphabetsoup.test.py b/share/extensions/test/render_alphabetsoup.test.py deleted file mode 100755 index b5575a052..000000000 --- a/share/extensions/test/render_alphabetsoup.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../render_alphabetsoup.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from render_alphabetsoup import * - -class AlphabetSoupBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = AlphabetSoup() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/render_barcode.data b/share/extensions/test/render_barcode.data deleted file mode 100644 index a5052faca..000000000 --- a/share/extensions/test/render_barcode.data +++ /dev/null @@ -1,500 +0,0 @@ -ean8:9493712:2020001011010001100010110111101020201000100110011011011001100110202 -ean8:2811738:2020010011011011100110010011001020201000100100001010010001011100202 -ean8:2248057:2020010011001001101000110110111020201110010100111010001001010000202 -ean8:0995042:2020001101000101100010110110001020201110010101110011011001110100202 -ean8:0262682:2020001101001001101011110010011020201010000100100011011001010000202 -ean8:2006346:2020010011000110100011010101111020201000010101110010100001000100202 -ean8:9892307:2020001011011011100010110010011020201000010111001010001001010000202 -ean8:7033691:2020111011000110101111010111101020201010000111010011001101000100202 -ean8:6587381:2020101111011000101101110111011020201000010100100011001101010000202 -ean8:4491441:2020100011010001100010110011001020201011100101110011001101000100202 -ean8:0099044:2020001101000110100010110001011020201110010101110010111001001000202 -ean8:7565347:2020111011011000101011110110001020201000010101110010001001000100202 -ean8:0764195:2020001101011101101011110100011020201100110111010010011101011100202 -ean8:4882328:2020100011011011101101110010011020201000010110110010010001110100202 -ean8:4635078:2020100011010111101111010110001020201110010100010010010001000100202 -ean8:8992114:2020110111000101100010110010011020201100110110011010111001101100202 -ean8:6658162:2020101111010111101100010110111020201100110101000011011001001000202 -ean8:7880049:2020111011011011101101110001101020201110010101110011101001010000202 -ean8:7782648:2020111011011101101101110010011020201010000101110010010001110010202 -ean8:8249002:2020110111001001101000110001011020201110010111001011011001000100202 -ean8:8735885:2020110111011101101111010110001020201001000100100010011101001000202 -ean8:9818050:2020001011011011100110010110111020201110010100111011100101110100202 -ean8:3410390:2020111101010001100110010001101020201000010111010011100101010000202 -ean8:9699144:2020001011010111100010110001011020201100110101110010111001101100202 -ean8:7628790:2020111011010111100100110110111020201000100111010011100101110100202 -ean8:2020310:2020010011000110100100110001101020201000010110011011100101001000202 -ean8:0429248:2020001101010001100100110001011020201101100101110010010001000100202 -ean8:3135528:2020111101001100101111010110001020201001110110110010010001001110202 -ean8:3182301:2020111101001100101101110010011020201000010111001011001101101100202 -ean8:0320063:2020001101011110100100110001101020201110010101000010000101010000202 -ean8:0865925:2020001101011011101011110110001020201110100110110010011101001110202 -ean8:3413434:2020111101010001100110010111101020201011100100001010111001011100202 -ean8:6730313:2020101111011101101111010001101020201000010110011010000101000100202 -ean8:4091215:2020100011000110100010110011001020201101100110011010011101001000202 -ean8:6504268:2020101111011000100011010100011020201101100101000010010001000100202 -ean8:0127593:2020001101001100100100110111011020201001110111010010000101000010202 -ean8:9214184:2020001011001001100110010100011020201100110100100010111001100110202 -ean8:4457000:2020100011010001101100010111011020201110010111001011100101101100202 -ean8:2575579:2020010011011000101110110110001020201001110100010011101001011100202 -ean8:3501739:2020111101011000100011010011001020201000100100001011101001011100202 -ean8:0733658:2020001101011101101111010111101020201010000100111010010001011100202 -ean8:6162818:2020101111001100101011110010011020201001000110011010010001101100202 -ean8:2397509:2020010011011110100010110111011020201001110111001011101001001110202 -ean8:3813610:2020111101011011100110010111101020201010000110011011100101001000202 -ean8:9488712:2020001011010001101101110110111020201000100110011011011001110100202 -ean8:1754326:2020011001011101101100010100011020201000010110110010100001101100202 -ean8:5221351:2020110001001001100100110011001020201000010100111011001101110100202 -ean8:6047658:2020101111000110101000110111011020201010000100111010010001010000202 -ean8:0475473:2020001101010001101110110110001020201011100100010010000101101100202 -ean8:0775368:2020001101011101101110110110001020201000010101000010010001001000202 -ean8:5825189:2020110001011011100100110110001020201100110100100011101001001000202 -ean8:9934666:2020001011000101101111010100011020201010000101000010100001110100202 -ean8:4849196:2020100011011011101000110001011020201100110111010010100001110100202 -ean8:6672405:2020101111010111101110110010011020201011100111001010011101010000202 -ean8:6368942:2020101111011110101011110110111020201110100101110011011001010000202 -ean8:0356360:2020001101011110101100010101111020201000010101000011100101100110202 -ean8:1506024:2020011001011000100011010101111020201110010110110010111001101100202 -ean8:0218852:2020001101001001100110010110111020201001000100111011011001101100202 -ean8:4357801:2020100011011110101100010111011020201001000111001011001101010000202 -ean8:8268643:2020110111001001101011110110111020201010000101110010000101000100202 -ean8:0117677:2020001101001100100110010111011020201010000100010010001001000010202 -ean8:8066330:2020110111000110101011110101111020201000010100001011100101110010202 -ean8:3074324:2020111101000110101110110100011020201000010110110010111001000010202 -ean8:7241642:2020111011001001101000110011001020201010000101110011011001010000202 -ean8:3375910:2020111101011110101110110110001020201110100110011011100101011100202 -ean8:5797167:2020110001011101100010110111011020201100110101000010001001011100202 -ean8:4413827:2020100011010001100110010111101020201001000110110010001001100110202 -ean8:0008083:2020001101000110100011010110111020201110010100100010000101001110202 -ean8:3240693:2020111101001001101000110001101020201010000111010010000101100110202 -ean8:3358989:2020111101011110101100010110111020201110100100100011101001000010202 -ean8:2525297:2020010011011000100100110110001020201101100111010010001001101100202 -ean8:9429514:2020001011010001100100110001011020201001110110011010111001010000202 -ean8:7496160:2020111011010001100010110101111020201100110101000011100101000010202 -ean8:2549811:2020010011011000101000110001011020201001000110011011001101110010202 -ean8:0366059:2020001101011110101011110101111020201110010100111011101001100110202 -ean8:7565529:2020111011011000101011110110001020201001110110110011101001000100202 -ean8:0544331:2020001101011000101000110100011020201000010100001011001101011100202 -ean8:5278325:2020110001001001101110110110111020201000010110110010011101001000202 -ean8:9659719:2020001011010111101100010001011020201000100110011011101001011100202 -ean8:6060276:2020101111000110101011110001101020201101100100010010100001000010202 -ean8:9983234:2020001011000101101101110111101020201101100100001010111001010000202 -ean8:9912723:2020001011000101100110010010011020201000100110110010000101000100202 -ean8:3934993:2020111101000101101111010100011020201110100111010010000101011100202 -ean8:9878705:2020001011011011101110110110111020201000100111001010011101110010202 -ean8:6099896:2020101111000110100010110001011020201001000111010010100001001110202 -ean8:9344302:2020001011011110101000110100011020201000010111001011011001110100202 -ean8:5779196:2020110001011101101110110001011020201100110111010010100001001000202 -ean8:2670364:2020010011010111101110110001101020201000010101000010111001110010202 -ean8:4049157:2020100011000110101000110001011020201100110100111010001001001000202 -ean8:6303180:2020101111011110100011010111101020201100110100100011100101001110202 -ean8:4252404:2020100011001001101100010010011020201011100111001010111001001110202 -ean8:6442834:2020101111010001101000110010011020201001000100001010111001001110202 -ean8:7330702:2020111011011110101111010001101020201000100111001011011001110010202 -ean8:6650523:2020101111010111101100010001101020201001110110110010000101001110202 -ean8:3261954:2020111101001001101011110011001020201110100100111010111001010000202 -ean8:1149083:2020011001001100101000110001011020201110010100100010000101001000202 -ean8:1227062:2020011001001001100100110111011020201110010101000011011001110010202 -ean8:7770854:2020111011011101101110110001101020201001000100111010111001110010202 -ean8:4841093:2020100011011011101000110011001020201110010111010010000101110100202 -ean8:9642244:2020001011010111101000110010011020201101100101110010111001100110202 -ean13:082432472648:20201101110010011010001101111010010011010001102020100010011011001010000101110010010001110010202 -ean13:867963203104:20201011110010001000101100001010100001001001102020111001010000101100110111001010111001001110202 -ean13:509274672682:20200011010010111001101101110110100011000010102020100010011011001010000100100011011001110010202 -ean13:137969745319:20201111010111011001011101011110010111001000102020101110010011101000010110011011101001101100202 -ean13:167788639568:20201011110111011001000101101110001001000010102020100001011101001001110101000010010001101100202 -ean13:763909437639:20201011110100001000101101001110001011001110102020100001010001001010000100001011101001110010202 -ean13:552090940230:20201100010011011010011100010110001101001011102020101110011100101101100100001011100101110100202 -ean13:064430020090:20201011110100011010001101111010001101000110102020110110011100101110010111010011100101001000202 -ean13:932131660272:20201111010011011011001101111010110011010111102020101000011100101101100100010011011001001000202 -ean13:697948544222:20200010110010001001011100111010110111011000102020101110010111001101100110110011011001110010202 -ean13:156973387097:20201100010101111001011101110110100001010000102020100100010001001110010111010010001001100110202 -ean13:742353933447:20201000110011011011110101110010111101001011102020100001010000101011100101110010001001001000202 -ean13:165804313397:20201011110110001000100100011010011101010000102020110011010000101000010111010010001001101100202 -ean13:142542648187:20201000110010011011100101000110011011000010102020101110010010001100110100100010001001101100202 -ean13:293746185362:20200010110111101001000100111010101111011001102020100100010011101000010101000011011001011100202 -ean13:079018947306:20201110110001011000110100110010110111000101102020101110010001001000010111001010100001110010202 -ean13:114714603442:20200110010100011001000100110010011101000010102020111001010000101011100101110011011001000100202 -ean13:886864480655:20201101110000101011011100001010011101010001102020100100011100101010000100111010011101011100202 -ean13:087399049352:20201101110111011011110100010110001011000110102020101110011101001000010100111011011001000010202 -ean13:680731212600:20201101110100111001000101000010011001001001102020110011011011001010000111001011100101001000202 -ean13:839853108496:20201111010010111011011101110010100001001100102020111001010010001011100111010010100001001000202 -ean13:759662798861:20201100010010111010111100001010010011001000102020111010010010001001000101000011001101011100202 -ean13:522030126885:20200100110011011010011101111010001101011001102020110110010100001001000100100010011101011100202 -ean13:872252192093:20201110110011011001001101110010011011001100102020111010011011001110010111010010000101011100202 -ean13:978323527315:20201110110001001010000100100110100001011000102020110110010001001000010110011010011101110100202 -ean13:594820728295:20200010110011101000100100100110001101001000102020110110010010001101100111010010011101000100202 -ean13:817309047999:20200110010010001011110101001110010111000110102020101110010001001110100111010011101001011100202 -ean13:529552650589:20200100110010111011100101100010010011000010102020100111011100101001110100100011101001000010202 -ean13:301953031072:20200011010011001001011101110010100001000110102020100001011001101110010100010011011001101100202 -ean13:279759074172:20201110110001011001000101110010001011010011102020100010010111001100110100010011011001011100202 -ean13:966269952443:20201011110000101001101101011110010111000101102020100111011011001011100101110010000101000100202 -ean13:393886491651:20200010110111101000100100010010000101010001102020111010011001101010000100111011001101110100202 -ean13:592818880852:20200010110011011000100100110010110111000100102020100100011100101001000100111011011001110010202 -ean13:629415132010:20200100110010111001110101100110110001001100102020100001011011001110010110011011100101001000202 -ean13:649798154930:20201000110010111001000100101110110111001100102020100111010111001110100100001011100101110100202 -ean13:106475417609:20200011010101111001110101110110111001001110102020110011010001001010000111001011101001110010202 -ean13:853904645292:20201100010100001000101101001110011101010111102020101110010011101101100111010011011001100110202 -ean13:431977667645:20201111010110011000101101110110010001000010102020101000010001001010000101110010011101000010202 -ean13:814819509497:20200110010011101011011101100110010111011000102020111001011101001011100111010010001001000100202 -ean13:308817835364:20200011010110111000100101100110010001011011102020100001010011101000010101000010111001011100202 -ean13:618801393027:20200110010001001000100101001110011001011110102020111010010000101110010110110010001001110010202 -ean13:164480667538:20201011110100011001110101101110100111000010102020101000010001001001110100001010010001011100202 -ean13:081023710137:20201101110011001000110100100110111101011101102020110011011100101100110100001010001001000100202 -ean13:493359422890:20200010110100001011110101100010010111001110102020110110011011001001000111010011100101110010202 -ean13:275532814865:20201110110110001011100101000010010011000100102020110011010111001001000101000010011101001000202 -ean13:111345042302:20200110010011001010000101000110111001010011102020101110011011001000010111001011011001001000202 -ean13:513537464719:20200110010100001011100101111010111011001110102020101000010111001000100110011011101001001110202 -ean13:766449694282:20201011110000101010001100111010001011000010102020111010010111001101100100100011011001110100202 -ean13:961792988802:20201011110110011001000100010110011011000101102020100100010010001001000111001011011001001110202 -ean13:866540005468:20201011110000101011000100111010100111000110102020111001010011101011100101000010010001101100202 -ean13:888983089059:20201101110001001000101100010010100001000110102020100100011101001110010100111011101001100110202 -ean13:722513175727:20200100110011011011000101100110111101011001102020100010010011101000100110110010001001110100202 -ean13:843297735811:20201000110100001001001100101110010001011101102020100001010011101001000110011011001101101100202 -ean13:627233353075:20200100110010001001101101000010111101011110102020100111010000101110010100010010011101110010202 -ean13:203591705672:20200011010111101011100100101110011001001000102020111001010011101010000100010011011001001110202 -ean13:686779501514:20201101110000101001000100100010001011011000102020111001011001101001110110011010111001001110202 -ean13:379483955591:20201110110001011001110100010010100001000101102020100111010011101001110111010011001101101100202 -ean13:576363706332:20201110110000101010000101011110111101001000102020111001010100001000010100001011011001000010202 -ean13:295226681860:20200010110110001001101100110110101111000010102020100100011001101001000101000011100101110100202 -ean13:901443422086:20200011010110011001110101000110100001010001102020110110011011001110010100100010100001000100202 -ean13:093300442985:20200010110111101011110100011010001101010001102020101110011011001110100100100010011101000010202 -ean13:517520551545:20200110010010001011100100100110001101011100102020100111011001101001110101110010011101000010202 -ean13:370982564882:20201110110001101001011100010010011011011000102020101000010111001001000100100011011001110010202 -ean13:640884610730:20201000110100111000100100010010100011010111102020110011011100101000100100001011100101001110202 -ean13:601211133573:20200011010110011001101101100110011001001100102020100001010000101001110100010010000101110100202 -ean13:772390839786:20201110110011011011110100101110001101000100102020100001011101001000100100100010100001110100202 -ean13:037823325554:20201111010111011011011100100110111101011110102020110110010011101001110100111010111001000010202 -ean13:636746415900:20201111010000101001000100111010101111010001102020110011010011101110100111001011100101000100202 -ean13:378365729312:20201110110110111010000100001010111001011101102020110110011101001000010110011011011001110010202 -ean13:588008084415:20201101110001001010011100011010110111010011102020100100010111001011100110011010011101000010202 -ean13:493847586062:20200010110100001011011101000110010001011100102020100100010100001110010101000011011001110010202 -ean13:661725378018:20201011110110011001000100110110110001011110102020100010010010001110010110011010010001110010202 -ean13:785941917380:20201101110111001000101100111010011001001011102020110011010001001000010100100011100101011100202 -ean13:476858945743:20201110110000101011011101100010001001001011102020101110010011101000100101110010000101010000202 -ean13:621022451023:20200100110110011010011100110110010011010001102020100111011001101110010110110010000101001000202 -ean13:738611126276:20201111010001001010111101100110011001011001102020110110010100001101100100010010100001110010202 -ean13:610023637901:20200110010100111010011100110110111101010111102020100001010001001110100111001011001101001000202 -ean13:310432899227:20200110010001101001110101000010011011011011102020111010011101001101100110110010001001110010202 -ean13:079481718507:20201110110001011010001101101110011001011101102020110011010010001001110111001010001001000010202 -ean13:794525704564:20200010110011101011000100110110110001001000102020111001010111001001110101000010111001010000202 -ean13:367079205365:20201011110111011010011100100010010111001001102020111001010011101000010101000010011101100110202 -ean13:791478205064:20200010110110011010001100100010110111001101102020111001010011101110010101000010111001000100202 -ean13:622805103976:20200100110011011000100101001110110001001100102020111001010000101110100100010010100001100110202 -ean13:659692878482:20201100010010111000010100101110010011011011102020100010010010001011100100100011011001011100202 -ean13:312673979722:20200110010010011000010100100010100001000101102020100010011101001000100110110011011001110010202 -ean13:634789369262:20201111010011101001000100010010001011011110102020101000011101001101100101000011011001000100202 -ean13:508031061191:20200011010001001010011101111010011001010011102020101000011001101100110111010011001101000100202 -ean13:617546677352:20200110010010001011100100111010101111010111102020100010010001001000010100111011011001000010202 -ean13:386750842077:20201101110101111001000101110010100111011011102020101110011011001110010100010010001001100110202 -ean13:217930060540:20200110010111011001011101000010001101010011102020101000011100101001110101110011100101100110202 -ean13:529453929533:20200100110010111001110101100010111101001011102020110110011101001001110100001010000101000010202 -ean13:403667633768:20200011010100001010111101011110010001000010102020100001010000101000100101000010010001110100202 -ean13:788401327704:20201101110001001010001101001110011001010000102020110110010001001000100111001010111001000100202 -ean13:316882500762:20200110010101111000100100010010011011011000102020111001011100101000100101000011011001101100202 -ean13:413254666172:20200110010100001001001101100010011101000010102020101000010100001100110100010011011001100110202 -ean13:666719764771:20201011110000101001000101100110001011011101102020101000010111001000100100010011001101100110202 -ean13:502326102133:20200011010011011010000100100110101111011001102020111001011011001100110100001010000101010000202 -ean13:690549661049:20200010110100111011100100111010001011010111102020101000011001101110010101110011101001001110202 -ean13:055572466568:20201100010110001011000101110110010011010001102020101000010100001001110101000010010001110100202 -ean13:636596356068:20201111010000101011100100101110101111011110102020100111010100001110010101000010010001000010202 -upce:844677:202000100100111010011101010111101110110111011020202 -upce:610879:202000010101100110001101011011101110110010111020202 -upce:982526:202001011100010010011011011000100100110101111020202 -upce:846420:202000100100111010101111010001100110110001101020202 -upce:322140:202010000100110110010011001100100111010001101020202 -upce:625042:202000010100100110110001010011101000110011011020202 -upce:996072:202001011100101110101111000110101110110011011020202 -upce:539996:202011100101000010001011000101100010110000101020202 -upce:340168:202010000100111010001101001100100001010110111020202 -upce:841913:202000100101000110100111000101101100110011001020202 -upce:124122:202011001100110110100011001100100110110010011020202 -upce:401968:202001110100011010110011000101101011110001001020202 -upce:225085:202001101100100110111001010011101101110110001020202 -upce:368038:202010000101011110001001010011101111010110111020202 -upce:817155:202000100100110010111011011001101100010111001020202 -upce:554120:202011100101110010100011011001100100110001101020202 -upce:113080:202011001101100110111101000110101101110100111020202 -upce:755380:202001000101100010110001011110100010010100111020202 -upce:201858:202001101100011010110011000100101100010110111020202 -upce:226567:202001101100100110000101011100101011110111011020202 -upce:507089:202011100101001110111011000110101101110010111020202 -upce:442680:202001110101000110011011010111101101110100111020202 -upce:557738:202011100101100010111011001000101000010110111020202 -upce:928720:202001011100100110001001011101100100110100111020202 -upce:395240:202010000100101110110001001101101000110001101020202 -upce:931548:202001011101111010110011011000101000110001001020202 -upce:729228:202001000100100110001011001001100110110001001020202 -upce:116746:202011001100110010000101011101100111010101111020202 -upce:293469:202001101100101110111101010001101011110010111020202 -upce:555569:202011100101100010111001011000100001010001011020202 -upce:786474:202001000100010010000101010001101110110100011020202 -upce:761950:202001000101011110110011000101101100010100111020202 -upce:585584:202011100101101110111001011000100010010100011020202 -upce:929816:202001011100110110001011011011100110010000101020202 -upce:311259:202010000100110010011001001101101110010001011020202 -upce:694531:202000010100101110011101011000101111010011001020202 -upce:375808:202010000100100010110001011011101101110011101020202 -upce:240462:202001101100111010001101010001100001010010011020202 -upce:309270:202010000100011010010111001001100100010001101020202 -upce:531272:202011100101111010110011001001101110110011011020202 -upce:910577:202001011100110010001101011100100100010111011020202 -upce:816561:202000100100110010000101011000100001010011001020202 -upce:805838:202000100100011010110001011011101000010001001020202 -upce:533215:202011100101000010111101001101100110010110001020202 -upce:346122:202010000101000110000101001100100100110011011020202 -upce:625930:202000010100100110110001001011101000010001101020202 -upce:952717:202001011101110010010011001000100110010111011020202 -upce:402896:202001110101001110010011011011100010110000101020202 -upce:295983:202001101100101110110001000101101101110100001020202 -upce:024592:202010011100100110011101011000100010110011011020202 -upce:289724:202001101101101110010111011101100100110011101020202 -upce:252704:202001101101110010011011011101100011010100011020202 -upce:273290:202001101101110110111101001101100010110100111020202 -upce:385633:202010000100010010110001010111101111010100001020202 -upce:549951:202011100100111010001011001011101100010011001020202 -upce:568347:202011100101011110110111010000100111010111011020202 -upce:214740:202001101100110010011101001000101000110001101020202 -upce:969934:202001011101011110010111000101101111010011101020202 -upce:832367:202000100101111010010011010000100001010111011020202 -upce:359222:202010000101100010001011001101100110110010011020202 -upce:508230:202011100101001110001001001001101111010001101020202 -upce:308002:202010000101001110110111010011100011010010011020202 -upce:318751:202010000100110010001001011101101110010011001020202 -upce:174459:202011001100100010011101010001101100010001011020202 -upce:403448:202001110101001110111101010001101000110001001020202 -upce:429459:202001110100100110010111010001101110010001011020202 -upce:271338:202001101100100010110011011110101111010110111020202 -upce:515949:202011100100110010110001001011101000110010111020202 -upce:066186:202010011101011110000101001100100010010101111020202 -upce:609466:202000010100011010001011001110101011110000101020202 -upce:857406:202000100101110010010001010001101011110100011020202 -upce:237382:202001101101111010111011010000101101110011011020202 -upce:260304:202001101100001010001101010000100011010100011020202 -upce:899152:202000100100101110010111001100101100010010011020202 -upce:773424:202001000100100010111101001110100100110100011020202 -upce:367789:202010000101011110111011011101100010010010111020202 -upce:344078:202010000100111010011101000110101110110110111020202 -upce:627031:202000010100100110010001000110101000010011001020202 -upce:146732:202011001100111010101111001000101111010010011020202 -upce:608666:202000010100011010001001000010101011110101111020202 -upce:855228:202000100101110010111001001001100100110110111020202 -upce:439192:202001110101000010010111001100100010110010011020202 -upce:917451:202001011100110010010001010001101110010011001020202 -upce:072613:202010011101110110100111010111100110010011011020202 -upce:813590:202000100100110010100001011000100010110100111020202 -upce:176138:202011001100100010101111001100101000010110111020202 -upce:690945:202000010100101110001101001011101000110110001020202 -upce:849613:202000100100111010001011010111101100110111101020202 -upce:269053:202001101101011110001011000110101110010100001020202 -upce:701050:202001000100011010011001010011101110010001101020202 -upce:074527:202010011101110110011101011000100110110111011020202 -upce:218296:202001101100110010001001001101100010110101111020202 -upce:874938:202000100100100010100011000101101111010001001020202 -upce:023936:202010011100110110111101000101101111010000101020202 -upce:896764:202000100100101110000101011101101011110100011020202 -upce:979612:202001011100100010001011010111101100110010011020202 -upce:137449:202011001101000010010001010001101000110001011020202 -upce:687160:202000010100010010010001001100101011110001101020202 -upce:839620:202000100101111010010111000010100100110001101020202 -upce:921800:202001011100100110110011000100100011010001101020202 -ean5:72823:010110010001010011011010110111010010011010111101 -ean5:19075:010110110011010001011010001101010010001010110001 -ean5:16659:010110011001010000101010101111010111001010001011 -ean5:54239:010110111001010100011010011011010111101010001011 -ean5:70848:010110111011010001101010001001010011101010110111 -ean5:75795:010110010001010110001010111011010001011010111001 -ean5:15726:010110011001010110001010010001010011011010101111 -ean5:58560:010110110001010110111010110001010000101010100111 -ean5:24670:010110011011010100011010101111010111011010100111 -ean5:24946:010110011011010100011010001011010100011010000101 -ean5:69776:010110000101010001011010010001010111011010101111 -ean5:74692:010110010001010100011010101111010010111010010011 -ean5:10925:010110110011010001101010001011010010011010111001 -ean5:63372:010110000101010111101010111101010111011010011011 -ean5:62942:010110101111010010011010010111010011101010010011 -ean5:35265:010110111101010110001010011011010101111010111001 -ean5:38088:010110111101010001001010001101010001001010110111 -ean5:50203:010110111001010100111010010011010001101010111101 -ean5:57111:010110111001010111011010011001010011001010110011 -ean5:64593:010110101111010100011010111001010001011010100001 -ean5:52424:010110110001010010011010011101010011011010100011 -ean5:77259:010110010001010111011010010011010111001010001011 -ean5:07028:010110001101010111011010100111010011011010110111 -ean5:50627:010110111001010001101010101111010011011010111011 -ean5:60414:010110000101010001101010011101010011001010100011 -ean5:86940:010110001001010101111010010111010100011010001101 -ean5:36095:010110111101010101111010100111010001011010111001 -ean5:01124:010110100111010011001010011001010011011010100011 -ean5:57346:010110111001010111011010100001010100011010101111 -ean5:79607:010110010001010001011010000101010001101010111011 -ean5:31184:010110111101010011001010110011010001001010100011 -ean5:29583:010110011011010001011010110001010110111010100001 -ean5:75568:010110111011010110001010111001010101111010001001 -ean5:53258:010110110001010100001010010011010111001010110111 -ean5:78345:010110010001010110111010111101010100011010111001 -ean5:56838:010110110001010000101010001001010111101010110111 -ean5:61031:010110101111010110011010001101010100001010011001 -ean5:98054:010110001011010110111010001101010111001010011101 -ean5:28204:010110010011010110111010010011010100111010011101 -ean5:18738:010110011001010001001010111011010100001010110111 -ean5:17221:010110110011010111011010010011010010011010110011 -ean5:02270:010110001101010011011010010011010010001010001101 -ean5:02378:010110001101010011011010100001010111011010110111 -ean5:15957:010110110011010110001010010111010110001010111011 -ean5:13621:010110011001010111101010000101010010011010110011 -ean5:98891:010110001011010001001010110111010010111010011001 -ean5:50554:010110110001010100111010110001010111001010100011 -ean5:22677:010110010011010010011010101111010010001010010001 -ean5:49420:010110011101010001011010100011010010011010100111 -ean5:57712:010110110001010010001010010001010011001010010011 -ean5:13839:010110011001010100001010110111010111101010010111 -ean5:36422:010110111101010101111010011101010010011010011011 -ean5:10137:010110011001010100111010110011010111101010111011 -ean5:22734:010110010011010011011010010001010111101010100011 -ean5:25562:010110010011010110001010110001010000101010011011 -ean5:49015:010110100011010010111010001101010110011010110001 -ean5:34620:010110100001010100011010000101010010011010001101 -ean5:74909:010110010001010100011010010111010001101010001011 -ean5:57115:010110110001010111011010110011010110011010110001 -ean5:84963:010110001001010011101010001011010101111010111101 -ean5:95948:010110001011010110001010010111010100011010001001 -ean5:36006:010110100001010101111010100111010001101010101111 -ean5:05457:010110100111010110001010100011010110001010010001 -ean5:54806:010110111001010100011010110111010001101010000101 -ean5:32152:010110100001010010011010110011010110001010010011 -ean5:64913:010110101111010100011010010111010011001010100001 -ean5:53560:010110111001010111101010111001010101111010001101 -ean5:57373:010110110001010111011010100001010111011010100001 -ean5:54685:010110110001010100011010101111010001001010111001 -ean5:75408:010110010001010110001010100011010100111010110111 -ean5:56632:010110111001010000101010101111010111101010010011 -ean5:22639:010110010011010010011010101111010100001010010111 -ean5:92955:010110010111010010011010001011010111001010110001 -ean5:75465:010110111011010111001010100011010000101010110001 -ean5:56506:010110111001010101111010110001010100111010101111 -ean5:22627:010110011011010010011010000101010010011010111011 -ean5:98251:010110010111010110111010010011010110001010110011 -ean5:90220:010110010111010001101010011011010010011010001101 -ean5:93426:010110010111010111101010100011010011011010101111 -ean5:74169:010110010001010100011010110011010101111010001011 -ean5:36259:010110100001010101111010011011010110001010001011 -ean5:71855:010110111011010110011010001001010110001010110001 -ean5:04584:010110001101010100011010111001010001001010100011 -ean5:01152:010110100111010011001010011001010110001010011011 -ean5:72757:010110111011010010011010111011010111001010010001 -ean5:28673:010110010011010001001010101111010111011010100001 -ean5:75084:010110010001010111001010001101010110111010100011 -ean5:10562:010110011001010100111010110001010101111010011011 -ean5:63726:010110000101010111101010111011010011011010101111 -ean5:04292:010110001101010100011010011011010001011010011011 -ean5:77513:010110111011010010001010110001010110011010111101 -ean5:17826:010110011001010111011010110111010011011010000101 -ean5:44790:010110011101010011101010111011010001011010001101 -ean5:39572:010110111101010010111010111001010111011010010011 -ean5:55321:010110111001010111001010111101010010011010011001 -ean5:89717:010110110111010001011010111011010110011010010001 -ean5:02126:010110001101010011011010011001010011011010101111 -ean5:30106:010110100001010100111010011001010001101010101111 -ean5:57489:010110110001010111011010011101010110111010010111 -ean5:26505:010110011011010000101010110001010001101010110001 -upca:40710631975:20201000110001101011101100110010001101010111102020100001011001101110100100010010011101100110202 -upca:80176224795:20201101110001101001100101110110101111001001102020110110010111001000100111010010011101100110202 -upca:92748137722:20200010110010011011101101000110110111001100102020100001010001001000100110110011011001010000202 -upca:32450677259:20201111010010011010001101100010001101010111102020100010010001001101100100111011101001110010202 -upca:40851674702:20201000110001101011011101100010011001010111102020100010010111001000100111001011011001001000202 -upca:59115174167:20201100010001011001100100110010110001001100102020100010010111001100110101000010001001100110202 -upca:84003578078:20201101110100011000110100011010111101011000102020100010010010001110010100010010010001001000202 -upca:95062540829:20200010110110001000110101011110010011011000102020101110011100101001000110110011101001010000202 -upca:64901078016:20201011110100011000101100011010011001000110102020100010010010001110010110011010100001110010202 -upca:48432140125:20201000110110111010001101111010010011001100102020101110011100101100110110110010011101010000202 -upca:17430588576:20200110010111011010001101111010001101011000102020100100010010001001110100010010100001001000202 -upca:63153964133:20201011110111101001100101100010111101000101102020101000010111001100110100001010000101010000202 -upca:74093932950:20201110110100011000110100010110111101000101102020100001011011001110100100111011100101001110202 -upca:57541363089:20201100010111011011000101000110011001011110102020101000010000101110010100100011101001000100202 -upca:07377087198:20200011010111011011110101110110111011000110102020100100010001001100110111010010010001110100202 -upca:05635524594:20200011010110001010111101111010110001011000102020110110010111001001110111010010111001001000202 -upca:70318362910:20201110110001101011110100110010110111011110102020101000011011001110100110011011100101011100202 -upca:36925218506:20201111010101111000101100100110110001001001102020110011010010001001110111001010100001001110202 -upca:45343236277:20201000110110001011110101000110111101001001102020100001010100001101100100010010001001110010202 -upca:03926388241:20200011010111101000101100100110101111011110102020100100010010001101100101110011001101101100202 -upca:64192083538:20201011110100011001100100010110010011000110102020100100010000101001110100001010010001100110202 -upca:25525653142:20200100110110001011000100100110110001010111102020100111010000101100110101110011011001110010202 -upca:38104462945:20201111010110111001100100011010100011010001102020101000011011001110100101110010011101001000202 -upca:09225889378:20200011010001011001001100100110110001011011102020100100011101001000010100010010010001000100202 -upca:93748811785:20200010110111101011101101000110110111011011102020110011011001101000100100100010011101001110202 -upca:30467816622:20201111010001101010001101011110111011011011102020110011010100001010000110110011011001110100202 -upca:74931591622:20201110110100011000101101111010011001011000102020111010011001101010000110110011011001000010202 -upca:92475784788:20200010110010011010001101110110110001011101102020100100010111001000100100100010010001110100202 -upca:40454544331:20201000110001101010001101100010100011011000102020101110010111001000010100001011001101000010202 -upca:35237883084:20201111010110001001001101111010111011011011102020100100010000101110010100100010111001100110202 -upca:75646706855:20201110110110001010111101000110101111011101102020111001010100001001000100111010011101000100202 -upca:82889483314:20201101110010011011011101101110001011010001102020100100010000101000010110011010111001101100202 -upca:73893633416:20201110110111101011011100010110111101010111102020100001010000101011100110011010100001001110202 -upca:10454576813:20200110010001101010001101100010100011011000102020100010010100001001000110011010000101101100202 -upca:33334522835:20201111010111101011110101111010100011011000102020110110011011001001000100001010011101110100202 -upca:45793591164:20201000110110001011101100010110111101011000102020111010011001101100110101000010111001110010202 -upca:18057726450:20200110010110111000110101100010111011011101102020110110010100001011100100111011100101000100202 -upca:96083152912:20200010110101111000110101101110111101001100102020100111011011001110100110011011011001001000202 -upca:16563181689:20200110010101111011000101011110111101001100102020100100011001101010000100100011101001101100202 -upca:51276473461:20201100010011001001001101110110101111010001102020100010010000101011100101000011001101011100202 -upca:08128913293:20200011010110111001100100100110110111000101102020110011010000101101100111010010000101011100202 -upca:34146752391:20201111010100011001100101000110101111011101102020100111011011001000010111010011001101000100202 -upca:97515692692:20200010110111011011000100110010110001010111102020111010011011001010000111010011011001000100202 -upca:97669919853:20200010110111011010111101011110001011000101102020110011011101001001000100111010000101010000202 -upca:18678734797:20200110010110111010111101110110110111011101102020100001010111001000100111010010001001110100202 -upca:74076303825:20201110110100011000110101110110101111011110102020111001010000101001000110110010011101000010202 -upca:08662387020:20200011010110111010111101011110010011011110102020100100010001001110010110110011100101010000202 -upca:26133671442:20200100110101111001100101111010111101010111102020100010011001101011100101110011011001000010202 -upca:87138605931:20201101110111011001100101111010110111010111102020111001010011101110100100001011001101001110202 -upca:67189289819:20201011110111011001100101101110001011001001102020100100011101001001000110011011101001110010202 -upca:09759720707:20200011010001011011101101100010001011011101102020110110011100101000100111001010001001000010202 -upca:56485529906:20201100010101111010001101101110110001011000102020110110011101001110100111001010100001110100202 -upca:58154525395:20201100010110111001100101100010100011011000102020110110010011101000010111010010011101001000202 -upca:67888609275:20201011110111011011011101101110110111010111102020111001011101001101100100010010011101010000202 -upca:15168153237:20200110010110001001100101011110110111001100102020100111010000101101100100001010001001110010202 -upca:74424730673:20201110110100011010001100100110100011011101102020100001011100101010000100010010000101110100202 -upca:45168971187:20201000110110001001100101011110110111000101102020100010011001101100110100100010001001000100202 -upca:12149723784:20200110010010011001100101000110001011011101102020110110010000101000100100100010111001011100202 -upca:33804286457:20201111010111101011011100011010100011001001102020100100010100001011100100111010001001101100202 -upca:27558248562:20200100110111011011000101100010110111001001102020101110010010001001110101000011011001011100202 -upca:92390267160:20200010110010011011110100010110001101001001102020101000010001001100110101000011100101000100202 -upca:63742039163:20201011110111101011101101000110010011000110102020100001011101001100110101000010000101101100202 -upca:67117098326:20201011110111011001100100110010111011000110102020111010010010001000010110110010100001010000202 -upca:32901624258:20201111010010011000101100011010011001010111102020110110010111001101100100111010010001001000202 -upca:88848685777:20201101110110111011011101000110110111010111102020100100010011101000100100010010001001101100202 -upca:57070085601:20201100010111011000110101110110001101000110102020100100010011101010000111001011001101100110202 -upca:83043128438:20201101110111101000110101000110111101001100102020110110010010001011100100001010010001010000202 -upca:52432147628:20201100010010011010001101111010010011001100102020101110010001001010000110110010010001001000202 -upca:15067795584:20200110010110001000110101011110111011011101102020111010010011101001110100100010111001100110202 -upca:27777156430:20200100110111011011101101110110111011001100102020100111010100001011100100001011100101100110202 -upca:82471218344:20201101110010011010001101110110011001001001102020110011010010001000010101110010111001011100202 -upca:94175044091:20200010110100011001100101110110110001000110102020101110010111001110010111010011001101010000202 -upca:34936749963:20201111010100011000101101111010101111011101102020101110011101001110100101000010000101110100202 -upca:46502492658:20201000110101111011000100011010010011010001102020111010011011001010000100111010010001100110202 -upca:47153985860:20201000110111011001100101100010111101000101102020100100010011101001000101000011100101010000202 -upca:79601763982:20201110110001011010111100011010011001011101102020101000010000101110100100100011011001110010202 -upca:91685238225:20200010110011001010111101101110110001001001102020100001010010001101100110110010011101110100202 -upca:46916417994:20201000110101111000101100110010101111010001102020110011010001001110100111010010111001011100202 -upca:30878845484:20201111010001101011011101110110110111011011102020101110010011101011100100100010111001110100202 -upca:39321907655:20201111010001011011110100100110011001000101102020111001010001001010000100111010011101011100202 -upca:48232524842:20201000110110111001001101111010010011011000102020110110010111001001000101110011011001010000202 -upca:94750199914:20200010110100011011101101100010001101001100102020111010011101001110100110011010111001010000202 -upca:28310653784:20200100110110111011110100110010001101010111102020100111010000101000100100100010111001100110202 -upca:00814405096:20200011010001101011011100110010100011010001102020111001010011101110010111010010100001000100202 -upca:60974743279:20201011110001101000101101110110100011011101102020101110010000101101100100010011101001011100202 -upca:45141255670:20201000110110001001100101000110011001001001102020100111010011101010000100010011100101010000202 -upca:62241294735:20201011110010011001001101000110011001001001102020111010010111001000100100001010011101001110202 -upca:67241197048:20201011110111011001001101000110011001001100102020111010010001001110010101110010010001110100202 -upca:57709892169:20201100010111011011101100011010001011011011102020111010011011001100110101000011101001000100202 -upca:49234133045:20201000110001011001001101111010100011001100102020100001010000101110010101110010011101010000202 -upca:44106865868:20201000110100011001100100011010101111011011102020101000010011101001000101000010010001001000202 -upca:07033900539:20200011010111011000110101111010111101000101102020111001011100101001110100001011101001000100202 -upca:63922260360:20201011110111101000101100100110010011001001102020101000011100101000010101000011100101110100202 -upca:63544942112:20201011110111101011000101000110100011000101102020101110011011001100110110011011011001001110202 -upca:52602007800:20201100010010011010111100011010010011000110102020111001010001001001000111001011100101001000202 -upca:94048257810:20200010110100011000110101000110110111001001102020100111010001001001000110011011100101101100202 -upca:82699181094:20201101110010011010111100010110001011001100102020100100011001101110010111010010111001000010202 -upca:94628599972:20200010110100011010111100100110110111011000102020111010011101001110100100010011011001011100202 -upca:09938844603:20200011010001011000101101111010110111011011102020101110010111001010000111001010000101010000202 -upca:37128560103:20201111010111011001100100100110110111011000102020101000011100101100110111001010000101110010202 diff --git a/share/extensions/test/render_barcode.test.py b/share/extensions/test/render_barcode.test.py deleted file mode 100755 index f2ce23873..000000000 --- a/share/extensions/test/render_barcode.test.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2010 Martin Owens -# -# Written to test the coding of generating barcodes. -# - -import sys -import random -import unittest - -# Allow import of the extension code and modules -sys.path.append('..') - -from render_barcode import * - - -digits = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] - -class InsertBarcodeBasicTest(unittest.TestCase): - """Render Barcode""" - def setUp(self): - self.data = {} - fhl = open('render_barcode.data', 'r') - for line in fhl: - line = line.replace('\n', '').replace('\r', '') - (btype, text, code) = line.split(':') - if not self.data.has_key(btype): - self.data[btype] = [] - self.data[btype].append( [ text, code ] ) - fhl.close() - - #def test_run_without_parameters(self): - # args = [ 'minimal-blank.svg', '-t', 'Ean5' ] - # e = InsertBarcode() - # e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - - def test_render_barcode_ian5(self): - """Barcode IAN5""" - self.barcode_test( 'Ean5' ) - - def test_render_barcode_ian8(self): - """Barcode IAN5""" - self.barcode_test( 'Ean8' ) - - def test_render_barcode_ian13(self): - """Barcode IAN5""" - self.barcode_test( 'Ean13' ) - - def test_render_barcode_upca(self): - """Barcode IAN5""" - self.barcode_test( 'Upca' ) - - def test_render_barcode_upce(self): - """Barcode UPCE""" - self.barcode_test( 'Upce' ) - - def barcode_test(self, name): - """Base module for all barcode testing""" - for datum in self.data[name.lower()]: - (text, code) = datum - if not text or not code: - continue - coder = getBarcode( name, text=text) - code2 = coder.encode( text ) - self.assertEqual(code, code2) - - -if __name__ == '__main__': - unittest.main() - diff --git a/share/extensions/test/render_gears.test.py b/share/extensions/test/render_gears.test.py deleted file mode 100755 index ad1668126..000000000 --- a/share/extensions/test/render_gears.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../gears.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from render_gears import * - -class GearsBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Gears() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/restack.test.py b/share/extensions/test/restack.test.py deleted file mode 100755 index da0001b2a..000000000 --- a/share/extensions/test/restack.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../restack.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from restack import * - -class RestackBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Restack() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/rtree.test.py b/share/extensions/test/rtree.test.py deleted file mode 100755 index 56bf89c03..000000000 --- a/share/extensions/test/rtree.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../rtree.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from rtree import * - -class RTreeTurtleBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = RTreeTurtle() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/run-all-extension-tests b/share/extensions/test/run-all-extension-tests deleted file mode 100755 index ff739c311..000000000 --- a/share/extensions/test/run-all-extension-tests +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -# TODO: check for GNU mktemp and sed (from coreutils), else exit -# --------------------------------------------------------------------- -# solution below is based on -# <http://www.ooblick.com/weblog/2011/05/12/a-couple-of-shell-quickies/> - -# Wrapper function for GNU mktemp -gnu_mktemp() { - mktemp "$@" -} - -# Wrapper function for BSD mktemp -bsd_mktemp() { - mktemp -t tmpfile.XXXXXX "$@" -} - -# Try to figure out which wrapper to use -if mktemp -V | grep version >/dev/null 2>&1; then - MKTEMP=gnu_mktemp -else - MKTEMP=bsd_mktemp -fi - -#mytmpfile=`$MKTEMP` -echo "MKTEMP to be used: $MKTEMP" - -# --------------------------------------------------------------------- - -echo -e "\n##### Extension Tests #####" - -cd "$(dirname "$0")" - -has_py_coverage=false -py_cover_files=$( $MKTEMP ) -failed_tests=$( $MKTEMP ) - -if coverage.py erase >/dev/null 2>/dev/null; then - has_py_coverage=true - cover_py_cmd=coverage.py - else - if coverage erase >/dev/null 2>/dev/null; then - has_py_coverage=true - cover_py_cmd=coverage - else - if python-coverage erase >/dev/null 2>/dev/null; then - has_py_coverage=true - cover_py_cmd=python-coverage - else - if coverage-script.py erase >/dev/null 2>/dev/null; then - has_py_coverage=true - cover_py_cmd=coverage-script.py - fi - fi - fi -fi - -if $has_py_coverage; then - echo -e "\nRunning tests with coverage (${cover_py_cmd})" -fi -#if $has_py_coverage; then -# $cover_py_cmd -e -#fi - -function run_py_test() { - echo -e "\n>>>>>> Testing $1 <<<<<<\n" - if $has_py_coverage; then - if ! $cover_py_cmd run -a "$1.test.py"; then - echo "$1" >> $failed_tests - fi - echo "../$1.py" >> $py_cover_files - else - if ! python "$1.test.py"; then - echo "$1" >> $failed_tests - fi - fi - return 0 -} - -tot_FAILED=0 - -# TODO: check for GNU mktemp and sed (from coreutils), else exit -# --------------------------------------------------------------------- -# solution below is based on -# <http://notmuchmail.org/pipermail/notmuch/2011/004579.html> - -if [ `sed --version >/dev/null 2>/dev/null && echo 1` ]; then - SED_EXTENDED='sed -r' # GNU sed (e.g. on Linux) -else - SED_EXTENDED='sed -E' # BSD sed (e.g. on Mac OS X) -fi - -echo -e "sed regex command: $SED_EXTENDED\n" - -# --------------------------------------------------------------------- - -for testFile in *.test.py; do - if ! run_py_test $( echo $testFile | $SED_EXTENDED 's/^([^.]+)..*$/\1/' ); then - let tot_FAILED++ - fi -done - -if $has_py_coverage; then - echo -e "\n>> Coverage Report:" - cat $py_cover_files | xargs $cover_py_cmd report -fi - -fail=false -if ! test -z "$( cat $failed_tests )"; then - echo -e "\nFailed $( cat $failed_tests | wc -l ) of $( ls -1 *.test.py | wc -l ) extension tests:" - cat $failed_tests | sed 's/^/ - /' - fail=true -fi -echo "" - -rm $py_cover_files $failed_tests - -if [ x$fail == xtrue ]; then - exit 1 -else - exit 0 -fi diff --git a/share/extensions/test/simplestyle.test.py b/share/extensions/test/simplestyle.test.py deleted file mode 100755 index a4746ec09..000000000 --- a/share/extensions/test/simplestyle.test.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -import unittest, sys -sys.path.append('..') # this line allows to import the extension code - -from simplestyle import parseColor, parseStyle - - -class ParseColorTest(unittest.TestCase): - """Test for single transformations""" - def test_namedcolor(self): - "Parse 'red'" - col = parseColor('red') - self.failUnlessEqual((255,0,0),col) - - def test_hexcolor4digit(self): - "Parse '#ff0102'" - col = parseColor('#ff0102') - self.failUnlessEqual((255,1,2),col) - - def test_hexcolor3digit(self): - "Parse '#fff'" - col = parseColor('#fff') - self.failUnlessEqual((255,255,255),col) - - def test_rgbcolorint(self): - "Parse 'rgb(255,255,255)'" - col = parseColor('rgb(255,255,255)') - self.failUnlessEqual((255,255,255),col) - - def test_rgbcolorpercent(self): - "Parse 'rgb(100%,100%,100%)'" - col = parseColor('rgb(100%,100%,100%)') - self.failUnlessEqual((255,255,255),col) - - def test_rgbcolorpercent2(self): - "Parse 'rgb(100%,100%,100%)'" - col = parseColor('rgb(50%,0%,1%)') - self.failUnlessEqual((127,0,2),col) - - def test_rgbcolorpercentdecimal(self): - "Parse 'rgb(66.667%,0%,6.667%)'" - col = parseColor('rgb(66.667%,0%,6.667%)') - self.failUnlessEqual((170, 0, 17),col) - - # TODO: This test appears to be broken. parseColor can - # only return an RGB colour code - #def test_currentColor(self): - # "Parse 'currentColor'" - # col = parseColor('currentColor') - # self.failUnlessEqual(('currentColor'),col) - - def test_spaceinstyle(self): - "Parse 'stop-color: rgb(0,0,0)'" - col = parseStyle('stop-color: rgb(0,0,0)') - self.failUnlessEqual({'stop-color': 'rgb(0,0,0)'},col) - - #def test_unknowncolor(self): - # "Parse 'unknown'" - # col = parseColor('unknown') - # self.failUnlessEqual((0,0,0),col) - # - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/simpletransform.test.py b/share/extensions/test/simpletransform.test.py deleted file mode 100755 index 9e5dbc3b2..000000000 --- a/share/extensions/test/simpletransform.test.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code - -import inkex -from simpletransform import * - -class ComputeBBoxTest(unittest.TestCase): - def setUp(self): - args = [ 'svg/simpletransform.test.svg' ] - self.e = inkex.Effect() - self.e.affect(args, False) - - def test_scaled_object(self): - "Object in the defs with 50,50 scaled by 0.5 when used" - bbox = computeBBox(self.e.document.xpath("//svg:g", namespaces=inkex.NSS)) - text_bbox = "{} {} {} {}".format(bbox[0], bbox[1], bbox[2], bbox[3]) - self.assertEqual(text_bbox, "0.0 25.0 0.0 25.0") - - - -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(ComputeBBoxTest) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/spirograph.test.py b/share/extensions/test/spirograph.test.py deleted file mode 100755 index c7eefa61e..000000000 --- a/share/extensions/test/spirograph.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../spirograph.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from spirograph import * - -class SpirographBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Spirograph() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/straightseg.test.py b/share/extensions/test/straightseg.test.py deleted file mode 100755 index 0a4d07b52..000000000 --- a/share/extensions/test/straightseg.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../straightseg.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from straightseg import * - -class SegmentStraightenerBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = SegmentStraightener() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/summersnight.test.py b/share/extensions/test/summersnight.test.py deleted file mode 100755 index 711bd051d..000000000 --- a/share/extensions/test/summersnight.test.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -''' -Unit test file for ../summersnight.py -Revision history: - * 2012-01-28 (jazzynico): first working version (only checks the extension - with the default parameters). - --- -If you want to help, read the python unittest documentation: -http://docs.python.org/library/unittest.html -''' - -import sys -import unittest - -sys.path.append('..') # this line allows to import the extension code -from summersnight import * - -class EnvelopeBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = ['minimal-blank.svg'] - e = Project() - self.assertRaises(SystemExit, e.affect, args) - -if __name__ == '__main__': - unittest.main() - #suite = unittest.TestLoader().loadTestsFromTestCase(EnvelopeBasicTest) - #unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/share/extensions/test/svg/default-inkscape-SVG.svg b/share/extensions/test/svg/default-inkscape-SVG.svg deleted file mode 100644 index 259e13c0d..000000000 --- a/share/extensions/test/svg/default-inkscape-SVG.svg +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:cc="http://web.resource.org/cc/" - xmlns:dc="http://purl.org/dc/elements/1.1/" - width="793.7007874" - height="1122.519685"> - <defs /> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.35" - inkscape:cx="375" - inkscape:cy="520" - inkscape:document-units="px" - inkscape:current-layer="layer1" /> - <metadata> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" /> -</svg> diff --git a/share/extensions/test/svg/default-plain-SVG.svg b/share/extensions/test/svg/default-plain-SVG.svg deleted file mode 100644 index 9c0884789..000000000 --- a/share/extensions/test/svg/default-plain-SVG.svg +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.1" - width="793.7007874" - height="1122.519685"> - <defs - id="defs4" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="layer1" /> -</svg> diff --git a/share/extensions/test/svg/empty-SVG.svg b/share/extensions/test/svg/empty-SVG.svg deleted file mode 100644 index d6c680b67..000000000 --- a/share/extensions/test/svg/empty-SVG.svg +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - version="1.1" - width="793.7007874" - height="1122.519685"> -</svg> diff --git a/share/extensions/test/svg/multilayered-test.svg b/share/extensions/test/svg/multilayered-test.svg deleted file mode 100644 index c3bf929e9..000000000 --- a/share/extensions/test/svg/multilayered-test.svg +++ /dev/null @@ -1,152 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="210mm" - height="297mm" - id="svg2" - version="1.1" - inkscape:version="0.48+devel " - sodipodi:docname="Nouveau document 1"> - <defs - id="defs4" /> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.35" - inkscape:cx="30.714286" - inkscape:cy="520" - inkscape:document-units="px" - inkscape:current-layer="layer3" - showgrid="false" - inkscape:window-width="1251" - inkscape:window-height="670" - inkscape:window-x="119" - inkscape:window-y="69" - inkscape:window-maximized="0" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:groupmode="layer" - id="layer3" - inkscape:label="Bottom layer"> - <g - id="g3930"> - <path - transform="matrix(-0.97176714,-0.23594199,0.23594199,-0.97176714,541.8979,1030.862)" - inkscape:transform-center-y="21.296232" - inkscape:transform-center-x="0.78818963" - d="M 431.42857,463.79076 283.13917,424.83761 166.98297,524.91176 158.20567,371.84296 27.135259,292.29647 170,236.6479 205.15023,87.411314 302.22279,206.0874 455.01724,193.40062 372.14664,322.39504 z" - inkscape:randomized="0" - inkscape:rounded="0" - inkscape:flatsided="false" - sodipodi:arg2="1.3436561" - sodipodi:arg1="0.71533758" - sodipodi:r2="115.44059" - sodipodi:r1="230.8812" - sodipodi:cy="312.36218" - sodipodi:cx="257.14285" - sodipodi:sides="5" - id="path3902" - style="fill:#ffccaa;fill-opacity:1" - sodipodi:type="star" /> - <text - sodipodi:linespacing="125%" - id="text3926" - y="723.79077" - x="245.71429" - style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" - xml:space="preserve"><tspan - y="723.79077" - x="245.71429" - id="tspan3928" - sodipodi:role="line">Bottom layer</tspan></text> - </g> - </g> - <g - inkscape:groupmode="layer" - id="layer2" - inkscape:label="Middle layer"> - <g - inkscape:groupmode="layer" - id="layer4" - inkscape:label="Middle sublayer"> - <path - style="fill:#ffaaaa;fill-opacity:1" - d="m 522.85714,488.07648 c 0,73.37498 -71.63444,132.85715 -160,132.85715 -88.36556,0 -159.99999,-59.48217 -159.99999,-132.85715 0,-73.37497 71.63443,-132.85714 159.99999,-132.85714 88.36556,0 160,59.48217 160,132.85714 z" - id="path3900" - inkscape:connector-curvature="0" /> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" - id="text3918" - sodipodi:linespacing="125%"><textPath - xlink:href="#path3900" - id="textPath3923"><tspan - id="tspan3920">Middle sublayer</tspan></textPath></text> - </g> - <g - id="g3913" - transform="translate(8.5714286,-94.285711)"> - <rect - y="406.64789" - x="162.85715" - height="134.28572" - width="385.71429" - id="rect3898" - style="fill:#cccccc;fill-opacity:1" /> - <text - sodipodi:linespacing="125%" - id="text3909" - y="520.93365" - x="294.28571" - style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" - xml:space="preserve"><tspan - y="520.93365" - x="294.28571" - id="tspan3911" - sodipodi:role="line">Middle layer</tspan></text> - </g> - </g> - <g - inkscape:label="Top Layer" - inkscape:groupmode="layer" - id="layer1" - style="display:inline"> - <text - xml:space="preserve" - style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans" - id="text3894" - sodipodi:linespacing="125%"><textPath - xlink:href="#path3904" - id="textPath3906"><tspan - id="tspan3896">Top layer</tspan></textPath></text> - <path - style="fill:#00d4aa;fill-opacity:1" - id="path3904" - d="m 199.54403,352.9691 c 33.89855,-23.39174 72.10651,-36.95679 109.79252,-52.48463 7.71344,-3.19326 15.44578,-6.34124 23.14032,-9.57978 26.03103,-10.95613 51.7881,-22.59387 76.79106,-35.76157 42.32507,-22.29031 32.37854,-17.45018 21.71695,-12.37413 27.69959,-16.89942 54.76258,-34.80763 82.06841,-52.32954 3.94676,-2.5326 7.78542,-5.23846 11.81547,-7.63629 13.93107,-8.28881 28.03813,-16.27818 42.05719,-24.41727 1.82085,-0.65301 3.535,-1.79625 5.46253,-1.95903 1.14748,-0.0969 2.55329,0.29335 3.23024,1.22493 4.4402,6.11031 -2.74745,15.55901 -5.48451,20.72818 -5.75765,10.57294 -11.80107,21.00672 -18.37568,31.09425 -8.69682,12.13204 -17.21613,24.35107 -25.30545,36.8994 -8.76999,14.06322 -13.80724,29.8609 -17.16277,45.97506 -1.61982,9.03135 -2.30641,16.44531 6.23493,21.70829 3.31001,1.71191 6.61295,2.19795 10.26307,2.25814 0,0 -34.1559,24.2492 -34.1559,24.2492 l 0,0 c -4.04274,-0.78094 -7.88137,-1.74859 -11.38493,-4.05868 -9.57886,-7.50134 -10.04511,-14.7248 -7.95368,-26.29078 3.70976,-16.48328 8.59159,-32.8557 17.13895,-47.54924 7.808,-12.43792 15.71401,-24.76749 24.43097,-36.58289 6.64463,-10.0123 12.98801,-20.22738 18.69995,-30.80719 1.06673,-2.02099 5.47855,-11.97387 6.83302,-13.43922 0.3422,-0.37021 1.06394,-0.32013 1.51003,-0.0852 0.35221,0.18545 -0.77587,0.17836 -1.1638,0.26755 -1.3924,0.57649 -2.7848,1.15299 -4.1772,1.72949 8.53309,-5.01782 16.92726,-10.27974 25.59928,-15.05345 4.46703,-2.45898 -8.64504,5.40995 -12.97447,8.10383 -28.33878,17.63307 -56.24248,35.94219 -84.66825,53.43629 -22.66355,13.24936 -55.91511,33.356 -81.64049,46.80647 -32.95242,17.22913 -67.12661,31.94029 -101.42871,46.2266 -18.19015,7.69388 -36.62175,14.9775 -54.55262,23.27042 -3.77844,1.7475 -7.50549,3.60582 -11.21421,5.49679 -2.53121,1.2906 -9.9408,5.50416 -7.50216,4.04617 10.489,-6.27105 21.10584,-12.32577 31.65876,-18.48866 0,0 -39.29882,15.37653 -39.29882,15.37653 z" - inkscape:connector-curvature="0" /> - </g> -</svg> diff --git a/share/extensions/test/svg/simpletransform.test.svg b/share/extensions/test/svg/simpletransform.test.svg deleted file mode 100644 index 62876eea7..000000000 --- a/share/extensions/test/svg/simpletransform.test.svg +++ /dev/null @@ -1,8 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100"> - <g> - <defs> - <rect width="50" height="50" id="rect"/> - </defs> - <use xlink:href="#rect" transform="scale(.5)"/> - </g> -</svg>
\ No newline at end of file diff --git a/share/extensions/test/svg/single_box.svg b/share/extensions/test/svg/single_box.svg deleted file mode 100644 index 094233d15..000000000 --- a/share/extensions/test/svg/single_box.svg +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="744.09448819" - height="1052.3622047" - id="svg2" - version="1.1" - inkscape:version="0.48.3.1 r9886" - sodipodi:docname="New document 1"> - <defs - id="defs4" /> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.35" - inkscape:cx="375" - inkscape:cy="514.28571" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="479" - inkscape:window-height="379" - inkscape:window-x="1319" - inkscape:window-y="75" - inkscape:window-maximized="0" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1"> - <rect - style="opacity:0.5;fill:#6900ff;fill-opacity:0.36000001;stroke:#cae8ef;stroke-width:7.19999981;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - id="rect3006" - width="237.14285" - height="305.71429" - x="285.71429" - y="406.64789" /> - </g> -</svg> diff --git a/share/extensions/test/svg_and_media_zip_output.test.py b/share/extensions/test/svg_and_media_zip_output.test.py deleted file mode 100755 index 7f68dd6ef..000000000 --- a/share/extensions/test/svg_and_media_zip_output.test.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../svg_and_media_zip_output.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from svg_and_media_zip_output import * - -class SVG_and_Media_ZIP_Output_BasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = CompressedMediaOutput() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - #e.clear_tmp() - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/svgcalendar.test.py b/share/extensions/test/svgcalendar.test.py deleted file mode 100755 index 7b93c9b38..000000000 --- a/share/extensions/test/svgcalendar.test.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest, calendar -from svgcalendar import * - -class CalendarArguments(unittest.TestCase): - - #def setUp(self): - - def test_default_names_list(self): - args = [ 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.month_names[0], 'January' ) - self.assertEqual( e.options.month_names[11], 'December' ) - self.assertEqual( e.options.day_names[0], 'Sun' ) - self.assertEqual( e.options.day_names[6], 'Sat' ) - - def test_modifyed_names_list(self): - args = [ - '--month-names=JAN FEV MAR ABR MAI JUN JUL AGO SET OUT NOV DEZ', - '--day-names=DOM SEG TER QUA QUI SEX SAB', - 'minimal-blank.svg' - ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.month_names[0], 'JAN' ) - self.assertEqual( e.options.month_names[11], 'DEZ' ) - self.assertEqual( e.options.day_names[0], 'DOM' ) - self.assertEqual( e.options.day_names[6], 'SAB' ) - - def test_starting_or_ending_spaces_must_not_affect_names_list(self): - args = [ - '--month-names= JAN FEV MAR ABR MAI JUN JUL AGO SET OUT NOV DEZ ', - '--day-names= DOM SEG TER QUA QUI SEX SAB ', - 'minimal-blank.svg' - ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.month_names[0], 'JAN' ) - self.assertEqual( e.options.month_names[11], 'DEZ' ) - self.assertEqual( e.options.day_names[0], 'DOM' ) - self.assertEqual( e.options.day_names[6], 'SAB' ) - - def test_inner_extra_spaces_must_not_affect_names_list(self): - args = [ - '--month-names=JAN FEV MAR ABR MAI JUN JUL AGO SET OUT NOV DEZ', - '--day-names=DOM SEG TER QUA QUI SEX SAB', - 'minimal-blank.svg' - ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.month_names[0], 'JAN' ) - self.assertEqual( e.options.month_names[2], 'MAR' ) - self.assertEqual( e.options.month_names[11], 'DEZ' ) - self.assertEqual( e.options.day_names[0], 'DOM' ) - self.assertEqual( e.options.day_names[2], 'TER' ) - self.assertEqual( e.options.day_names[6], 'SAB' ) - - def test_default_year_must_be_the_current_year(self): - args = [ 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.year, datetime.today().year ) - - def test_option_year_equal_0_is_converted_to_current_year(self): - args = [ '--year=0', 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.year, datetime.today().year ) - - def test_option_year_2000_configuration(self): - args = [ '--year=2000', 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( e.options.year, 2000 ) - - def test_default_week_start_day(self): - args = [ 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( calendar.firstweekday(), 6 ) - - def test_configuring_week_start_day(self): - args = [ '--start-day=sun', 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( calendar.firstweekday(), 6 ) - args = [ '--start-day=mon', 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertEqual( calendar.firstweekday(), 0 ) - -class CalendarMethods(unittest.TestCase): - - def test_recognize_a_weekend(self): - args = [ '--start-day=sun', '--weekend=sat+sun', 'minimal-blank.svg' ] - e = SVGCalendar() - e.affect( args, False ) - self.assertTrue( e.is_weekend(0), 'Sunday is weekend in this configuration' ) - self.assertTrue( e.is_weekend(6), 'Saturday is weekend in this configuration' ) - self.assertFalse( e.is_weekend(1), 'Monday is NOT weekend' ) - -if __name__ == '__main__': - unittest.main() - diff --git a/share/extensions/test/test_template.py.txt b/share/extensions/test/test_template.py.txt deleted file mode 100755 index 9a570cd6a..000000000 --- a/share/extensions/test/test_template.py.txt +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for %FILE% -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from %MODULE% import * - -class %CLASS%BasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = %CLASS%() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/triangle.test.py b/share/extensions/test/triangle.test.py deleted file mode 100755 index 96743f7e2..000000000 --- a/share/extensions/test/triangle.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../triangle.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from triangle import * - -class Grid_PolarBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Grid_Polar() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/test/whirl.test.py b/share/extensions/test/whirl.test.py deleted file mode 100755 index c08ea01c3..000000000 --- a/share/extensions/test/whirl.test.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -# This is only the automatic generated test file for ../whirl.py -# This must be filled with real tests and this commentary -# must be cleared. -# If you want to help, read the python unittest documentation: -# http://docs.python.org/library/unittest.html - -import sys -sys.path.append('..') # this line allows to import the extension code - -import unittest -from whirl import * - -class WhirlBasicTest(unittest.TestCase): - - #def setUp(self): - - def test_run_without_parameters(self): - args = [ 'minimal-blank.svg' ] - e = Whirl() - e.affect( args, False ) - #self.assertEqual( e.something, 'some value', 'A commentary about that.' ) - -if __name__ == '__main__': - unittest.main() diff --git a/share/extensions/text_braille.inx b/share/extensions/text_braille.inx deleted file mode 100644 index ec9bc5b47..000000000 --- a/share/extensions/text_braille.inx +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Convert to Braille</_name> - <id>org.inkscape.text.braille</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_braille.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_braille.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_braille.py b/share/extensions/text_braille.py deleted file mode 100755 index ba2e3d81b..000000000 --- a/share/extensions/text_braille.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import chardataeffect, inkex, string - -convert_table = {\ -'a': unicode("⠁", "utf-8"),\ -'b': unicode("⠃", "utf-8"),\ -'c': unicode("⠉", "utf-8"),\ -'d': unicode("⠙", "utf-8"),\ -'e': unicode("⠑", "utf-8"),\ -'f': unicode("⠋", "utf-8"),\ -'g': unicode("⠛", "utf-8"),\ -'h': unicode("⠓", "utf-8"),\ -'i': unicode("⠊", "utf-8"),\ -'j': unicode("⠚", "utf-8"),\ -'k': unicode("⠅", "utf-8"),\ -'l': unicode("⠇", "utf-8"),\ -'m': unicode("⠍", "utf-8"),\ -'n': unicode("⠝", "utf-8"),\ -'o': unicode("⠕", "utf-8"),\ -'p': unicode("⠏", "utf-8"),\ -'q': unicode("⠟", "utf-8"),\ -'r': unicode("⠗", "utf-8"),\ -'s': unicode("⠎", "utf-8"),\ -'t': unicode("⠞", "utf-8"),\ -'u': unicode("⠥", "utf-8"),\ -'v': unicode("⠧", "utf-8"),\ -'w': unicode("⠺", "utf-8"),\ -'x': unicode("⠭", "utf-8"),\ -'y': unicode("⠽", "utf-8"),\ -'z': unicode("⠵", "utf-8"),\ -} - -class C(chardataeffect.CharDataEffect): - - def process_chardata(self,text, line, par): - r = "" - for c in text: - if convert_table.has_key(c.lower()): - r = r + convert_table[c.lower()] - else: - r = r + c - return r - -c = C() -c.affect() diff --git a/share/extensions/text_extract.inx b/share/extensions/text_extract.inx deleted file mode 100644 index bf3a66e60..000000000 --- a/share/extensions/text_extract.inx +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Extract</_name> - <id>org.inkscape.text.extract</id> - <dependency type="executable" location="extensions">text_extract.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="direction" type="enum" _gui-text="Text direction:"> - <_item value="lr">Left to right</_item> - <_item value="bt">Bottom to top</_item> - <_item value="rl">Right to left</_item> - <_item value="tb">Top to bottom</_item> - </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="enum" _gui-text="Vertical point:"> - <_item value="t">Top</_item> - <_item value="m">Middle</_item> - <_item value="b">Bottom</_item> - </param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_extract.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_extract.py b/share/extensions/text_extract.py deleted file mode 100755 index b6b575dfc..000000000 --- a/share/extensions/text_extract.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -""" -Copyright (C) 2011 Nicolas Dufour (jazzynico) -Direction code from the Restack extension, by Rob Antonishen - -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. - -""" -# standard library -import chardataeffect -from copy import deepcopy -import csv -import math -import os -import string -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False - -# local library -import inkex - -class Extract(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-d", "--direction", - action="store", type="string", - dest="direction", default="tb", - help="direction to extract text") - self.OptionParser.add_option("-x", "--xanchor", - action="store", type="string", - dest="xanchor", default="m", - help="horizontal point to compare") - self.OptionParser.add_option("-y", "--yanchor", - action="store", type="string", - dest="yanchor", default="m", - help="vertical point to compare") - - def effect(self): - if len(self.selected)==0: - for node in self.document.xpath('//svg:text | //svg:flowRoot', namespaces=inkex.NSS): - self.selected[node.get('id')] = node - - if len( self.selected ) > 0: - objlist = [] - svg = self.document.getroot() - parentnode = self.current_layer - file = self.args[ -1 ] - - # get all bounding boxes in file by calling inkscape again with the --query-all command line option - # it returns a comma separated list structured id,x,y,w,h - if bsubprocess: - p = Popen('inkscape --query-all "%s"' % (file), shell=True, stdout=PIPE, stderr=PIPE) - err = p.stderr - f = p.communicate()[0] - try: - reader=csv.CSVParser().parse_string(f) #there was a module cvs.py in earlier inkscape that behaved differently - except: - reader=csv.reader(f.split( os.linesep )) - err.close() - else: - _,f,err = os.popen3('inkscape --query-all "%s"' % ( file ) ) - reader=csv.reader( f ) - err.close() - - #build a dictionary with id as the key - dimen = dict() - for line in reader: - if len(line) > 0: - dimen[line[0]] = map( float, line[1:]) - - if not bsubprocess: #close file if opened using os.popen3 - f.close - - #find the center of all selected objects **Not the average! - x,y,w,h = dimen[self.selected.keys()[0]] - minx = x - miny = y - maxx = x + w - maxy = y + h - - for id, node in self.selected.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - if x < minx: - minx = x - if (x + w) > maxx: - maxx = x + w - if y < miny: - miny = y - if (y + h) > maxy: - maxy = y + h - - midx = (minx + maxx) / 2 - midy = (miny + maxy) / 2 - - #calculate distances for each selected object - for id, node in self.selected.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - - # calc the comparison coords - if self.options.xanchor == "l": - cx = x - elif self.options.xanchor == "r": - cx = x + w - else: # middle - cx = x + w / 2 - - if self.options.yanchor == "t": - cy = y - elif self.options.yanchor == "b": - cy = y + h - else: # middle - cy = y + h / 2 - - #direction chosen - if self.options.direction == "tb": - objlist.append([cy,id]) - elif self.options.direction == "bt": - objlist.append([-cy,id]) - elif self.options.direction == "lr": - objlist.append([cx,id]) - elif self.options.direction == "rl": - objlist.append([-cx,id]) - - objlist.sort() - #move them to the top of the object stack in this order. - for item in objlist: - self.recurse(deepcopy(self.selected[item[1]])) - - def recurse(self, node): - istext = (node.tag == '{http://www.w3.org/2000/svg}flowPara' or node.tag == '{http://www.w3.org/2000/svg}flowDiv' or node.tag == '{http://www.w3.org/2000/svg}text') - if node.text != None or node.tail != None: - for child in node: - if child.get('{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}role'): - child.tail = "\n" - inkex.errormsg(inkex.etree.tostring(node, method='text').strip()) - else: - for child in node: - self.recurse(child) - - -if __name__ == '__main__': - e = Extract() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/text_flipcase.inx b/share/extensions/text_flipcase.inx deleted file mode 100644 index 3eae4a804..000000000 --- a/share/extensions/text_flipcase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>fLIP cASE</_name> - <id>org.inkscape.text.flipcase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_flipcase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_flipcase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_flipcase.py b/share/extensions/text_flipcase.py deleted file mode 100755 index 6ddb9d5ea..000000000 --- a/share/extensions/text_flipcase.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -class C(chardataeffect.CharDataEffect): - - def process_chardata(self,text, line, par): - r = "" - for i in range(len(text)): - c = text[i] - if c.islower(): - r = r + c.upper() - elif c.isupper(): - r = r + c.lower() - else: - r = r + c - - return r - -c = C() -c.affect() diff --git a/share/extensions/text_lowercase.inx b/share/extensions/text_lowercase.inx deleted file mode 100644 index d97313db7..000000000 --- a/share/extensions/text_lowercase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>lowercase</_name> - <id>org.inkscape.text.lowercase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_lowercase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_lowercase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_lowercase.py b/share/extensions/text_lowercase.py deleted file mode 100755 index c5e9e6279..000000000 --- a/share/extensions/text_lowercase.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -class C(chardataeffect.CharDataEffect): - def process_chardata(self,text, line=False, par=False): - return text.lower() - -c = C() -c.affect() diff --git a/share/extensions/text_merge.inx b/share/extensions/text_merge.inx deleted file mode 100644 index fbbe7e857..000000000 --- a/share/extensions/text_merge.inx +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Merge</_name> - <id>org.inkscape.text.merge</id> - <dependency type="executable" location="extensions">text_merge.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="direction" type="enum" _gui-text="Text direction:"> - <_item value="lr">Left to right</_item> - <_item value="bt">Bottom to top</_item> - <_item value="rl">Right to left</_item> - <_item value="tb">Top to bottom</_item> - </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="enum" _gui-text="Vertical point:"> - <_item value="t">Top</_item> - <_item value="m">Middle</_item> - <_item value="b">Bottom</_item> - </param> -<!-- <param name="flowtext" type="boolean" _gui-text="Flow text">false</param> --> - <param name="keepstyle" type="boolean" _gui-text="Keep style">true</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_merge.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_merge.py b/share/extensions/text_merge.py deleted file mode 100755 index a3ba29022..000000000 --- a/share/extensions/text_merge.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -""" -Copyright (C) 2013 Nicolas Dufour (jazzynico) -Direction code from the Restack extension, by Rob Antonishen - -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. - -""" -# standard library -import chardataeffect -import copy -import csv -import math -import os -import string -try: - from subprocess import Popen, PIPE - bsubprocess = True -except: - bsubprocess = False -# local library -import inkex - - -class Merge(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-d", "--direction", - action="store", type="string", - dest="direction", default="tb", - help="direction to merge text") - self.OptionParser.add_option("-x", "--xanchor", - action="store", type="string", - dest="xanchor", default="m", - help="horizontal point to compare") - self.OptionParser.add_option("-y", "--yanchor", - action="store", type="string", - dest="yanchor", default="m", - help="vertical point to compare") - self.OptionParser.add_option("-t", "--flowtext", - action="store", type="inkbool", - dest="flowtext", default=False, - help="use a flow text structure instead of a normal text element") - self.OptionParser.add_option("-k", "--keepstyle", - action="store", type="inkbool", - dest="keepstyle", default=False, - help="keep format") - - def effect(self): - if len(self.selected)==0: - for node in self.document.xpath('//svg:text | //svg:flowRoot', namespaces=inkex.NSS): - self.selected[node.get('id')] = node - - if len( self.selected ) > 0: - objlist = [] - svg = self.document.getroot() - parentnode = self.current_layer - file = self.args[ -1 ] - - # get all bounding boxes in file by calling inkscape again with the --query-all command line option - # it returns a comma separated list structured id,x,y,w,h - if bsubprocess: - p = Popen('inkscape --query-all "%s"' % (file), shell=True, stdout=PIPE, stderr=PIPE) - err = p.stderr - f = p.communicate()[0] - try: - reader=csv.CSVParser().parse_string(f) #there was a module cvs.py in earlier inkscape that behaved differently - except: - reader=csv.reader(f.split( os.linesep )) - err.close() - else: - _,f,err = os.popen3('inkscape --query-all "%s"' % ( file ) ) - reader=csv.reader( f ) - err.close() - - #build a dictionary with id as the key - dimen = dict() - for line in reader: - if len(line) > 0: - dimen[line[0]] = map( float, line[1:]) - - if not bsubprocess: #close file if opened using os.popen3 - f.close - - #find the center of all selected objects **Not the average! - x,y,w,h = dimen[self.selected.keys()[0]] - minx = x - miny = y - maxx = x + w - maxy = y + h - - for id, node in self.selected.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - if x < minx: - minx = x - if (x + w) > maxx: - maxx = x + w - if y < miny: - miny = y - if (y + h) > maxy: - maxy = y + h - - midx = (minx + maxx) / 2 - midy = (miny + maxy) / 2 - - #calculate distances for each selected object - for id, node in self.selected.iteritems(): - # get the bounding box - x,y,w,h = dimen[id] - - # calc the comparison coords - if self.options.xanchor == "l": - cx = x - elif self.options.xanchor == "r": - cx = x + w - else: # middle - cx = x + w / 2 - - if self.options.yanchor == "t": - cy = y - elif self.options.yanchor == "b": - cy = y + h - else: # middle - cy = y + h / 2 - - #direction chosen - if self.options.direction == "tb": - objlist.append([cy,id]) - elif self.options.direction == "bt": - objlist.append([-cy,id]) - elif self.options.direction == "lr": - objlist.append([cx,id]) - elif self.options.direction == "rl": - objlist.append([-cx,id]) - - objlist.sort() - #move them to the top of the object stack in this order. - - if self.options.flowtext: - self.text_element = "flowRoot" - self.text_span = "flowPara" - else: - self.text_element = "text" - self.text_span = "tspan" - - self.textRoot=inkex.etree.SubElement(parentnode,inkex.addNS(self.text_element,'svg'),{inkex.addNS('space','xml'):'preserve'}) - self.textRoot.set(inkex.addNS('style', ''), 'font-size:20px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;') - - for item in objlist: - self.recurse(self.selected[item[1]], self.textRoot) - - if self.options.flowtext: - self.region=inkex.etree.SubElement(self.textRoot,inkex.addNS('flowRegion','svg'),{inkex.addNS('space','xml'):'preserve'}) - self.rect=inkex.etree.SubElement(self.region,inkex.addNS('rect','svg'),{inkex.addNS('space','xml'):'preserve'}) - self.rect.set(inkex.addNS('height', ''), '200') - self.rect.set(inkex.addNS('width', ''), '200') - - def recurse(self, node, span): - #istext = (node.tag == '{http://www.w3.org/2000/svg}flowPara' or node.tag == '{http://www.w3.org/2000/svg}flowDiv' or node.tag == '{http://www.w3.org/2000/svg}tspan') - if node.tag != '{http://www.w3.org/2000/svg}flowRegion': - - newspan=inkex.etree.SubElement(span,inkex.addNS(self.text_span,'svg'),{inkex.addNS('space','xml'):'preserve'}) - - if node.get('{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}role'): - newspan.set(inkex.addNS('role', 'sodipodi'), node.get('{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}role')) - if (node.tag == '{http://www.w3.org/2000/svg}text' or node.tag == '{http://www.w3.org/2000/svg}flowPara'): - newspan.set(inkex.addNS('role', 'sodipodi'), 'line') - - if self.options.keepstyle: - if node.get('style'): - newspan.set(inkex.addNS('style', ''), node.get('style')) - - if node.text != None: - newspan.text = node.text - for child in node: - self.recurse(child, newspan) - if (node.tail and node.tag != '{http://www.w3.org/2000/svg}text'): - newspan.tail = node.tail - - -if __name__ == '__main__': - e = Merge() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/text_randomcase.inx b/share/extensions/text_randomcase.inx deleted file mode 100644 index f6fd23ba6..000000000 --- a/share/extensions/text_randomcase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>rANdOm CasE</_name> - <id>org.inkscape.text.randomcase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_randomcase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_randomcase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_randomcase.py b/share/extensions/text_randomcase.py deleted file mode 100755 index 74c061a7c..000000000 --- a/share/extensions/text_randomcase.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -import random - -class C(chardataeffect.CharDataEffect): - - def process_chardata(self,text, line, par): - r = "" - a = 1 - for i in range(len(text)): - c = text[i] - # bias the randomness towards inversion of the previous case: - if a > 0: - a = random.choice([-2,-1,1]) - else: - a = random.choice([-1,1,2]) - if a > 0 and c.isalpha(): - r = r + c.upper() - elif a < 0 and c.isalpha(): - r = r + c.lower() - else: - r = r + c - - return r - -c = C() -c.affect() diff --git a/share/extensions/text_sentencecase.inx b/share/extensions/text_sentencecase.inx deleted file mode 100644 index 8252325ca..000000000 --- a/share/extensions/text_sentencecase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Sentence case</_name> - <id>org.inkscape.text.sentencecase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_sentencecase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_sentencecase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_sentencecase.py b/share/extensions/text_sentencecase.py deleted file mode 100755 index e699a7efa..000000000 --- a/share/extensions/text_sentencecase.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -class C(chardataeffect.CharDataEffect): - - sentence_start = True - was_punctuation = False - - def process_chardata(self, text, line, par): - r = "" - #inkex.debug(text+str(line)+str(par)) - for c in text: - if c == '.' or c == '!' or c == '?': - self.was_punctuation = True - elif ((c.isspace() or line == True) and self.was_punctuation) or par == True: - self.sentence_start = True - self.was_punctuation = False - elif c == '"' or c == ')': - pass - else: - self.was_punctuation = False - - if not c.isspace(): - line = False - par = False - - if self.sentence_start and c.isalpha(): - r = r + c.upper() - self.sentence_start = False - elif not self.sentence_start and c.isalpha(): - r = r + c.lower() - else: - r = r + c - - return r - -c = C() -c.affect() diff --git a/share/extensions/text_titlecase.inx b/share/extensions/text_titlecase.inx deleted file mode 100644 index e665f8a40..000000000 --- a/share/extensions/text_titlecase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Title Case</_name> - <id>org.inkscape.text.titlecase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_titlecase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_titlecase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_titlecase.py b/share/extensions/text_titlecase.py deleted file mode 100755 index 533ab1a39..000000000 --- a/share/extensions/text_titlecase.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -class C(chardataeffect.CharDataEffect): - - word_ended = True - - def process_chardata(self, text, line, par): - r = "" - for i in range(len(text)): - c = text[i] - if c.isspace() or line == True or par == True: - self.word_ended = True - if not c.isspace(): - line = False - par = False - - if self.word_ended and c.isalpha(): - r = r + c.upper() - self.word_ended = False - elif c.isalpha(): - r = r + c.lower() - else: - r = r + c - - return r - -c = C() -c.affect() diff --git a/share/extensions/text_uppercase.inx b/share/extensions/text_uppercase.inx deleted file mode 100644 index 0de16238e..000000000 --- a/share/extensions/text_uppercase.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>UPPERCASE</_name> - <id>org.inkscape.text.uppercase</id> - <dependency type="executable" location="extensions">chardataeffect.py</dependency> - <dependency type="executable" location="extensions">text_uppercase.py</dependency> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Text"> - <submenu _name="Change Case" /> - </submenu> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">text_uppercase.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/text_uppercase.py b/share/extensions/text_uppercase.py deleted file mode 100755 index 772c1fd88..000000000 --- a/share/extensions/text_uppercase.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import chardataeffect, inkex, string - -class C(chardataeffect.CharDataEffect): - def process_chardata(self,text, line=False, par=False): - return text.upper() - -c = C() -c.affect() diff --git a/share/extensions/triangle.inx b/share/extensions/triangle.inx deleted file mode 100644 index 0c66ed907..000000000 --- a/share/extensions/triangle.inx +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Triangle</_name> - <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="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> - </effect> - <script> - <command reldir="extensions" interpreter="python">triangle.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/triangle.py b/share/extensions/triangle.py deleted file mode 100755 index 4d8ff035a..000000000 --- a/share/extensions/triangle.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2007 John Beard john.j.beard@gmail.com - -##This extension allows you to draw a triangle given certain information -## about side length or angles. - -##Measurements of the triangle - - C(x_c,y_c) - /`__ - / a_c``--__ - / ``--__ s_a - s_b / ``--__ - /a_a a_b`--__ - /--------------------------------``B(x_b, y_b) - A(x_a,y_a) s_b - - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex -import simplestyle, sys -from simpletransform import computePointInNode -from math import * - -def draw_SVG_tri( (x1, y1), (x2, y2), (x3, y3), (ox,oy), width, name, parent): - style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' } - tri_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('label','inkscape'):name, - 'd':'M '+str(x1+ox)+','+str(y1+oy)+ - ' L '+str(x2+ox)+','+str(y2+oy)+ - ' L '+str(x3+ox)+','+str(y3+oy)+ - ' L '+str(x1+ox)+','+str(y1+oy)+' z'} - inkex.etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs ) - -def angle_from_3_sides(a, b, c): #return the angle opposite side c - cosx = (a*a + b*b - c*c)/(2*a*b) #use the cosine rule - return acos(cosx) - -def third_side_from_enclosed_angle(s_a,s_b,a_c): #return the side opposite a_c - c_squared = s_a*s_a + s_b*s_b -2*s_a*s_b*cos(a_c) - if c_squared > 0: - return sqrt(c_squared) - else: - return 0 #means we have an invalid or degenerate triangle (zero is caught at the drawing stage) - -def pt_on_circ(radius, angle): #return the x,y coordinate of the polar coordinate - x = radius * cos(angle) - y = radius * sin(angle) - return [x, y] - -def v_add( (x1,y1),(x2,y2) ):#add an offset to coordinates - return [x1+x2, y1+y2] - -def is_valid_tri_from_sides(a,b,c):#check whether triangle with sides a,b,c is valid - return (a+b)>c and (a+c)>b and (b+c)>a and a > 0 and b> 0 and c>0#two sides must always be greater than the third - #no zero-length sides, no degenerate case - -def draw_tri_from_3_sides(s_a, s_b, s_c, offset, width, parent): #draw a triangle from three sides (with a given offset - if is_valid_tri_from_sides(s_a,s_b,s_c): - a_b = angle_from_3_sides(s_a, s_c, s_b) - - a = (0,0) #a is the origin - b = v_add(a, (s_c, 0)) #point B is horizontal from the origin - c = v_add(b, pt_on_circ(s_a, pi-a_b) ) #get point c - c[1] = -c[1] - - offx = max(b[0],c[0])/2 #b or c could be the furthest right - offy = c[1]/2 #c is the highest point - offset = ( offset[0]-offx , offset[1]-offy ) #add the centre of the triangle to the offset - - draw_SVG_tri(a, b, c , offset, width, 'Triangle', parent) - else: - sys.stderr.write('Error:Invalid Triangle Specifications.\n') - -class Grid_Polar(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--s_a", - action="store", type="float", - dest="s_a", default=100.0, - help="Side Length a") - self.OptionParser.add_option("--s_b", - action="store", type="float", - dest="s_b", default=100.0, - help="Side Length b") - self.OptionParser.add_option("--s_c", - action="store", type="float", - dest="s_c", default=100.0, - help="Side Length c") - self.OptionParser.add_option("--a_a", - action="store", type="float", - dest="a_a", default=60.0, - help="Angle a") - self.OptionParser.add_option("--a_b", - action="store", type="float", - dest="a_b", default=30.0, - help="Angle b") - self.OptionParser.add_option("--a_c", - action="store", type="float", - dest="a_c", default=90.0, - help="Angle c") - self.OptionParser.add_option("--mode", - action="store", type="string", - dest="mode", default='3_sides', - help="Side Length c") - - def effect(self): - - tri = self.current_layer - offset = computePointInNode(list(self.view_center), self.current_layer) #the offset require to centre the triangle - self.options.s_a = self.unittouu(str(self.options.s_a) + 'px') - self.options.s_b = self.unittouu(str(self.options.s_b) + 'px') - self.options.s_c = self.unittouu(str(self.options.s_c) + 'px') - stroke_width = self.unittouu('2px') - - if self.options.mode == '3_sides': - s_a = self.options.s_a - s_b = self.options.s_b - s_c = self.options.s_c - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - - elif self.options.mode == 's_ab_a_c': - s_a = self.options.s_a - s_b = self.options.s_b - a_c = self.options.a_c*pi/180 #in rad - - s_c = third_side_from_enclosed_angle(s_a,s_b,a_c) - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - - elif self.options.mode == 's_ab_a_a': - s_a = self.options.s_a - s_b = self.options.s_b - a_a = self.options.a_a*pi/180 #in rad - - if (a_a < pi/2.0) and (s_a < s_b) and (s_a > s_b*sin(a_a) ): #this is an ambiguous case - ambiguous=True#we will give both answers - else: - ambiguous=False - - sin_a_b = s_b*sin(a_a)/s_a - - if (sin_a_b <= 1) and (sin_a_b >= -1):#check the solution is possible - a_b = asin(sin_a_b) #acute solution - a_c = pi - a_a - a_b - error=False - else: - sys.stderr.write('Error:Invalid Triangle Specifications.\n')#signal an error - error=True - - if not(error) and (a_b < pi) and (a_c < pi): #check that the solution is valid, if so draw acute solution - s_c = third_side_from_enclosed_angle(s_a,s_b,a_c) - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - - if not(error) and ((a_b > pi) or (a_c > pi) or ambiguous):#we want the obtuse solution - a_b = pi - a_b - a_c = pi - a_a - a_b - s_c = third_side_from_enclosed_angle(s_a,s_b,a_c) - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - - elif self.options.mode == 's_a_a_ab': - s_a = self.options.s_a - a_a = self.options.a_a*pi/180 #in rad - a_b = self.options.a_b*pi/180 #in rad - - a_c = pi - a_a - a_b - s_b = s_a*sin(a_b)/sin(a_a) - s_c = s_a*sin(a_c)/sin(a_a) - - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - - elif self.options.mode == 's_c_a_ab': - s_c = self.options.s_c - a_a = self.options.a_a*pi/180 #in rad - a_b = self.options.a_b*pi/180 #in rad - - a_c = pi - a_a - a_b - s_a = s_c*sin(a_a)/sin(a_c) - s_b = s_c*sin(a_b)/sin(a_c) - - draw_tri_from_3_sides(s_a, s_b, s_c, offset, stroke_width, tri) - -if __name__ == '__main__': - e = Grid_Polar() - e.affect() - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/ungroup_deep.inx b/share/extensions/ungroup_deep.inx deleted file mode 100644 index f0b6339e8..000000000 --- a/share/extensions/ungroup_deep.inx +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Deep Ungroup</_name> - <id>mcepl.ungroup_deep</id> - <dependency type="executable" location="extensions">ungroup_deep.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <_param name="title" type="description">Ungroup all groups in the selected object.</_param> - <param name="startdepth" type="int" min="0" max="65535" _gui-text="Starting Depth">0</param> - <param name="maxdepth" type="int" min="0" max="65535" _gui-text="Stopping Depth (from top)">65535</param> - <param name="keepdepth" type="int" min="0" max="65535" _gui-text="Depth to Keep (from bottom)">0</param> - <effect needs-live-preview="false"> - <effects-menu > - <submenu _name="Arrange" /> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">ungroup_deep.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/ungroup_deep.py b/share/extensions/ungroup_deep.py deleted file mode 100755 index 359232007..000000000 --- a/share/extensions/ungroup_deep.py +++ /dev/null @@ -1,281 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -see #inkscape on Freenode and -https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 -for an example how to do the transform of parent to children. -""" - -__version__ = "0.2" # Works but in terms of maturity, still unsure - -from inkex import addNS -import logging -import simplestyle -import simpletransform -logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', - level=logging.INFO) - -try: - import inkex -except ImportError: - raise ImportError("""No module named inkex in {0}.""".format(__file__)) - -try: - from numpy import matrix -except: - raise ImportError("""Cannot find numpy.matrix in {0}.""".format(__file__)) - -SVG_NS = "http://www.w3.org/2000/svg" -INKSCAPE_NS = "http://www.inkscape.org/namespaces/inkscape" - - -class Ungroup(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-s", "--startdepth", - action="store", type="int", - dest="startdepth", default=0, - help="starting depth for ungrouping") - self.OptionParser.add_option("-m", "--maxdepth", - action="store", type="int", - dest="maxdepth", default=65535, - help="maximum ungrouping depth") - self.OptionParser.add_option("-k", "--keepdepth", - action="store", type="int", - dest="keepdepth", default=0, - help="levels of ungrouping to " + - "leave untouched") - - def _get_dimension(s="1024"): - """Convert an SVG length string from arbitrary units to pixels""" - if s == "": - return 0 - try: - last = int(s[-1]) - except: - last = None - - if type(last) == int: - return float(s) - elif s[-1] == "%": - return 1024 - elif s[-2:] == "px": - return float(s[:-2]) - elif s[-2:] == "pt": - return float(s[:-2]) * 1.33 - elif s[-2:] == "em": - return float(s[:-2]) * 16 - elif s[-2:] == "mm": - return float(s[:-2]) * 3.779 - elif s[-2:] == "pc": - return float(s[:-2]) * 16 - elif s[-2:] == "cm": - return float(s[:-2]) * 37.79 - elif s[-2:] == "in": - return float(s[:-2]) * 96 - else: - return 1024 - - def _merge_transform(self, node, transform): - """Propagate style and transform to remove inheritance - Originally from - https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 - """ - - # Compose the transformations - if node.tag == addNS("svg", "svg") and node.get("viewBox"): - vx, vy, vw, vh = [self._get_dimension(x) - for x in node.get("viewBox").split()] - dw = self._get_dimension(node.get("width", vw)) - dh = self._get_dimension(node.get("height", vh)) - t = ("translate(%f, %f) scale(%f, %f)" % - (-vx, -vy, dw / vw, dh / vh)) - this_transform = simpletransform.parseTransform( - t, transform) - this_transform = simpletransform.parseTransform( - node.get("transform"), this_transform) - del node.attrib["viewBox"] - else: - this_transform = simpletransform.parseTransform(node.get( - "transform"), transform) - - # Set the node's transform attrib - node.set("transform", - simpletransform.formatTransform(this_transform)) - - def _merge_style(self, node, style): - """Propagate style and transform to remove inheritance - Originally from - https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 - """ - - # Compose the style attribs - this_style = simplestyle.parseStyle(node.get("style", "")) - remaining_style = {} # Style attributes that are not propagated - - # Filters should remain on the top ancestor - non_propagated = ["filter"] - for key in non_propagated: - if key in this_style.keys(): - remaining_style[key] = this_style[key] - del this_style[key] - - # Create a copy of the parent style, and merge this style into it - parent_style_copy = style.copy() - parent_style_copy.update(this_style) - this_style = parent_style_copy - - # Merge in any attributes outside of the style - style_attribs = ["fill", "stroke"] - for attrib in style_attribs: - if node.get(attrib): - this_style[attrib] = node.get(attrib) - del node.attrib[attrib] - - if (node.tag == addNS("svg", "svg") - or node.tag == addNS("g", "svg") - or node.tag == addNS("a", "svg") - or node.tag == addNS("switch", "svg")): - # Leave only non-propagating style attributes - if len(remaining_style) == 0: - if "style" in node.keys(): - del node.attrib["style"] - else: - node.set("style", simplestyle.formatStyle(remaining_style)) - - else: - # This element is not a container - - # Merge remaining_style into this_style - this_style.update(remaining_style) - - # Set the element's style attribs - node.set("style", simplestyle.formatStyle(this_style)) - - def _merge_clippath(self, node, clippathurl): - - if (clippathurl): - node_transform = simpletransform.parseTransform( - node.get("transform")) - if (node_transform): - # Clip-paths on nodes with a transform have the transform - # applied to the clipPath as well, which we don't want. So, we - # create new clipPath element with references to all existing - # clippath subelements, but with the inverse transform applied - inverse_node_transform = simpletransform.formatTransform( - self._invert_transform(node_transform)) - new_clippath = inkex.etree.SubElement( - self.xpathSingle('//svg:defs'), 'clipPath', - {'clipPathUnits': 'userSpaceOnUse', - 'id': self.uniqueId("clipPath")}) - clippath = self.getElementById(clippathurl[5:-1]) - for c in (clippath.iterchildren()): - inkex.etree.SubElement( - new_clippath, 'use', - {inkex.addNS('href', 'xlink'): '#' + c.get("id"), - 'transform': inverse_node_transform, - 'id': self.uniqueId("use")}) - - # Set the clippathurl to be the one with the inverse transform - clippathurl = "url(#" + new_clippath.get("id") + ")" - - # Reference the parent clip-path to keep clipping intersection - # Find end of clip-path chain and add reference there - node_clippathurl = node.get("clip-path") - while (node_clippathurl): - node = self.getElementById(node_clippathurl[5:-1]) - node_clippathurl = node.get("clip-path") - node.set("clip-path", clippathurl) - - def _invert_transform(self, transform): - # duplicate list to avoid modifying it - return matrix(transform + [[0, 0, 1]]).I.tolist()[0:2] - - # Flatten a group into same z-order as parent, propagating attribs - def _ungroup(self, node): - node_parent = node.getparent() - node_index = list(node_parent).index(node) - node_style = simplestyle.parseStyle(node.get("style")) - node_transform = simpletransform.parseTransform(node.get("transform")) - node_clippathurl = node.get('clip-path') - for c in reversed(list(node)): - self._merge_transform(c, node_transform) - self._merge_style(c, node_style) - self._merge_clippath(c, node_clippathurl) - node_parent.insert(node_index, c) - node_parent.remove(node) - - # Put all ungrouping restrictions here - def _want_ungroup(self, node, depth, height): - if (node.tag == addNS("g", "svg") and - node.getparent() is not None and - height > self.options.keepdepth and - depth >= self.options.startdepth and - depth <= self.options.maxdepth): - return True - return False - - def _deep_ungroup(self, node): - # using iteration instead of recursion to avoid hitting Python - # max recursion depth limits, which is a problem in converted PDFs - - # Seed the queue (stack) with initial node - q = [{'node': node, - 'depth': 0, - 'prev': {'height': None}, - 'height': None}] - - while q: - current = q[-1] - node = current['node'] - depth = current['depth'] - height = current['height'] - - # Recursion path - if (height is None): - # Don't enter non-graphical portions of the document - if (node.tag == addNS("namedview", "sodipodi") - or node.tag == addNS("defs", "svg") - or node.tag == addNS("metadata", "svg") - or node.tag == addNS("foreignObject", "svg")): - q.pop() - - # Base case: Leaf node - if (node.tag != addNS("g", "svg") or not len(node)): - current['height'] = 0 - - # Recursive case: Group element with children - else: - depth += 1 - for c in node.iterchildren(): - q.append({'node': c, 'prev': current, - 'depth': depth, 'height': None}) - - # Return path - else: - # Ungroup if desired - if (self._want_ungroup(node, depth, height)): - self._ungroup(node) - - # Propagate (max) height up the call chain - height += 1 - previous = current['prev'] - prev_height = previous['height'] - if (prev_height is None or prev_height < height): - previous['height'] = height - - # Only process each node once - q.pop() - - def effect(self): - if len(self.selected): - for elem in self.selected.itervalues(): - self._deep_ungroup(elem) - else: - for elem in self.document.getroot(): - self._deep_ungroup(elem) - -if __name__ == '__main__': - effect = Ungroup() - effect.affect() diff --git a/share/extensions/uniconv-ext.py b/share/extensions/uniconv-ext.py deleted file mode 100755 index 876cc4642..000000000 --- a/share/extensions/uniconv-ext.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -""" -uniconv-ext.py -Python script for running UniConvertor in Inkscape extensions - -Copyright (C) 2008 Stephen Silver - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" -# standard library -import sys -# local library -from run_command import run -import inkex - -cmd = None - -try: - from subprocess import Popen, PIPE - p = Popen('uniconvertor', shell=True, stdout=PIPE, stderr=PIPE).wait() - if p==0 : - cmd = 'uniconvertor' - else: - p = Popen('uniconv', shell=True, stdout=PIPE, stderr=PIPE).wait() - if p==0 : - cmd = 'uniconv' -except ImportError: - from popen2 import Popen3 - p = Popen3('uniconv', True).wait() - if p!=32512 : cmd = 'uniconv' - p = Popen3('uniconvertor', True).wait() - if p!=32512 : cmd = 'uniconvertor' - -if cmd == None: - # there's no succeffully-returning uniconv command; try to get the module directly (on Windows) - try: - # cannot simply import uniconvertor, it aborts if you import it without parameters - import imp - imp.find_module("uniconvertor") - except ImportError: - inkex.localize() - inkex.errormsg(_('You need to install the UniConvertor software.\n'+\ - 'For GNU/Linux: install the package python-uniconvertor.\n'+\ - 'For Windows: download it from\n'+\ - 'https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download\n'+\ - 'and install into your Inkscape\'s Python location\n')) - sys.exit(1) - 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 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/uniconv_output.py b/share/extensions/uniconv_output.py deleted file mode 100755 index 253f43a41..000000000 --- a/share/extensions/uniconv_output.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python - -""" -uniconv_output.py -Module for running UniConverter exporting commands in Inkscape extensions - -Copyright (C) 2009 Nicolas Dufour (jazzynico) -Based on unicon-ext.py and run_command.py by Stephen Silver - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -# Run a command that generates an UniConvertor export file from a SVG file. -# On success, outputs the contents of the UniConverter conversion to stdout, -# and exits with a return code of 0. -# On failure, outputs an error message to stderr, and exits with a return -# code of 1. - -# standard library -import os -import sys -import tempfile -# local library -import inkex - -def run(command_format, prog_name, uniconv_format): - outfile = tempfile.mktemp(uniconv_format) - command = command_format + outfile - msg = None - # In order to get a return code from the process, we use subprocess.Popen - # if it's available (Python 2.4 onwards) and otherwise use popen2.Popen3 - # (Unix only). As the Inkscape package for Windows includes Python 2.5, - # this should cover all supported platforms. - try: - try: - from subprocess import Popen, PIPE - p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) - rc = p.wait() - out = p.stdout.read() - err = p.stderr.read() - except ImportError: - try: - from popen2 import Popen3 - p = Popen3(command, True) - p.wait() - rc = p.poll() - out = p.fromchild.read() - err = p.childerr.read() - except ImportError: - # shouldn't happen... - msg = "Neither subprocess.Popen nor popen2.Popen3 is available" - if rc and msg is None: - msg = "%s failed:\n%s\n%s\n" % (prog_name, out, err) - except Exception, inst: - msg = "Error attempting to run %s: %s" % (prog_name, str(inst)) - - # If successful, copy the output file to stdout. - if msg is None: - if os.name == 'nt': # make stdout work in binary on Windows - import msvcrt - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - try: - f = open(outfile, "rb") - data = f.read() - sys.stdout.write(data) - f.close() - except IOError, inst: - msg = "Error reading temporary file: %s" % str(inst) - - # Clean up. - try: - os.remove(outfile) - except Exception: - pass - - # Output error message (if any) and exit. - if msg is not None: - sys.stderr.write(msg + "\n") - sys.exit(1) - else: - sys.exit(0) - -def get_command(): - cmd = None - - try: - from subprocess import Popen, PIPE - p = Popen('uniconvertor', shell=True, stdout=PIPE, stderr=PIPE).wait() - if p==0 : - cmd = 'uniconvertor' - else: - p = Popen('uniconv', shell=True, stdout=PIPE, stderr=PIPE).wait() - if p==0 : - cmd = 'uniconv' - except ImportError: - from popen2 import Popen3 - p = Popen3('uniconv', True).wait() - if p!=32512 : cmd = 'uniconv' - p = Popen3('uniconvertor', True).wait() - if p!=32512 : cmd = 'uniconvertor' - - if cmd == None: - # there's no succeffully-returning uniconv command; try to get the module directly (on Windows) - try: - # cannot simply import uniconvertor, it aborts if you import it without parameters - import imp - imp.find_module("uniconvertor") - except ImportError: - inkex.localize() - inkex.errormsg(_('You need to install the UniConvertor software.\n'+\ - 'For GNU/Linux: install the package python-uniconvertor.\n'+\ - 'For Windows: download it from\n'+\ - 'https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download\n'+\ - 'and install into your Inkscape\'s Python location\n')) - sys.exit(1) - cmd = 'python -c "import uniconvertor; uniconvertor.uniconv_run();"' - - return cmd - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/voronoi.py b/share/extensions/voronoi.py deleted file mode 100755 index ac2c13f8f..000000000 --- a/share/extensions/voronoi.py +++ /dev/null @@ -1,792 +0,0 @@ -#!/usr/bin/env python -############################################################################# -# -# Voronoi diagram calculator/ Delaunay triangulator -# Translated to Python by Bill Simons -# September, 2005 -# -# Calculate Delaunay triangulation or the Voronoi polygons for a set of -# 2D input points. -# -# Derived from code bearing the following notice: -# -# The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T -# Bell Laboratories. -# Permission to use, copy, modify, and distribute this software for any -# purpose without fee is hereby granted, provided that this entire notice -# is included in all copies of any software which is or includes a copy -# or modification of this software and in all copies of the supporting -# documentation for such software. -# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -# WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY -# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -# OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -# -# Comments were incorporated from Shane O'Sullivan's translation of the -# original code into C++ (http://mapviewer.skynet.ie/voronoi.html) -# -# Steve Fortune's homepage: http://netlib.bell-labs.com/cm/cs/who/sjf/index.html -# -############################################################################# - -def usage(): - print """ -voronoi - compute Voronoi diagram or Delaunay triangulation - -voronoi [-t -p -d] [filename] - -Voronoi reads from filename (or standard input if no filename given) for a set -of points in the plane and writes either the Voronoi diagram or the Delaunay -triangulation to the standard output. Each input line should consist of two -real numbers, separated by white space. - -If option -t is present, the Delaunay triangulation is produced. -Each output line is a triple i j k, which are the indices of the three points -in a Delaunay triangle. Points are numbered starting at 0. - -If option -t is not present, the Voronoi diagram is produced. -There are four output record types. - -s a b indicates that an input point at coordinates a b was seen. -l a b c indicates a line with equation ax + by = c. -v a b indicates a vertex at a b. -e l v1 v2 indicates a Voronoi segment which is a subsegment of line number l - with endpoints numbered v1 and v2. If v1 or v2 is -1, the line - extends to infinity. - -Other options include: - -d Print debugging info - -p Produce output suitable for input to plot (1), rather than the forms - described above. - -On unsorted data uniformly distributed in the unit square, voronoi uses about -20n+140 bytes of storage. - -AUTHOR -Steve J. Fortune (1987) A Sweepline Algorithm for Voronoi Diagrams, -Algorithmica 2, 153-174. -""" - -############################################################################# -# -# For programmatic use two functions are available: -# -# computeVoronoiDiagram(points) -# -# Takes a list of point objects (which must have x and y fields). -# Returns a 3-tuple of: -# -# (1) a list of 2-tuples, which are the x,y coordinates of the -# Voronoi diagram vertices -# (2) a list of 3-tuples (a,b,c) which are the equations of the -# lines in the Voronoi diagram: a*x + b*y = c -# (3) a list of 3-tuples, (l, v1, v2) representing edges of the -# Voronoi diagram. l is the index of the line, v1 and v2 are -# the indices of the vetices at the end of the edge. If -# v1 or v2 is -1, the line extends to infinity. -# -# computeDelaunayTriangulation(points): -# -# Takes a list of point objects (which must have x and y fields). -# Returns a list of 3-tuples: the indices of the points that form a -# Delaunay triangle. -# -############################################################################# -import math -import sys -import getopt -TOLERANCE = 1e-9 -BIG_FLOAT = 1e38 - -#------------------------------------------------------------------ -class Context(object): - def __init__(self): - self.doPrint = 0 - self.debug = 0 - self.plot = 0 - self.triangulate = False - self.vertices = [] # list of vertex 2-tuples: (x,y) - self.lines = [] # equation of line 3-tuple (a b c), for the equation of the line a*x+b*y = c - self.edges = [] # edge 3-tuple: (line index, vertex 1 index, vertex 2 index) if either vertex index is -1, the edge extends to infiinity - self.triangles = [] # 3-tuple of vertex indices - - def circle(self,x,y,rad): - pass - - def clip_line(self,edge): - pass - - def line(self,x0,y0,x1,y1): - pass - - def outSite(self,s): - if(self.debug): - print "site (%d) at %f %f" % (s.sitenum, s.x, s.y) - elif(self.triangulate): - pass - elif(self.plot): - self.circle (s.x, s.y, cradius) - elif(self.doPrint): - print "s %f %f" % (s.x, s.y) - - def outVertex(self,s): - self.vertices.append((s.x,s.y)) - if(self.debug): - print "vertex(%d) at %f %f" % (s.sitenum, s.x, s.y) - elif(self.triangulate): - pass - elif(self.doPrint and not self.plot): - print "v %f %f" % (s.x,s.y) - - def outTriple(self,s1,s2,s3): - self.triangles.append((s1.sitenum, s2.sitenum, s3.sitenum)) - if(self.debug): - print "circle through left=%d right=%d bottom=%d" % (s1.sitenum, s2.sitenum, s3.sitenum) - elif(self.triangulate and self.doPrint and not self.plot): - print "%d %d %d" % (s1.sitenum, s2.sitenum, s3.sitenum) - - def outBisector(self,edge): - self.lines.append((edge.a, edge.b, edge.c)) - if(self.debug): - print "line(%d) %gx+%gy=%g, bisecting %d %d" % (edge.edgenum, edge.a, edge.b, edge.c, edge.reg[0].sitenum, edge.reg[1].sitenum) - elif(self.triangulate): - if(self.plot): - self.line(edge.reg[0].x, edge.reg[0].y, edge.reg[1].x, edge.reg[1].y) - elif(self.doPrint and not self.plot): - print "l %f %f %f" % (edge.a, edge.b, edge.c) - - def outEdge(self,edge): - sitenumL = -1 - if edge.ep[Edge.LE] is not None: - sitenumL = edge.ep[Edge.LE].sitenum - sitenumR = -1 - if edge.ep[Edge.RE] is not None: - sitenumR = edge.ep[Edge.RE].sitenum - self.edges.append((edge.edgenum,sitenumL,sitenumR)) - if(not self.triangulate): - if self.plot: - self.clip_line(edge) - elif(self.doPrint): - print "e %d" % edge.edgenum, - print " %d " % sitenumL, - print "%d" % sitenumR - -#------------------------------------------------------------------ -def voronoi(siteList,context): - edgeList = EdgeList(siteList.xmin,siteList.xmax,len(siteList)) - priorityQ = PriorityQueue(siteList.ymin,siteList.ymax,len(siteList)) - siteIter = siteList.iterator() - - bottomsite = siteIter.next() - context.outSite(bottomsite) - newsite = siteIter.next() - minpt = Site(-BIG_FLOAT,-BIG_FLOAT) - while True: - if not priorityQ.isEmpty(): - minpt = priorityQ.getMinPt() - - if (newsite and (priorityQ.isEmpty() or cmp(newsite,minpt) < 0)): - # newsite is smallest - this is a site event - context.outSite(newsite) - - # get first Halfedge to the LEFT and RIGHT of the new site - lbnd = edgeList.leftbnd(newsite) - rbnd = lbnd.right - - # if this halfedge has no edge, bot = bottom site (whatever that is) - # create a new edge that bisects - bot = lbnd.rightreg(bottomsite) - edge = Edge.bisect(bot,newsite) - context.outBisector(edge) - - # create a new Halfedge, setting its pm field to 0 and insert - # this new bisector edge between the left and right vectors in - # a linked list - bisector = Halfedge(edge,Edge.LE) - edgeList.insert(lbnd,bisector) - - # if the new bisector intersects with the left edge, remove - # the left edge's vertex, and put in the new one - p = lbnd.intersect(bisector) - if p is not None: - priorityQ.delete(lbnd) - priorityQ.insert(lbnd,p,newsite.distance(p)) - - # create a new Halfedge, setting its pm field to 1 - # insert the new Halfedge to the right of the original bisector - lbnd = bisector - bisector = Halfedge(edge,Edge.RE) - edgeList.insert(lbnd,bisector) - - # if this new bisector intersects with the right Halfedge - p = bisector.intersect(rbnd) - if p is not None: - # push the Halfedge into the ordered linked list of vertices - priorityQ.insert(bisector,p,newsite.distance(p)) - - newsite = siteIter.next() - - elif not priorityQ.isEmpty(): - # intersection is smallest - this is a vector (circle) event - - # pop the Halfedge with the lowest vector off the ordered list of - # vectors. Get the Halfedge to the left and right of the above HE - # and also the Halfedge to the right of the right HE - lbnd = priorityQ.popMinHalfedge() - llbnd = lbnd.left - rbnd = lbnd.right - rrbnd = rbnd.right - - # get the Site to the left of the left HE and to the right of - # the right HE which it bisects - bot = lbnd.leftreg(bottomsite) - top = rbnd.rightreg(bottomsite) - - # output the triple of sites, stating that a circle goes through them - mid = lbnd.rightreg(bottomsite) - context.outTriple(bot,top,mid) - - # get the vertex that caused this event and set the vertex number - # couldn't do this earlier since we didn't know when it would be processed - v = lbnd.vertex - siteList.setSiteNumber(v) - context.outVertex(v) - - # set the endpoint of the left and right Halfedge to be this vector - if lbnd.edge.setEndpoint(lbnd.pm,v): - context.outEdge(lbnd.edge) - - if rbnd.edge.setEndpoint(rbnd.pm,v): - context.outEdge(rbnd.edge) - - - # delete the lowest HE, remove all vertex events to do with the - # right HE and delete the right HE - edgeList.delete(lbnd) - priorityQ.delete(rbnd) - edgeList.delete(rbnd) - - - # if the site to the left of the event is higher than the Site - # to the right of it, then swap them and set 'pm' to RIGHT - pm = Edge.LE - if bot.y > top.y: - bot,top = top,bot - pm = Edge.RE - - # Create an Edge (or line) that is between the two Sites. This - # creates the formula of the line, and assigns a line number to it - edge = Edge.bisect(bot, top) - context.outBisector(edge) - - # create a HE from the edge - bisector = Halfedge(edge, pm) - - # insert the new bisector to the right of the left HE - # set one endpoint to the new edge to be the vector point 'v' - # If the site to the left of this bisector is higher than the right - # Site, then this endpoint is put in position 0; otherwise in pos 1 - edgeList.insert(llbnd, bisector) - if edge.setEndpoint(Edge.RE - pm, v): - context.outEdge(edge) - - # if left HE and the new bisector don't intersect, then delete - # the left HE, and reinsert it - p = llbnd.intersect(bisector) - if p is not None: - priorityQ.delete(llbnd); - priorityQ.insert(llbnd, p, bot.distance(p)) - - # if right HE and the new bisector don't intersect, then reinsert it - p = bisector.intersect(rrbnd) - if p is not None: - priorityQ.insert(bisector, p, bot.distance(p)) - else: - break - - he = edgeList.leftend.right - while he is not edgeList.rightend: - context.outEdge(he.edge) - he = he.right - -#------------------------------------------------------------------ -def isEqual(a,b,relativeError=TOLERANCE): - # is nearly equal to within the allowed relative error - norm = max(abs(a),abs(b)) - return (norm < relativeError) or (abs(a - b) < (relativeError * norm)) - -#------------------------------------------------------------------ -class Site(object): - def __init__(self,x=0.0,y=0.0,sitenum=0): - self.x = x - self.y = y - self.sitenum = sitenum - - def dump(self): - print "Site #%d (%g, %g)" % (self.sitenum,self.x,self.y) - - def __cmp__(self,other): - if self.y < other.y: - return -1 - elif self.y > other.y: - return 1 - elif self.x < other.x: - return -1 - elif self.x > other.x: - return 1 - else: - return 0 - - def distance(self,other): - dx = self.x - other.x - dy = self.y - other.y - return math.sqrt(dx*dx + dy*dy) - -#------------------------------------------------------------------ -class Edge(object): - LE = 0 - RE = 1 - EDGE_NUM = 0 - DELETED = {} # marker value - - def __init__(self): - self.a = 0.0 - self.b = 0.0 - self.c = 0.0 - self.ep = [None,None] - self.reg = [None,None] - self.edgenum = 0 - - def dump(self): - print "(#%d a=%g, b=%g, c=%g)" % (self.edgenum,self.a,self.b,self.c) - print "ep",self.ep - print "reg",self.reg - - def setEndpoint(self, lrFlag, site): - self.ep[lrFlag] = site - if self.ep[Edge.RE - lrFlag] is None: - return False - return True - - @staticmethod - def bisect(s1,s2): - newedge = Edge() - newedge.reg[0] = s1 # store the sites that this edge is bisecting - newedge.reg[1] = s2 - - # to begin with, there are no endpoints on the bisector - it goes to infinity - # ep[0] and ep[1] are None - - # get the difference in x dist between the sites - dx = float(s2.x - s1.x) - dy = float(s2.y - s1.y) - adx = abs(dx) # make sure that the difference in positive - ady = abs(dy) - - # get the slope of the line - newedge.c = float(s1.x * dx + s1.y * dy + (dx*dx + dy*dy)*0.5) - if adx > ady : - # set formula of line, with x fixed to 1 - newedge.a = 1.0 - newedge.b = dy/dx - newedge.c /= dx - else: - # set formula of line, with y fixed to 1 - newedge.b = 1.0 - if dy <= 0: - dy = 0.01 - newedge.a = dx/dy - newedge.c /= dy - - newedge.edgenum = Edge.EDGE_NUM - Edge.EDGE_NUM += 1 - return newedge - - -#------------------------------------------------------------------ -class Halfedge(object): - def __init__(self,edge=None,pm=Edge.LE): - self.left = None # left Halfedge in the edge list - self.right = None # right Halfedge in the edge list - self.qnext = None # priority queue linked list pointer - self.edge = edge # edge list Edge - self.pm = pm - self.vertex = None # Site() - self.ystar = BIG_FLOAT - - def dump(self): - print "Halfedge--------------------------" - print "left: ", self.left - print "right: ", self.right - print "edge: ", self.edge - print "pm: ", self.pm - print "vertex: ", - if self.vertex: self.vertex.dump() - else: print "None" - print "ystar: ", self.ystar - - - def __cmp__(self,other): - if self.ystar > other.ystar: - return 1 - elif self.ystar < other.ystar: - return -1 - elif self.vertex.x > other.vertex.x: - return 1 - elif self.vertex.x < other.vertex.x: - return -1 - else: - return 0 - - def leftreg(self,default): - if not self.edge: - return default - elif self.pm == Edge.LE: - return self.edge.reg[Edge.LE] - else: - return self.edge.reg[Edge.RE] - - def rightreg(self,default): - if not self.edge: - return default - elif self.pm == Edge.LE: - return self.edge.reg[Edge.RE] - else: - return self.edge.reg[Edge.LE] - - - # returns True if p is to right of halfedge self - def isPointRightOf(self,pt): - e = self.edge - topsite = e.reg[1] - right_of_site = pt.x > topsite.x - - if(right_of_site and self.pm == Edge.LE): - return True - - if(not right_of_site and self.pm == Edge.RE): - return False - - if(e.a == 1.0): - dyp = pt.y - topsite.y - dxp = pt.x - topsite.x - fast = 0; - if ((not right_of_site and e.b < 0.0) or (right_of_site and e.b >= 0.0)): - above = dyp >= e.b * dxp - fast = above - else: - above = pt.x + pt.y * e.b > e.c - if(e.b < 0.0): - above = not above - if (not above): - fast = 1 - if (not fast): - dxs = topsite.x - (e.reg[0]).x - above = e.b * (dxp*dxp - dyp*dyp) < dxs*dyp*(1.0+2.0*dxp/dxs + e.b*e.b) - if(e.b < 0.0): - above = not above - else: # e.b == 1.0 - yl = e.c - e.a * pt.x - t1 = pt.y - yl - t2 = pt.x - topsite.x - t3 = yl - topsite.y - above = t1*t1 > t2*t2 + t3*t3 - - if(self.pm==Edge.LE): - return above - else: - return not above - - #-------------------------- - # create a new site where the Halfedges el1 and el2 intersect - def intersect(self,other): - e1 = self.edge - e2 = other.edge - if (e1 is None) or (e2 is None): - return None - - # if the two edges bisect the same parent return None - if e1.reg[1] is e2.reg[1]: - return None - - d = e1.a * e2.b - e1.b * e2.a - if isEqual(d,0.0): - return None - - xint = (e1.c*e2.b - e2.c*e1.b) / d - yint = (e2.c*e1.a - e1.c*e2.a) / d - if(cmp(e1.reg[1],e2.reg[1]) < 0): - he = self - e = e1 - else: - he = other - e = e2 - - rightOfSite = xint >= e.reg[1].x - if((rightOfSite and he.pm == Edge.LE) or - (not rightOfSite and he.pm == Edge.RE)): - return None - - # create a new site at the point of intersection - this is a new - # vector event waiting to happen - return Site(xint,yint) - - - -#------------------------------------------------------------------ -class EdgeList(object): - def __init__(self,xmin,xmax,nsites): - if xmin > xmax: xmin,xmax = xmax,xmin - self.hashsize = int(2*math.sqrt(nsites+4)) - - self.xmin = xmin - self.deltax = float(xmax - xmin) - self.hash = [None]*self.hashsize - - self.leftend = Halfedge() - self.rightend = Halfedge() - self.leftend.right = self.rightend - self.rightend.left = self.leftend - self.hash[0] = self.leftend - self.hash[-1] = self.rightend - - def insert(self,left,he): - he.left = left - he.right = left.right - left.right.left = he - left.right = he - - def delete(self,he): - he.left.right = he.right - he.right.left = he.left - he.edge = Edge.DELETED - - # Get entry from hash table, pruning any deleted nodes - def gethash(self,b): - if(b < 0 or b >= self.hashsize): - return None - he = self.hash[b] - if he is None or he.edge is not Edge.DELETED: - return he - - # Hash table points to deleted half edge. Patch as necessary. - self.hash[b] = None - return None - - def leftbnd(self,pt): - # Use hash table to get close to desired halfedge - bucket = int(((pt.x - self.xmin)/self.deltax * self.hashsize)) - - if(bucket < 0): - bucket =0; - - if(bucket >=self.hashsize): - bucket = self.hashsize-1 - - he = self.gethash(bucket) - if(he is None): - i = 1 - while True: - he = self.gethash(bucket-i) - if (he is not None): break; - he = self.gethash(bucket+i) - if (he is not None): break; - i += 1 - - # Now search linear list of halfedges for the corect one - if (he is self.leftend) or (he is not self.rightend and he.isPointRightOf(pt)): - he = he.right - while he is not self.rightend and he.isPointRightOf(pt): - he = he.right - he = he.left; - else: - he = he.left - while (he is not self.leftend and not he.isPointRightOf(pt)): - he = he.left - - # Update hash table and reference counts - if(bucket > 0 and bucket < self.hashsize-1): - self.hash[bucket] = he - return he - - -#------------------------------------------------------------------ -class PriorityQueue(object): - def __init__(self,ymin,ymax,nsites): - self.ymin = ymin - self.deltay = ymax - ymin - self.hashsize = int(4 * math.sqrt(nsites)) - self.count = 0 - self.minidx = 0 - self.hash = [] - for i in range(self.hashsize): - self.hash.append(Halfedge()) - - def __len__(self): - return self.count - - def isEmpty(self): - return self.count == 0 - - def insert(self,he,site,offset): - he.vertex = site - he.ystar = site.y + offset - last = self.hash[self.getBucket(he)] - next = last.qnext - while((next is not None) and cmp(he,next) > 0): - last = next - next = last.qnext - he.qnext = last.qnext - last.qnext = he - self.count += 1 - - def delete(self,he): - if (he.vertex is not None): - last = self.hash[self.getBucket(he)] - while last.qnext is not he: - last = last.qnext - last.qnext = he.qnext - self.count -= 1 - he.vertex = None - - def getBucket(self,he): - bucket = int(((he.ystar - self.ymin) / self.deltay) * self.hashsize) - if bucket < 0: bucket = 0 - if bucket >= self.hashsize: bucket = self.hashsize-1 - if bucket < self.minidx: self.minidx = bucket - return bucket - - def getMinPt(self): - while(self.hash[self.minidx].qnext is None): - self.minidx += 1 - he = self.hash[self.minidx].qnext - x = he.vertex.x - y = he.ystar - return Site(x,y) - - def popMinHalfedge(self): - curr = self.hash[self.minidx].qnext - self.hash[self.minidx].qnext = curr.qnext - self.count -= 1 - return curr - - -#------------------------------------------------------------------ -class SiteList(object): - def __init__(self,pointList): - self.__sites = [] - self.__sitenum = 0 - - self.__xmin = pointList[0].x - self.__ymin = pointList[0].y - self.__xmax = pointList[0].x - self.__ymax = pointList[0].y - for i,pt in enumerate(pointList): - self.__sites.append(Site(pt.x,pt.y,i)) - if pt.x < self.__xmin: self.__xmin = pt.x - if pt.y < self.__ymin: self.__ymin = pt.y - if pt.x > self.__xmax: self.__xmax = pt.x - if pt.y > self.__ymax: self.__ymax = pt.y - self.__sites.sort() - - def setSiteNumber(self,site): - site.sitenum = self.__sitenum - self.__sitenum += 1 - - class Iterator(object): - def __init__(this,lst): this.generator = (s for s in lst) - def __iter__(this): return this - def next(this): - try: - return this.generator.next() - except StopIteration: - return None - - def iterator(self): - return SiteList.Iterator(self.__sites) - - def __iter__(self): - return SiteList.Iterator(self.__sites) - - def __len__(self): - return len(self.__sites) - - def _getxmin(self): return self.__xmin - def _getymin(self): return self.__ymin - def _getxmax(self): return self.__xmax - def _getymax(self): return self.__ymax - xmin = property(_getxmin) - ymin = property(_getymin) - xmax = property(_getxmax) - ymax = property(_getymax) - - -#------------------------------------------------------------------ -def computeVoronoiDiagram(points): - """ Takes a list of point objects (which must have x and y fields). - Returns a 3-tuple of: - - (1) a list of 2-tuples, which are the x,y coordinates of the - Voronoi diagram vertices - (2) a list of 3-tuples (a,b,c) which are the equations of the - lines in the Voronoi diagram: a*x + b*y = c - (3) a list of 3-tuples, (l, v1, v2) representing edges of the - Voronoi diagram. l is the index of the line, v1 and v2 are - the indices of the vetices at the end of the edge. If - v1 or v2 is -1, the line extends to infinity. - """ - siteList = SiteList(points) - context = Context() - voronoi(siteList,context) - return (context.vertices,context.lines,context.edges) - -#------------------------------------------------------------------ -def computeDelaunayTriangulation(points): - """ Takes a list of point objects (which must have x and y fields). - Returns a list of 3-tuples: the indices of the points that form a - Delaunay triangle. - """ - siteList = SiteList(points) - context = Context() - context.triangulate = True - voronoi(siteList,context) - return context.triangles - -#----------------------------------------------------------------------------- -if __name__=="__main__": - try: - optlist,args = getopt.getopt(sys.argv[1:],"thdp") - except getopt.GetoptError: - usage() - sys.exit(2) - - doHelp = 0 - c = Context() - c.doPrint = 1 - for opt in optlist: - if opt[0] == "-d": c.debug = 1 - if opt[0] == "-p": c.plot = 1 - if opt[0] == "-t": c.triangulate = 1 - if opt[0] == "-h": doHelp = 1 - - if not doHelp: - pts = [] - fp = sys.stdin - if len(args) > 0: - fp = open(args[0],'r') - for line in fp: - fld = line.split() - x = float(fld[0]) - y = float(fld[1]) - pts.append(Site(x,y)) - if len(args) > 0: fp.close() - - if doHelp or len(pts) == 0: - usage() - sys.exit(2) - - sl = SiteList(pts) - voronoi(sl,c) - diff --git a/share/extensions/voronoi2svg.inx b/share/extensions/voronoi2svg.inx deleted file mode 100644 index c07dbb8e5..000000000 --- a/share/extensions/voronoi2svg.inx +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Voronoi Diagram</_name> - <id>org.inkscape.effect.voronoi</id> - <dependency type="executable" location="extensions">voronoi2svg.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <dependency type="executable" location="extensions">voronoi.py</dependency> - <param name="tab" type="notebook"> - <page name="options" _gui-text="Options"> - <param name="diagram-type" type="enum" _gui-text="Type of diagram:"> - <_item value="Voronoi">Voronoi Diagram</_item> - <_item value="Delaunay">Delaunay Triangulation</_item> - <_item value="Both">Voronoi and Delaunay</_item> - </param> - <_param name="Voronoi Options" type="description" appearance="header">Options for Voronoi diagram</_param> - <param name="clip-box" type="enum" _gui-text="Bounding box of the diagram:"> - <_item value="Page">Page</_item> - <_item value="Automatic from seeds">Automatic from selected objects</_item> - </param> - <param name="show-clip-box" type="boolean" _gui-text="Show the bounding box"></param> - <_param name="Delaunay Options" type="description" appearance="header">Options for Delaunay Triangulation</_param> - <param name="delaunay-fill-options" _gui-text="Triangles color" type="optiongroup"> - <_option value="delaunay-no-fill">Default (Stroke black and no fill)</_option> - <_option value="delaunay-fill">Triangles with item color</_option> - <_option value="delaunay-fill-random">Triangles with item color (random on apply)</_option> - </param> - </page> - <page name="help" _gui-text="Help"> - <_param name="help_text" type="description">Select a set of objects. Their centroids will be used as the sites of the Voronoi diagram. Text objects are not handled.</_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">voronoi2svg.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/voronoi2svg.py b/share/extensions/voronoi2svg.py deleted file mode 100755 index 5232fb81e..000000000 --- a/share/extensions/voronoi2svg.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -""" - -voronoi2svg.py -Create Voronoi diagram from seeds (midpoints of selected objects) - -- Voronoi Diagram algorithm and C code by Steven Fortune, 1987, http://ect.bell-labs.com/who/sjf/ -- Python translation to file voronoi.py by Bill Simons, 2005, http://www.oxfish.com/ - -Copyright (C) 2011 Vincent Nivoliers and contributors - -Contributors - ~suv, <suv-sf@users.sf.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 -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 - -""" -# standard library -import sys -import os -# local library -import inkex -import simplestyle -import simplepath -import simpletransform -import voronoi -import random - - -class Point: - def __init__(self,x,y): - self.x = x - self.y = y - -class Voronoi2svg(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - #{{{ Additional options - - self.OptionParser.add_option( - "--tab", - action="store", - type="string", - dest="tab") - self.OptionParser.add_option( - '--diagram-type', - action = 'store', - type = 'choice', choices=['Voronoi','Delaunay','Both'], - default = 'Voronoi', - dest='diagramType', - help = 'Defines the type of the diagram') - self.OptionParser.add_option( - '--clip-box', - action = 'store', - type = 'choice', choices=['Page','Automatic from seeds'], - default = 'Page', - dest='clipBox', - help = 'Defines the bounding box of the Voronoi diagram') - self.OptionParser.add_option( - '--show-clip-box', - action = 'store', - type = 'inkbool', - default = False, - dest='showClipBox', - help = 'Set this to true to write the bounding box') - self.OptionParser.add_option( - '--delaunay-fill-options', - action = 'store', - type = 'string', - default = "delaunay-no-fill", - dest='delaunayFillOptions', - help = 'Set the Delaunay triangles color options') - #}}} - - #{{{ Clipping a line by a bounding box - def dot(self,x,y): - return x[0]*y[0] + x[1]*y[1] - - def intersectLineSegment(self,line,v1,v2): - s1 = self.dot(line,v1) - line[2] - s2 = self.dot(line,v2) - line[2] - if s1*s2 > 0: - return (0,0,False) - else: - tmp = self.dot(line,v1)-self.dot(line,v2) - if tmp == 0: - return(0,0,False) - u = (line[2]-self.dot(line,v2))/tmp - v = 1-u - return (u*v1[0]+v*v2[0],u*v1[1]+v*v2[1],True) - - def clipEdge(self,vertices, lines, edge, bbox): - #bounding box corners - bbc = [] - bbc.append((bbox[0],bbox[2])) - bbc.append((bbox[1],bbox[2])) - bbc.append((bbox[1],bbox[3])) - bbc.append((bbox[0],bbox[3])) - - #record intersections of the line with bounding box edges - line = (lines[edge[0]]) - interpoints = [] - for i in range(4): - p = self.intersectLineSegment(line,bbc[i],bbc[(i+1)%4]) - if (p[2]): - interpoints.append(p) - - #if the edge has no intersection, return empty intersection - if (len(interpoints)<2): - return [] - - if (len(interpoints)>2): #happens when the edge crosses the corner of the box - interpoints = list(set(interpoints)) #remove doubles - - #points of the edge - v1 = vertices[edge[1]] - interpoints.append((v1[0],v1[1],False)) - v2 = vertices[edge[2]] - interpoints.append((v2[0],v2[1],False)) - - #sorting the points in the widest range to get them in order on the line - minx = interpoints[0][0] - maxx = interpoints[0][0] - miny = interpoints[0][1] - maxy = interpoints[0][1] - for point in interpoints: - minx = min(point[0],minx) - maxx = max(point[0],maxx) - miny = min(point[1],miny) - maxy = max(point[1],maxy) - - if (maxx-minx) > (maxy-miny): - interpoints.sort() - else: - interpoints.sort(key=lambda pt: pt[1]) - - start = [] - inside = False #true when the part of the line studied is in the clip box - startWrite = False #true when the part of the line is in the edge segment - for point in interpoints: - if point[2]: #The point is a bounding box intersection - if inside: - if startWrite: - return [[start[0],start[1]],[point[0],point[1]]] - else: - return [] - else: - if startWrite: - start = point - inside = not inside - else: #The point is a segment endpoint - if startWrite: - if inside: - #a vertex ends the line inside the bounding box - return [[start[0],start[1]],[point[0],point[1]]] - else: - return [] - else: - if inside: - start = point - startWrite = not startWrite - - #}}} - - #{{{ Transformation helpers - - def getGlobalTransform(self,node): - parent = node.getparent() - myTrans = simpletransform.parseTransform(node.get('transform')) - if myTrans: - if parent is not None: - parentTrans = self.getGlobalTransform(parent) - if parentTrans: - return simpletransform.composeTransform(parentTrans,myTrans) - else: - return myTrans - else: - if parent is not None: - return self.getGlobalTransform(parent) - else: - return None - - - #}}} - - def effect(self): - #saveout = sys.stdout - #sys.stdout = sys.stderr - #{{{ Check that elements have been selected - - if len(self.options.ids) == 0: - inkex.errormsg(_("Please select objects!")) - return - - #}}} - - #{{{ Drawing styles - - linestyle = { - 'stroke' : '#000000', - 'stroke-width' : str(self.unittouu('1px')), - 'fill' : 'none', - 'stroke-linecap' : 'round', - 'stroke-linejoin' : 'round' - } - - facestyle = { - 'stroke' : '#000000', - 'stroke-width' : str(self.unittouu('1px')), - 'fill' : 'none', - 'stroke-linecap' : 'round', - 'stroke-linejoin' : 'round' - } - - #}}} - - #{{{ Handle the transformation of the current group - parentGroup = self.getParentNode(self.selected[self.options.ids[0]]) - - trans = self.getGlobalTransform(parentGroup) - invtrans = None - if trans: - invtrans = simpletransform.invertTransform(trans) - - #}}} - - #{{{ Recovery of the selected objects - - pts = [] - nodes = [] - seeds = [] - fills = [] - - - for id in self.options.ids: - node = self.selected[id] - nodes.append(node) - bbox = simpletransform.computeBBox([node]) - if bbox: - cx = 0.5*(bbox[0]+bbox[1]) - cy = 0.5*(bbox[2]+bbox[3]) - pt = [cx,cy] - if trans: - simpletransform.applyTransformToPoint(trans,pt) - pts.append(Point(pt[0],pt[1])) - fill = 'none' - if self.options.delaunayFillOptions != "delaunay-no-fill": - if node.attrib.has_key('style'): - style = node.get('style') # fixme: this will break for presentation attributes! - if style: - declarations = style.split(';') - for i,decl in enumerate(declarations): - parts = decl.split(':', 2) - if len(parts) == 2: - (prop, val) = parts - prop = prop.strip().lower() - if prop == 'fill': - fill = val.strip() - fills.append(fill) - seeds.append(Point(cx,cy)) - - #}}} - - #{{{ Creation of groups to store the result - - if self.options.diagramType != 'Delaunay': - # Voronoi - groupVoronoi = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg')) - groupVoronoi.set(inkex.addNS('label', 'inkscape'), 'Voronoi') - if invtrans: - simpletransform.applyTransformToNode(invtrans,groupVoronoi) - if self.options.diagramType != 'Voronoi': - # Delaunay - groupDelaunay = inkex.etree.SubElement(parentGroup,inkex.addNS('g','svg')) - groupDelaunay.set(inkex.addNS('label', 'inkscape'), 'Delaunay') - - #}}} - - #{{{ Clipping box handling - - if self.options.diagramType != 'Delaunay': - #Clipping bounding box creation - gBbox = simpletransform.computeBBox(nodes) - - #Clipbox is the box to which the Voronoi diagram is restricted - clipBox = () - if self.options.clipBox == 'Page': - svg = self.document.getroot() - w = self.unittouu(svg.get('width')) - h = self.unittouu(svg.get('height')) - clipBox = (0,w,0,h) - else: - clipBox = (2*gBbox[0]-gBbox[1], - 2*gBbox[1]-gBbox[0], - 2*gBbox[2]-gBbox[3], - 2*gBbox[3]-gBbox[2]) - - #Safebox adds points so that no Voronoi edge in clipBox is infinite - safeBox = (2*clipBox[0]-clipBox[1], - 2*clipBox[1]-clipBox[0], - 2*clipBox[2]-clipBox[3], - 2*clipBox[3]-clipBox[2]) - pts.append(Point(safeBox[0],safeBox[2])) - pts.append(Point(safeBox[1],safeBox[2])) - pts.append(Point(safeBox[1],safeBox[3])) - pts.append(Point(safeBox[0],safeBox[3])) - - if self.options.showClipBox: - #Add the clip box to the drawing - rect = inkex.etree.SubElement(groupVoronoi,inkex.addNS('rect','svg')) - rect.set('x',str(clipBox[0])) - rect.set('y',str(clipBox[2])) - rect.set('width',str(clipBox[1]-clipBox[0])) - rect.set('height',str(clipBox[3]-clipBox[2])) - rect.set('style',simplestyle.formatStyle(linestyle)) - - #}}} - - #{{{ Voronoi diagram generation - - if self.options.diagramType != 'Delaunay': - vertices,lines,edges = voronoi.computeVoronoiDiagram(pts) - for edge in edges: - line = edge[0] - vindex1 = edge[1] - vindex2 = edge[2] - if (vindex1 <0) or (vindex2 <0): - continue # infinite lines have no need to be handled in the clipped box - else: - segment = self.clipEdge(vertices,lines,edge,clipBox) - #segment = [vertices[vindex1],vertices[vindex2]] # deactivate clipping - if len(segment)>1: - v1 = segment[0] - v2 = segment[1] - cmds = [['M',[v1[0],v1[1]]],['L',[v2[0],v2[1]]]] - path = inkex.etree.Element(inkex.addNS('path','svg')) - path.set('d',simplepath.formatPath(cmds)) - path.set('style',simplestyle.formatStyle(linestyle)) - groupVoronoi.append(path) - - if self.options.diagramType != 'Voronoi': - triangles = voronoi.computeDelaunayTriangulation(seeds) - i = 0; - if self.options.delaunayFillOptions == "delaunay-fill": - random.seed("inkscape") - for triangle in triangles: - p1 = seeds[triangle[0]] - p2 = seeds[triangle[1]] - p3 = seeds[triangle[2]] - cmds = [['M',[p1.x,p1.y]], - ['L',[p2.x,p2.y]], - ['L',[p3.x,p3.y]], - ['Z',[]]] - if self.options.delaunayFillOptions == "delaunay-fill" or self.options.delaunayFillOptions == "delaunay-fill-random": - facestyle = { - 'stroke' : fills[triangle[random.randrange(0, 2)]], - 'stroke-width' : str(self.unittouu('0.005px')), - 'fill' : fills[triangle[random.randrange(0, 2)]], - 'stroke-linecap' : 'round', - 'stroke-linejoin' : 'round' - } - path = inkex.etree.Element(inkex.addNS('path','svg')) - path.set('d',simplepath.formatPath(cmds)) - path.set('style',simplestyle.formatStyle(facestyle)) - groupDelaunay.append(path) - i += 1; - #sys.stdout = saveout - #}}} - - -if __name__ == "__main__": - e = Voronoi2svg() - e.affect() - - -# vim: expandtab shiftwidth=2 tabstop=2 softtabstop=2 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/web-set-att.inx b/share/extensions/web-set-att.inx deleted file mode 100644 index 65b35bada..000000000 --- a/share/extensions/web-set-att.inx +++ /dev/null @@ -1,52 +0,0 @@ -<?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="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> -</inkscape-extension> diff --git a/share/extensions/web-set-att.py b/share/extensions/web-set-att.py deleted file mode 100755 index 40246e2c5..000000000 --- a/share/extensions/web-set-att.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -import inkwebeffect -import inkex - -class InkWebTransmitAtt(inkwebeffect.InkWebEffect): - - def __init__(self): - inkwebeffect.InkWebEffect.__init__(self) - self.OptionParser.add_option("-a", "--att", - action="store", type="string", - dest="att", default="fill", - help="Attribute to set.") - self.OptionParser.add_option("-v", "--val", - action="store", type="string", - dest="val", default="red", - help="Values to set.") - self.OptionParser.add_option("-w", "--when", - action="store", type="string", - dest="when", default="onclick", - help="When it must to set?") - self.OptionParser.add_option("-c", "--compatibility", - action="store", type="string", - dest="compatibility", default="append", - help="Compatibility with previews code to this event.") - self.OptionParser.add_option("-t", "--from-and-to", - 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() - - if len(self.options.ids) < 2: - inkwebeffect.inkex.errormsg(_("You must select at least two elements.")) - exit(1) - - elFrom = [] - idTo = [] - if self.options.from_and_to == "g-to-one": - # All set the last - for selId in self.options.ids[:-1]: - elFrom.append( self.selected[selId] ) - idTo.append( self.options.ids[-1] ) - else: - # The first set all - elFrom.append( self.selected[ self.options.ids[0] ] ) - for selId in self.options.ids[1:]: - idTo.append( selId ) - - evCode = "InkWeb.setAtt({el:['"+ "','".join(idTo) +"'], " + \ - "att:'"+ self.options.att +"', " + \ - "val:'"+ self.options.val +"'})" - - for el in elFrom: - prevEvCode = el.get( self.options.when ) - if prevEvCode == None: prevEvCode = "" - - if self.options.compatibility == 'append': - elEvCode = prevEvCode +";\n"+ evCode - if self.options.compatibility == 'prepend': - elEvCode = evCode +";\n"+ prevEvCode - - el.set( self.options.when, elEvCode ) - -if __name__ == '__main__': - e = InkWebTransmitAtt() - e.affect() - diff --git a/share/extensions/web-transmit-att.inx b/share/extensions/web-transmit-att.inx deleted file mode 100644 index 343f65f61..000000000 --- a/share/extensions/web-transmit-att.inx +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Transmit Attributes</_name> - <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="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 deleted file mode 100755 index d1b625321..000000000 --- a/share/extensions/web-transmit-att.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -import inkwebeffect -import inkex - - -class InkWebTransmitAtt(inkwebeffect.InkWebEffect): - - def __init__(self): - inkwebeffect.InkWebEffect.__init__(self) - self.OptionParser.add_option("-a", "--att", - action="store", type="string", - dest="att", default="fill", - help="Attribute to transmitted.") - self.OptionParser.add_option("-w", "--when", - action="store", type="string", - dest="when", default="onclick", - help="When it must to transmit?") - self.OptionParser.add_option("-c", "--compatibility", - action="store", type="string", - dest="compatibility", default="append", - help="Compatibility with previews code to this event.") - self.OptionParser.add_option("-t", "--from-and-to", - 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() - - if len(self.options.ids) < 2: - inkwebeffect.inkex.errormsg(_("You must select at least two elements.")) - exit(1) - - elFrom = [] - idTo = [] - if self.options.from_and_to == "g-to-one": - # All tramsmit to the last - for selId in self.options.ids[:-1]: - elFrom.append( self.selected[selId] ) - idTo.append( self.options.ids[-1] ) - else: - # The first transmit to all - elFrom.append( self.selected[ self.options.ids[0] ] ) - for selId in self.options.ids[1:]: - idTo.append( selId ) - - evCode = "InkWeb.transmitAtt({from:this, " + \ - "to:['"+ "','".join(idTo) +"'], " + \ - "att:'"+ self.options.att +"'})" - - for el in elFrom: - prevEvCode = el.get( self.options.when ) - if prevEvCode == None: prevEvCode = "" - - if self.options.compatibility == 'append': - elEvCode = prevEvCode +";\n"+ evCode - if self.options.compatibility == 'prepend': - elEvCode = evCode +";\n"+ prevEvCode - - el.set( self.options.when, elEvCode ) - -if __name__ == '__main__': - e = InkWebTransmitAtt() - e.affect() - diff --git a/share/extensions/webslicer_create_group.inx b/share/extensions/webslicer_create_group.inx deleted file mode 100644 index aaa327ea7..000000000 --- a/share/extensions/webslicer_create_group.inx +++ /dev/null @@ -1,39 +0,0 @@ -<?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="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 deleted file mode 100755 index 567c911aa..000000000 --- a/share/extensions/webslicer_create_group.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2010 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -from webslicer_effect import * -import inkex - -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="") - self.OptionParser.add_option("--html-class", - action="store", type="string", - dest="html_class", - help="") - self.OptionParser.add_option("--width-unity", - action="store", type="string", - dest="width_unity", - help="") - self.OptionParser.add_option("--height-unity", - action="store", type="string", - dest="height_unity", - help="") - self.OptionParser.add_option("--bg-color", - 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() - if is_empty(self.layer): - inkex.errormsg(_('You must create and select some "Slicer rectangles" before trying to group.')) - exit(3) - self.layer_descendants = self.get_descendants_in_array(self.layer) - - - def get_descendants_in_array(self, el): - descendants = el.getchildren() - for e in descendants: - descendants.extend( self.get_descendants_in_array(e) ) - return descendants - - - def effect(self): - self.get_base_elements() - if len(self.selected) == 0: - inkex.errormsg(_('You must to select some "Slicer rectangles" or other "Layout groups".')) - exit(1) - for id,node in self.selected.iteritems(): - if node not in self.layer_descendants: - inkex.errormsg(_('Oops... The element "%s" is not in the Web Slicer layer') % id) - exit(2) - g_parent = self.getParentNode(node) - group = inkex.etree.SubElement(g_parent, 'g') - desc = inkex.etree.SubElement(group, 'desc') - desc.text = self.get_conf_text_from_list( - [ 'html_id', 'html_class', - 'width_unity', 'height_unity', - 'bg_color' ] ) - - for id,node in self.selected.iteritems(): - group.insert( 1, node ) - - -if __name__ == '__main__': - e = WebSlicer_CreateGroup() - e.affect() diff --git a/share/extensions/webslicer_create_rect.inx b/share/extensions/webslicer_create_rect.inx deleted file mode 100644 index 85578e24e..000000000 --- a/share/extensions/webslicer_create_rect.inx +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Create a slicer rectangle</_name> - <id>org.inkscape.web.slicer.create-rect</id> - <dependency type="executable" location="extensions">webslicer_effect.py</dependency> - <dependency type="executable" location="extensions">webslicer_create_rect.py</dependency> - <dependency type="executable" location="extensions">inkex.py</dependency> - <param name="name" type="string" _gui-text="Name:"></param> - <param name="format" type="enum" _gui-text="Format:"> - <item value="png">PNG</item> - <item value="jpg">JPG</item> - <item value="gif">GIF</item> - </param> - <param name="dpi" type="float" min="1" max="9999" _gui-text="DPI:">96</param> - <param name="dimension" type="string" _gui-text="Force Dimension:"></param> -<!-- i18n. Description duplicated in a fake value attribute in order to make it translatable --> - <param name="help-dimension1" type="description" _value="Force Dimension must be set as <width>x<height>">Force Dimension must be set as <width>x<height></param> - <_param name="help-dimension2" type="description">If set, this will replace DPI.</_param> - <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" appearance="header">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" appearance="header">GIF specific options</_param> - <param name="gif-type" type="enum" _gui-text="Type:"> - <_item value="grayscale">Grayscale</_item> - <_item value="palette">Palette</_item> - </param> - <param name="palette-size" type="int" min="2" max="256" _gui-text="Palette size:">256</param> - </page> - <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" appearance="header">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> - <_item value="bg-parent-repeat-x">Background — repeat horizontally (on parent group)</_item> - <_item value="bg-parent-repeat-y">Background — repeat vertically (on parent group)</_item> - <_item value="bg-parent-norepeat">Background — no repeat (on parent group)</_item> - <_item value="img-pos">Positioned Image</_item> - <_item value="img-nonpos">Non Positioned Image</_item> - <_item value="img-float-left">Left Floated Image</_item> - <_item value="img-float-right">Right Floated Image</_item> - </param> - <param name="layout-position-anchor" type="enum" _gui-text="Position anchor:"> - <_item value="tl">Top and Left</_item> - <_item value="tc">Top and Center</_item> - <_item value="tr">Top and right</_item> - <_item value="ml">Middle and Left</_item> - <_item value="mc">Middle and Center</_item> - <_item value="mr">Middle and Right</_item> - <_item value="bl">Bottom and Left</_item> - <_item value="bc">Bottom and Center</_item> - <_item value="br">Bottom and Right</_item> - </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_rect.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/webslicer_create_rect.py b/share/extensions/webslicer_create_rect.py deleted file mode 100755 index 865b74304..000000000 --- a/share/extensions/webslicer_create_rect.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2010 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# local library -from webslicer_effect import * -import inkex - -class WebSlicer_CreateRect(WebSlicer_Effect): - - def __init__(self): - WebSlicer_Effect.__init__(self) - self.OptionParser.add_option("--name", - action="store", type="string", - dest="name", - help="") - self.OptionParser.add_option("--format", - action="store", type="string", - dest="format", - help="") - self.OptionParser.add_option("--dpi", - action="store", type="int", - dest="dpi", - help="") - self.OptionParser.add_option("--dimension", - action="store", type="string", - dest="dimension", - help="") - self.OptionParser.add_option("--bg-color", - action="store", type="string", - dest="bg_color", - help="") - self.OptionParser.add_option("--quality", - action="store", type="int", - dest="quality", - help="") - self.OptionParser.add_option("--gif-type", - action="store", type="string", - dest="gif_type", - help="") - self.OptionParser.add_option("--palette-size", - action="store", type="int", - dest="palette_size", - help="") - self.OptionParser.add_option("--html-id", - action="store", type="string", - dest="html_id", - help="") - self.OptionParser.add_option("--html-class", - action="store", type="string", - dest="html_class", - help="") - self.OptionParser.add_option("--layout-disposition", - action="store", type="string", - dest="layout_disposition", - help="") - self.OptionParser.add_option("--layout-position-anchor", - action="store", type="string", - dest="layout_position_anchor", - help="") - # inkscape param workarround - self.OptionParser.add_option("--tab") - - - def unique_slice_name(self): - name = self.options.name - el = self.document.xpath( '//*[@id="'+name+'"]', namespaces=inkex.NSS ) - if len(el) > 0: - if name[-3:] == '-00': name = name[:-3] - num = 0 - num_s = '00' - while len(el) > 0: - num += 1 - num_s = str(num) - if len(num_s)==1 : num_s = '0'+num_s - el = self.document.xpath( '//*[@id="'+name+'-'+num_s+'"]', - namespaces=inkex.NSS ) - self.options.name = name+'-'+num_s - - - def validate_options(self): - self.options.format = self.options.ensure_value('format', 'png').lower() - if not is_empty( self.options.dimension ): - self.options.dimension - - def effect(self): - scale = self.unittouu('1px') # convert to document units - self.validate_options() - layer = self.get_slicer_layer(True) - #TODO: get selected elements to define location and size - rect = inkex.etree.SubElement(layer, 'rect') - if is_empty(self.options.name): - self.options.name = 'slice-00' - self.unique_slice_name() - rect.set('id', self.options.name) - rect.set('fill', 'red') - rect.set('opacity', '0.5') - rect.set('x', str(-scale*100)) - rect.set('y', str(-scale*100)) - rect.set('width', str(scale*200)) - rect.set('height', str(scale*200)) - desc = inkex.etree.SubElement(rect, 'desc') - conf_txt = "format:"+ self.options.format +"\n" - if not is_empty(self.options.dpi): - conf_txt += "dpi:" + str(self.options.dpi) +"\n" - if not is_empty(self.options.html_id): - conf_txt += "html-id:" + self.options.html_id - desc.text = self.get_conf_text_from_list( self.get_conf_list() ) - - - def get_conf_list(self): - conf_list = [ 'format' ] - if self.options.format == 'gif': - conf_list.extend( [ 'gif_type', 'palette_size' ] ) - if self.options.format == 'jpg': - conf_list.extend( [ 'quality' ] ) - conf_list.extend( [ - 'dpi', 'dimension', - 'bg_color', 'html_id', 'html_class', - 'layout_disposition', 'layout_position_anchor' - ] ) - return conf_list - - - -if __name__ == '__main__': - e = WebSlicer_CreateRect() - e.affect() diff --git a/share/extensions/webslicer_effect.py b/share/extensions/webslicer_effect.py deleted file mode 100755 index acb78fcbd..000000000 --- a/share/extensions/webslicer_effect.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2010 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' - -import inkex - - -def is_empty(val): - if val is None: - return True - else: - return len(str(val)) == 0 - - -class WebSlicer_Effect(inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - - def get_slicer_layer(self, force_creation=False): - # Test if webslicer-layer layer existis - layer = self.document.xpath( - '//*[@id="webslicer-layer" and @inkscape:groupmode="layer"]', - namespaces=inkex.NSS) - if len(layer) is 0: - if force_creation: - # Create a new layer - layer = inkex.etree.SubElement(self.document.getroot(), 'g') - layer.set('id', 'webslicer-layer') - layer.set(inkex.addNS('label', 'inkscape'), 'Web Slicer') - layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer') - else: - layer = None - else: - layer = layer[0] - return layer - - def get_conf_text_from_list(self, conf_atts): - conf_list = [] - for att in conf_atts: - if not is_empty(getattr(self.options, att)): - conf_list.append( - att.replace('_','-') +': '+ str(getattr(self.options, att)) - ) - return "\n".join( conf_list ) - diff --git a/share/extensions/webslicer_export.inx b/share/extensions/webslicer_export.inx deleted file mode 100644 index f20f66637..000000000 --- a/share/extensions/webslicer_export.inx +++ /dev/null @@ -1,29 +0,0 @@ -<?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="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 optionally - 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> - </effects-menu> - </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 deleted file mode 100755 index 9acb9d6c3..000000000 --- a/share/extensions/webslicer_export.py +++ /dev/null @@ -1,441 +0,0 @@ -#!/usr/bin/env python -''' -Copyright (C) 2010 Aurelio A. Heckert, aurium (a) gmail dot 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -# standard library -import os -import sys -import tempfile -# local library -from webslicer_effect import * -import inkex - - -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", - help="") - self.OptionParser.add_option("--create-dir", - action="store", type="inkbool", - default=False, - dest="create_dir", - help="") - self.OptionParser.add_option("--with-code", - action="store", type="inkbool", - default=False, - dest="with_code", - help="") - - - svgNS = '{http://www.w3.org/2000/svg}' - - - def validate_inputs(self): - # The user must supply a directory to export: - if is_empty( self.options.dir ): - inkex.errormsg(_('You must give a directory to export the slices.')) - return {'error':'You must give a directory to export the slices.'} - # No directory separator at the path end: - if self.options.dir[-1] == '/' or self.options.dir[-1] == '\\': - self.options.dir = self.options.dir[0:-1] - # Test if the directory exists: - if not os.path.exists( self.options.dir ): - if self.options.create_dir: - # Try to create it: - try: - os.makedirs( self.options.dir ) - 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.'} - else: - inkex.errormsg(_('The directory "%s" does not exists.') % self.options.dir) - return - # Check whether slicer layer exists (bug #1198826) - slicer_layer = self.get_slicer_layer() - if slicer_layer is None: - inkex.errormsg(_('No slicer layer found.')) - return {'error':'No slicer layer found.'} - else: - self.unique_html_id( slicer_layer ) - 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(): - if child.tag in [ self.svgNS+'rect', self.svgNS+'path', - self.svgNS+'circle', self.svgNS+'g' ]: - conf = self.get_el_conf(child) - if conf['html-id'] in self._html_ids: - inkex.errormsg( - _('You have more than one element with "%s" html-id.') % - conf['html-id'] ) - n = 2 - while (conf['html-id']+"-"+str(n)) in self._html_ids: n += 1 - conf['html-id'] += "-"+str(n) - self._html_ids.append( conf['html-id'] ) - self.save_conf( conf, child ) - self.unique_html_id( child ) - - - def test_if_has_imagemagick(self): - (status, output) = self.get_cmd_output('convert --version') - self.has_magick = ( status == 0 and 'ImageMagick' in output ) - - - def effect(self): - self.test_if_has_imagemagick() - error = self.validate_inputs() - if error: return error - # Register the basic CSS code: - self.reg_css( 'body', 'text-align', 'center' ) - # Create the temporary SVG with invisible Slicer layer to export image pieces - self.create_the_temporary_svg() - # Start what we really want! - self.export_chids_of( self.get_slicer_layer() ) - # Write the HTML and CSS files if asked for: - if self.options.with_code: - self.make_html_file() - self.make_css_file() - # Delete the temporary SVG with invisible Slicer layer - self.delete_the_temporary_svg() - #TODO: prevent inkex to return svg code to update Inkscape - - - def make_html_file(self): - f = open(os.path.join(self.options.dir,'layout.html'), 'w') - f.write( - '<html>\n<head>\n' +\ - ' <title>Web Layout Testing</title>\n' +\ - ' <style type="text/css" media="screen">\n' +\ - ' @import url("style.css")\n' +\ - ' </style>\n' +\ - '</head>\n<body>\n' +\ - self.html_code() +\ - ' <p style="position:absolute; bottom:10px">\n' +\ - ' This HTML code is not done to the web. <br/>\n' +\ - ' The automatic HTML and CSS code are only a helper.' +\ - '</p>\n</body>\n</html>' ) - f.close() - - - def make_css_file(self): - f = open(os.path.join(self.options.dir,'style.css'), 'w') - f.write( - '/*\n' +\ - '** This CSS code is not done to the web.\n' +\ - '** The automatic HTML and CSS code are only a helper.\n' +\ - '*/\n' +\ - self.css_code() ) - f.close() - - - def create_the_temporary_svg(self): - (ref, self.tmp_svg) = tempfile.mkstemp('.svg') - layer = self.get_slicer_layer() - current_style = ('style' in layer.attrib) and layer.attrib['style'] or '' - layer.attrib['style'] = 'display:none' - self.document.write( self.tmp_svg ); - layer.attrib['style'] = current_style - - - def delete_the_temporary_svg(self): - os.remove( self.tmp_svg ) - - - noid_element_count = 0 - def get_el_conf(self, el): - desc = el.find(self.svgNS+'desc') - conf = {} - if desc is None: - desc = inkex.etree.SubElement(el, 'desc') - if desc.text is None: - desc.text = '' - for line in desc.text.split("\n"): - if line.find(':') > 0: - line = line.split(':') - conf[line[0].strip()] = line[1].strip() - if not 'html-id' in conf: - if el == self.get_slicer_layer(): - return {'html-id':'#body#'} - else: - self.noid_element_count += 1 - conf['html-id'] = 'element-'+str(self.noid_element_count) - desc.text += "\nhtml-id:"+conf['html-id'] - return conf - - - def save_conf(self, conf, el): - desc = el.find('{http://www.w3.org/2000/svg}desc') - if desc is not None: - conf_a = [] - for k in conf: - conf_a.append( k+' : '+conf[k] ) - desc.text = "\n".join(conf_a) - - - def export_chids_of(self, parent): - parent_id = self.get_el_conf( parent )['html-id'] - for el in parent.getchildren(): - el_conf = self.get_el_conf( el ) - if el.tag == self.svgNS+'g': - if self.options.with_code: - self.register_group_code( el, el_conf ) - else: - self.export_chids_of( el ) - if el.tag in [ self.svgNS+'rect', self.svgNS+'path', self.svgNS+'circle' ]: - if self.options.with_code: - self.register_unity_code( el, el_conf, parent_id ) - self.export_img( el, el_conf ) - - - def register_group_code(self, group, conf): - self.reg_html('div', group) - selec = '#'+conf['html-id'] - self.reg_css( selec, 'position', 'absolute' ) - geometry = self.get_relative_el_geometry(group) - self.reg_css( selec, 'top', str(int(geometry['y']))+'px' ) - self.reg_css( selec, 'left', str(int(geometry['x']))+'px' ) - self.reg_css( selec, 'width', str(int(geometry['w']))+'px' ) - self.reg_css( selec, 'height', str(int(geometry['h']))+'px' ) - self.export_chids_of( group ) - - - def __validate_slice_conf(self, conf): - if not 'layout-disposition' in conf: - conf['layout-disposition'] = 'bg-el-norepeat' - if not 'layout-position-anchor' in conf: - conf['layout-position-anchor'] = 'mc' - return conf - - - def register_unity_code(self, el, conf, parent_id): - conf = self.__validate_slice_conf(conf) - css_selector = '#'+conf['html-id'] - bg_repeat = 'no-repeat' - img_name = self.img_name(el, conf) - if conf['layout-disposition'][0:2] == 'bg': - if conf['layout-disposition'][0:9] == 'bg-parent': - if parent_id == '#body#': - css_selector = 'body' - else: - css_selector = '#'+parent_id - if conf['layout-disposition'] == 'bg-parent-repeat': - bg_repeat = 'repeat' - if conf['layout-disposition'] == 'bg-parent-repeat-x': - bg_repeat = 'repeat-x' - if conf['layout-disposition'] == 'bg-parent-repeat-y': - bg_repeat = 'repeat-y' - lay_anchor = conf['layout-position-anchor'] - if lay_anchor == 'tl': lay_anchor = 'top left' - if lay_anchor == 'tc': lay_anchor = 'top center' - if lay_anchor == 'tr': lay_anchor = 'top right' - if lay_anchor == 'ml': lay_anchor = 'middle left' - if lay_anchor == 'mc': lay_anchor = 'middle center' - if lay_anchor == 'mr': lay_anchor = 'middle right' - if lay_anchor == 'bl': lay_anchor = 'bottom left' - if lay_anchor == 'bc': lay_anchor = 'bottom center' - if lay_anchor == 'br': lay_anchor = 'bottom right' - self.reg_css( css_selector, 'background', - 'url("%s") %s %s' % (img_name, bg_repeat, lay_anchor) ) - else: # conf['layout-disposition'][0:9] == 'bg-el...' - self.reg_html('div', el) - self.reg_css( css_selector, 'background', - 'url("%s") %s' % (img_name, 'no-repeat') ) - self.reg_css( css_selector, 'position', 'absolute' ) - geo = self.get_relative_el_geometry(el,True) - self.reg_css( css_selector, 'top', geo['y'] ) - self.reg_css( css_selector, 'left', geo['x'] ) - self.reg_css( css_selector, 'width', geo['w'] ) - self.reg_css( css_selector, 'height', geo['h'] ) - else: # conf['layout-disposition'] == 'img...' - self.reg_html('img', el) - if conf['layout-disposition'] == 'img-pos': - self.reg_css( css_selector, 'position', 'absolute' ) - geo = self.get_relative_el_geometry(el) - self.reg_css( css_selector, 'left', str(geo['x'])+'px' ) - self.reg_css( css_selector, 'top', str(geo['y'])+'px' ) - if conf['layout-disposition'] == 'img-float-left': - self.reg_css( css_selector, 'float', 'right' ) - if conf['layout-disposition'] == 'img-float-right': - self.reg_css( css_selector, 'float', 'right' ) - - - el_geo = { } - def register_all_els_geometry(self): - ink_cmm = 'inkscape --query-all '+self.tmp_svg - (status, output) = self.get_cmd_output( ink_cmm ) - self.el_geo = { } - if status == 0: - for el in output.split('\n'): - el = el.split(',') - if len(el) == 5: - self.el_geo[el[0]] = { 'x':float(el[1]), 'y':float(el[2]), - 'w':float(el[3]), 'h':float(el[4]) } - doc_w = self.unittouu( self.document.getroot().get('width') ) - doc_h = self.unittouu( self.document.getroot().get('height') ) - self.el_geo['webslicer-layer'] = { 'x':0, 'y':0, 'w':doc_w, 'h':doc_h } - - - def get_relative_el_geometry(self, el, value_to_css=False): - # This method return a dictionary with x, y, w and h keys. - # All values are float, if value_to_css is False, otherwise - # that is a string ended with "px". The x and y values are - # relative to parent position. - if not self.el_geo: self.register_all_els_geometry() - parent = self.getParentNode(el) - geometry = self.el_geo[el.attrib['id']] - geometry['x'] -= self.el_geo[parent.attrib['id']]['x'] - geometry['y'] -= self.el_geo[parent.attrib['id']]['y'] - if value_to_css: - for k in geometry: geometry[k] = str(int(geometry[k]))+'px' - return geometry - - - def img_name(self, el, conf): - return el.attrib['id']+'.'+conf['format'] - - - def export_img(self, el, conf): - if not self.has_magick: - inkex.errormsg(_('You must install the ImageMagick to get JPG and GIF.')) - conf['format'] = 'png' - img_name = os.path.join( self.options.dir, self.img_name(el, conf) ) - img_name_png = img_name - if conf['format'] != 'png': - img_name_png = img_name+'.png' - opts = '' - if 'bg-color' in conf: opts += ' -b "'+conf['bg-color']+'" -y 1' - if 'dpi' in conf: opts += ' -d '+conf['dpi'] - if 'dimension' in conf: - dim = conf['dimension'].split('x') - opts += ' -w '+dim[0]+' -h '+dim[1] - (status, output) = self.get_cmd_output( - 'inkscape %s -i "%s" -e "%s" "%s"' % ( - opts, el.attrib['id'], img_name_png, self.tmp_svg - ) - ) - if conf['format'] != 'png': - opts = '' - if conf['format'] == 'jpg': - opts += ' -quality '+str(conf['quality']) - if conf['format'] == 'gif': - if conf['gif-type'] == 'grayscale': - opts += ' -type Grayscale' - else: - opts += ' -type Palette' - if conf['palette-size'] < 256: - opts += ' -colors '+str(conf['palette-size']) - (status, output) = self.get_cmd_output( - 'convert "%s" %s "%s"' % ( img_name_png, opts, img_name ) - ) - if status != 0: - inkex.errormsg('Upss... ImageMagick error: '+output) - os.remove(img_name_png) - - - _html = {} - def reg_html(self, el_tag, el): - parent = self.getParentNode( el ) - parent_id = self.get_el_conf( parent )['html-id'] - if parent == self.get_slicer_layer(): parent_id = 'body' - conf = self.get_el_conf( el ) - el_id = conf['html-id'] - if 'html-class' in conf: - el_class = conf['html-class'] - else: - el_class = '' - if not parent_id in self._html: self._html[parent_id] = [] - self._html[parent_id].append({ 'tag':el_tag, 'id':el_id, 'class':el_class }) - - - def html_code(self, parent='body', ident=' '): - #inkex.errormsg( self._html ) - if not parent in self._html: return '' - code = '' - for el in self._html[parent]: - child_code = self.html_code(el['id'], ident+' ') - tag_class = '' - if el['class'] != '': tag_class = ' class="'+el['class']+'"' - if el['tag'] == 'img': - code += ident+'<img id="'+el['id']+'"'+tag_class+\ - ' src="'+self.img_name(el, self.get_el_conf(el))+'"/>\n' - else: - code += ident+'<'+el['tag']+' id="'+el['id']+'"'+tag_class+'>\n' - if child_code: - code += child_code - else: - code += ident+' Element '+el['id']+'\n' - code += ident+'</'+el['tag']+'><!-- id="'+el['id']+'" -->\n' - return code - - - _css = [] - def reg_css(self, selector, att, val): - pos = i = -1 - for s in self._css: - i += 1 - if s['selector'] == selector: pos = i - if pos == -1: - pos = i + 1 - self._css.append({ 'selector':selector, 'atts':{} }) - if not att in self._css[pos]['atts']: self._css[pos]['atts'][att] = [] - self._css[pos]['atts'][att].append( val ) - - - def css_code(self): - code = '' - for s in self._css: - code += '\n'+s['selector']+' {\n' - for att in s['atts']: - val = s['atts'][att] - if att == 'background' and len(val) > 1: - code += ' /* the next attribute needs a CSS3 enabled browser */\n' - code += ' '+ att +': '+ (', '.join(val)) +';\n' - code += '}\n' - return code - - - def output(self): - # Cancel document serialization to stdout - pass - - -if __name__ == '__main__': - e = WebSlicer_Export() - e.affect() diff --git a/share/extensions/whirl.inx b/share/extensions/whirl.inx deleted file mode 100644 index a7de60f2b..000000000 --- a/share/extensions/whirl.inx +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Whirl</_name> - <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="rotation" type="boolean" _gui-text="Rotation is clockwise">true</param> - <effect> - <object-type>path</object-type> - <effects-menu> - <submenu _name="Modify Path"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">whirl.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/whirl.py b/share/extensions/whirl.py deleted file mode 100755 index 93e04c60d..000000000 --- a/share/extensions/whirl.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -''' -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import math, inkex, cubicsuperpath -from simpletransform import computePointInNode - -class Whirl(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("-t", "--whirl", - action="store", type="float", - dest="whirl", default=1.0, - help="amount of whirl") - self.OptionParser.add_option("-r", "--rotation", - action="store", type="inkbool", - dest="rotation", default=True, - help="direction of rotation") - def effect(self): - view_center = computePointInNode(list(self.view_center), self.current_layer) - for id, node in self.selected.iteritems(): - rotation = -1 - if self.options.rotation == True: - rotation = 1 - whirl = self.options.whirl / 1000 - if node.tag == inkex.addNS('path','svg'): - d = node.get('d') - p = cubicsuperpath.parsePath(d) - for sub in p: - for csp in sub: - for point in csp: - point[0] -= view_center[0] - point[1] -= view_center[1] - dist = math.sqrt((point[0] ** 2) + (point[1] ** 2)) - if dist != 0: - a = rotation * dist * whirl - theta = math.atan2(point[1], point[0]) + a - point[0] = (dist * math.cos(theta)) - point[1] = (dist * math.sin(theta)) - point[0] += view_center[0] - point[1] += view_center[1] - node.set('d',cubicsuperpath.formatPath(p)) - -if __name__ == '__main__': - e = Whirl() - e.affect() - - -# 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 deleted file mode 100644 index 6702657e3..000000000 --- a/share/extensions/wireframe_sphere.inx +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Wireframe Sphere</_name> - <id>il.wireframesphere</id> - <dependency type="executable" location="extensions">wireframe_sphere.py</dependency> - <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="hide_back" type="boolean" _gui-text="Hide lines behind the sphere">false</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu _name="Render"/> - </effects-menu> - </effect> - <script> - <command reldir="extensions" interpreter="python">wireframe_sphere.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/wireframe_sphere.py b/share/extensions/wireframe_sphere.py deleted file mode 100755 index 840978f80..000000000 --- a/share/extensions/wireframe_sphere.py +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env python -# -*- coding: UTF-8 -*- -''' -Copyright (C) 2009 John Beard john.j.beard@gmail.com - -######DESCRIPTION###### - -This extension renders a wireframe sphere constructed from lines of latitude -and lines of longitude. - -The number of lines of latitude and longitude is independently variable. Lines -of latitude and longtude are in separate subgroups. The whole figure is also in -its own group. - -The whole sphere can be tilted towards or away from the veiwer by a given -number of degrees. If the whole sphere is then rotated normally in Inkscape, -any position can be achieved. - -There is an option to hide the lines at the back of the sphere, as if the -sphere were opaque. - #FIXME: Lines of latitude only have an approximation of the function needed - to hide the back portion. If you can derive the proper equation, - please add it in. - Line of longitude have the exact method already. - Workaround: Use the Inkscape ellipse tool to edit the start and end - points of the lines of latitude to end at the horizon circle. - - -#TODO: Add support for odd numbers of lines of longitude. This means breaking - the line at the poles, and having two half ellipses for each line. - The angles at which the ellipse arcs pass the poles are not constant and - need to be derived before this can be implemented. -#TODO: Add support for prolate and oblate spheroids - -######LICENCE####### -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -######VERSION HISTORY##### - Ver. Date Notes - - 0.10 2009-10-25 First version. Basic spheres supported. - Hidden lines of latitude still not properly calculated. - Prolate and oblate spheroids not considered. -''' -# standard library -from math import * -# local library -import inkex -import simplestyle -from simpletransform import computePointInNode - - -#SVG OUTPUT FUNCTIONS ================================================ -def draw_SVG_ellipse((rx, ry), (cx, cy), width, parent, start_end=(0,2*pi),transform='' ): - - style = { 'stroke' : '#000000', - 'stroke-width' : str(width), - 'fill' : 'none' } - circ_attribs = {'style':simplestyle.formatStyle(style), - inkex.addNS('cx','sodipodi') :str(cx), - inkex.addNS('cy','sodipodi') :str(cy), - inkex.addNS('rx','sodipodi') :str(rx), - inkex.addNS('ry','sodipodi') :str(ry), - inkex.addNS('start','sodipodi') :str(start_end[0]), - inkex.addNS('end','sodipodi') :str(start_end[1]), - inkex.addNS('open','sodipodi') :'true', #all ellipse sectors we will draw are open - inkex.addNS('type','sodipodi') :'arc', - 'transform' :transform - - } - circ = inkex.etree.SubElement(parent, inkex.addNS('path','svg'), circ_attribs ) - -class Wireframe_Sphere(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - - #PARSE OPTIONS - self.OptionParser.add_option("--num_lat", - action="store", type="int", - dest="NUM_LAT", default=19) - self.OptionParser.add_option("--num_long", - action="store", type="int", - dest="NUM_LONG", default=24) - self.OptionParser.add_option("--radius", - action="store", type="float", - dest="RADIUS", default=100.0) - self.OptionParser.add_option("--tilt", - action="store", type="float", - dest="TILT", default=35.0) - self.OptionParser.add_option("--rotation", - action="store", type="float", - dest="ROT_OFFSET", default=4) - self.OptionParser.add_option("--hide_back", - action="store", type="inkbool", - dest="HIDE_BACK", default=False) - - def effect(self): - - so = self.options - - #PARAMETER PROCESSING - - if so.NUM_LONG % 2 != 0: #lines of longitude are odd : abort - inkex.errormsg(_('Please enter an even number of lines of longitude.')) - else: - if so.TILT < 0: # if the tilt is backwards - flip = ' scale(1, -1)' # apply a vertical flip to the whole sphere - else: - flip = '' #no flip - - so.RADIUS = self.unittouu(str(so.RADIUS) + 'px') - so.TILT = abs(so.TILT)*(pi/180) #Convert to radians - so.ROT_OFFSET = so.ROT_OFFSET*(pi/180) #Convert to radians - stroke_width = self.unittouu('1px') - - EPSILON = 0.001 #add a tiny value to the ellipse radii, so that if we get a zero radius, the ellipse still shows up as a line - - #INKSCAPE GROUP TO CONTAIN EVERYTHING - - centre = tuple(computePointInNode(list(self.view_center), self.current_layer)) #Put in in the centre of the current view - grp_transform = 'translate' + str( centre ) + flip - grp_name = 'WireframeSphere' - 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 - - #LINES OF LONGITUDE - - if so.NUM_LONG > 0: #only process longitudes if we actually want some - - #GROUP FOR THE LINES OF LONGITUDE - grp_name = 'Lines of Longitude' - grp_attribs = {inkex.addNS('label','inkscape'):grp_name} - grp_long = inkex.etree.SubElement(grp, 'g', grp_attribs) - - delta_long = 360.0/so.NUM_LONG #angle between neighbouring lines of longitude in degrees - - for i in range(0,so.NUM_LONG/2): - long_angle = so.ROT_OFFSET + (i*delta_long)*(pi/180.0); #The longitude of this particular line in radians - if long_angle > pi: - long_angle -= 2*pi - width = so.RADIUS * cos(long_angle) - height = so.RADIUS * sin(long_angle) * sin(so.TILT) #the rise is scaled by the sine of the tilt - # length = sqrt(width*width+height*height) #by pythagorean theorem - # inverse = sin(acos(length/so.RADIUS)) - inverse = abs(sin(long_angle)) * cos(so.TILT) - - minorRad = so.RADIUS * inverse - minorRad=minorRad + EPSILON - - #calculate the rotation of the ellipse to get it to pass through the pole (in degrees) - rotation = atan(height/width)*(180.0/pi) - transform = "rotate("+str(rotation)+')' #generate the transform string - #the rotation will be applied about the group centre (the centre of the sphere) - - # remove the hidden side of the ellipses if required - # this is always exactly half the ellipse, but we need to find out which half - start_end = (0, 2*pi) #Default start and end angles -> full ellipse - if so.HIDE_BACK: - if long_angle <= pi/2: #cut out the half ellispse that is hidden - start_end = (pi/2, 3*pi/2) - else: - start_end = (3*pi/2, pi/2) - - #finally, draw the line of longitude - #the centre is always at the centre of the sphere - draw_SVG_ellipse( ( minorRad, so.RADIUS ), (0,0), stroke_width, grp_long , start_end,transform) - - # LINES OF LATITUDE - if so.NUM_LAT > 0: - - #GROUP FOR THE LINES OF LATITUDE - grp_name = 'Lines of Latitude' - grp_attribs = {inkex.addNS('label','inkscape'):grp_name} - grp_lat = inkex.etree.SubElement(grp, 'g', grp_attribs) - - - so.NUM_LAT = so.NUM_LAT + 1 #Account for the fact that we loop over N-1 elements - delta_lat = 180.0/so.NUM_LAT #Angle between the line of latitude (subtended at the centre) - - for i in range(1,so.NUM_LAT): - lat_angle=((delta_lat*i)*(pi/180)) #The angle of this line of latitude (from a pole) - - majorRad=so.RADIUS*sin(lat_angle) #The width of the LoLat (no change due to projection) - minorRad=so.RADIUS*sin(lat_angle) * sin(so.TILT) #The projected height of the line of latitude - minorRad=minorRad + EPSILON - - cy=so.RADIUS*cos(lat_angle) * cos(so.TILT) #The projected y position of the LoLat - cx=0 #The x position is just the center of the sphere - - if so.HIDE_BACK: - if lat_angle > so.TILT: #this LoLat is partially or fully visible - if lat_angle > pi-so.TILT: #this LoLat is fully visible - draw_SVG_ellipse((majorRad, minorRad), (cx,cy), stroke_width, grp_lat) - else: #this LoLat is partially visible - proportion = -(acos( tan(lat_angle - pi/2)/tan(pi/2 - so.TILT)) )/pi + 1 - start_end = ( pi/2 - proportion*pi, pi/2 + proportion*pi ) #make the start and end angles (mirror image around pi/2) - draw_SVG_ellipse((majorRad, minorRad), (cx,cy), stroke_width, grp_lat, start_end) - - else: #just draw the full lines of latitude - draw_SVG_ellipse((majorRad, minorRad), (cx,cy), stroke_width, grp_lat) - - - #THE HORIZON CIRCLE - draw_SVG_ellipse((so.RADIUS, so.RADIUS), (0,0), stroke_width, grp) #circle, centred on the sphere centre - -if __name__ == '__main__': - e = Wireframe_Sphere() - e.affect() - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/share/extensions/wmf_input.inx b/share/extensions/wmf_input.inx deleted file mode 100644 index db0f210e1..000000000 --- a/share/extensions/wmf_input.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Windows Metafile Input</_name> - <id>org.inkscape.input.wmf</id> - <dependency type="executable" location="extensions">uniconv-ext.py</dependency> - <input> - <extension>.wmf</extension> - <mimetype>application/x-wmf</mimetype> - <_filetypename>Windows Metafile (UC) (*.wmf)</_filetypename> - <_filetypetooltip>A popular graphics file format for clipart</_filetypetooltip> - </input> - <script> - <command reldir="extensions" interpreter="python">uniconv-ext.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/wmf_output.inx b/share/extensions/wmf_output.inx deleted file mode 100644 index bc43a82a9..000000000 --- a/share/extensions/wmf_output.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>Windows Metafile Input</_name> - <id>org.inkscape.output.wmf</id> - <dependency type="executable" location="extensions">wmf_output.py</dependency> - <output> - <extension>.wmf</extension> - <mimetype>application/x-wmf</mimetype> - <_filetypename>Windows Metafile (UC) (*.wmf)</_filetypename> - <_filetypetooltip>A popular graphics file format for clipart</_filetypetooltip> - </output> - <script> - <command reldir="extensions" interpreter="python">wmf_output.py</command> - </script> -</inkscape-extension> diff --git a/share/extensions/wmf_output.py b/share/extensions/wmf_output.py deleted file mode 100755 index 8d92b0518..000000000 --- a/share/extensions/wmf_output.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -wmf_output.py -Module for running UniConverter wmf exporting commands in Inkscape extensions - -Copyright (C) 2009 Nicolas Dufour (jazzynico) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -import sys -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 fileencoding=utf-8 textwidth=99
\ No newline at end of file diff --git a/share/extensions/xaml2svg.inx b/share/extensions/xaml2svg.inx deleted file mode 100644 index 366102907..000000000 --- a/share/extensions/xaml2svg.inx +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <_name>XAML Input</_name> - <id>org.inkscape.input.xaml</id> - <input> - <extension>.xaml</extension> - <mimetype>text/xml+xaml</mimetype> - <_filetypename>Microsoft XAML (*.xaml)</_filetypename> - <_filetypetooltip>Microsoft's GUI definition format</_filetypetooltip> - <output_extension>org.inkscape.output.xaml</output_extension> - </input> - <xslt> - <file reldir="extensions">xaml2svg.xsl</file> - </xslt> -</inkscape-extension> diff --git a/share/extensions/xaml2svg.xsl b/share/extensions/xaml2svg.xsl deleted file mode 100644 index 8c0e4a5c9..000000000 --- a/share/extensions/xaml2svg.xsl +++ /dev/null @@ -1,107 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- -Copyright (c) 2005-2007 Toine de Greef (a.degreef@chello.nl) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -Version history: - -20070907 Initial release -20070912 Removed NaN as viewBox values - ---> - -<xsl:stylesheet version="1.0" -xmlns:xsl="http://www.w3.org/1999/XSL/Transform" -xmlns:xlink="http://www.w3.org/1999/xlink" -xmlns:svg="http://www.w3.org/2000/svg" -xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" -xmlns:msxsl="urn:schemas-microsoft-com:xslt"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="UTF-8"/> -<xsl:include href="xaml2svg/animation.xsl" /> -<xsl:include href="xaml2svg/brushes.xsl" /> -<xsl:include href="xaml2svg/canvas.xsl" /> -<xsl:include href="xaml2svg/geometry.xsl" /> -<xsl:include href="xaml2svg/properties.xsl" /> -<xsl:include href="xaml2svg/shapes.xsl" /> -<xsl:include href="xaml2svg/transform.xsl" /> - -<xsl:template match="/"> - <svg> - <xsl:attribute name="overflow">visible</xsl:attribute> - <xsl:variable name="viewBox"><xsl:apply-templates mode="boundingbox" /></xsl:variable> - <xsl:if test="system-property('xsl:vendor') = 'Microsoft' and (msxsl:node-set($viewBox)/boundingbox/@x1 != '') and (msxsl:node-set($viewBox)/boundingbox/@x2 != '') and (msxsl:node-set($viewBox)/boundingbox/@y1 != '') and (msxsl:node-set($viewBox)/boundingbox/@y2 != '')"> - <xsl:attribute name="viewBox"> - <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" /> - <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@y1, ' ')" /> - <xsl:value-of select="concat(msxsl:node-set($viewBox)/boundingbox/@x2 - msxsl:node-set($viewBox)/boundingbox/@x1, ' ')" /> - <xsl:value-of select="msxsl:node-set($viewBox)/boundingbox/@y2 - msxsl:node-set($viewBox)/boundingbox/@y1" /> - </xsl:attribute> - </xsl:if> - <xsl:apply-templates mode="svg" /> - </svg> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Image']"> - <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if> - <image> - <xsl:if test="@Source"><xsl:attribute name="xlink:href"><xsl:value-of select="@Source" /></xsl:attribute></xsl:if> - <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if> - <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </image> - <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'TextBlock']"> - <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="concat('<svg x="', @Canvas.Left, '" y="', @Canvas.Top, '">')" /></xsl:if> - <text> - <xsl:if test="@FontSize"><xsl:attribute name="font-size"><xsl:value-of select="@FontSize" /></xsl:attribute></xsl:if> - <xsl:if test="@FontWeight"><xsl:attribute name="font-weight"><xsl:value-of select="@FontWeight" /></xsl:attribute></xsl:if> - <xsl:if test="@FontFamily"><xsl:attribute name="font-family"><xsl:value-of select="@FontFamily" /></xsl:attribute></xsl:if> - <xsl:if test="@FontStyle"><xsl:attribute name="font-style"><xsl:value-of select="@FontStyle" /></xsl:attribute></xsl:if> - <xsl:if test="@Foreground"><xsl:attribute name="fill"><xsl:value-of select="@Foreground" /></xsl:attribute></xsl:if> - <xsl:if test="@Width"><xsl:attribute name="width"><xsl:value-of select="@Width" /></xsl:attribute></xsl:if> - <xsl:if test="@Height"><xsl:attribute name="height"><xsl:value-of select="@Height" /></xsl:attribute></xsl:if> - <xsl:if test="@HorizontalAlignment"> - <xsl:attribute name="text-anchor"> - <xsl:choose> - <xsl:when test="@HorizontalAlignment = 'Left'">start</xsl:when> - <xsl:when test="@HorizontalAlignment = 'Center'">middle</xsl:when> - <xsl:when test="@HorizontalAlignment = 'Right'">end</xsl:when> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <xsl:attribute name="dominant-baseline">hanging</xsl:attribute> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates /> - </text> - <xsl:if test="@Canvas.Left or @Canvas.Top"><xsl:value-of disable-output-escaping="yes" select="'</svg> '" /></xsl:if> -</xsl:template> - -<xsl:template match="*"> -<xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/animation.xsl b/share/extensions/xaml2svg/animation.xsl deleted file mode 100644 index e51a430ba..000000000 --- a/share/extensions/xaml2svg/animation.xsl +++ /dev/null @@ -1,141 +0,0 @@ -<?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. ---> - -<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:def="Definition" -exclude-result-prefixes="def"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template name="template_animation"> - <xsl:if test="@From"><xsl:attribute name="from"><xsl:value-of select="@From" /></xsl:attribute></xsl:if> - <xsl:if test="@To"><xsl:attribute name="to"><xsl:value-of select="@To" /></xsl:attribute></xsl:if> - <xsl:if test="@Duration"><xsl:attribute name="dur"><xsl:value-of select="@Duration" /></xsl:attribute></xsl:if> - <xsl:if test="@RepeatDuration"><xsl:attribute name="repeatDur"><xsl:value-of select="translate(@RepeatDuration, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" /></xsl:attribute></xsl:if> - <xsl:if test="@RepeatCount"><xsl:attribute name="repeatCount"><xsl:value-of select="@RepeatCount" /></xsl:attribute></xsl:if> - <xsl:if test="@AutoReverse"> - <xsl:attribute name="fill"> - <xsl:choose> - <xsl:when test="@AutoReverse = 'True'">remove</xsl:when> - <xsl:otherwise>freeze</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<xsl:template name="template_timeline_animations"> - <xsl:variable name="id" select="@ID" /> - <xsl:variable name="name" select="@Name" /> - <xsl:apply-templates select="//*[name(.) = 'SetterTimeline' and ($id = @TargetID or $name = @TargetName)]" /> -</xsl:template> - -<xsl:template name="template_animation_path"> - <xsl:param name="target" /> - <xsl:choose> - <xsl:when test="$target = '(Line.X2)'">x2</xsl:when> - <xsl:when test="$target = '(Rectangle.Opacity)'">opacity</xsl:when> - </xsl:choose> -</xsl:template> - -<xsl:template match="*[name(.) = concat(name(..), '.Storyboards')]"> - <!--xsl:apply-templates /--> -</xsl:template> - -<xsl:template match="*[name(.) = 'ParallelTimeLine']"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'SetterTimeline']"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'ByteAnimationCollection' or name(.) = 'DecimalAnimationCollection' or name(.) = 'DoubleAnimationCollection' or name(.) = 'Int16AnimationCollection' or name(.) = 'Int32AnimationCollection' or name(.) = 'Int64AnimationCollection' or name(.) = 'LengthAnimationCollection' or name(.) = 'SingleAnimationCollection' or name(.) = 'SizeAnimationCollection' or name(.) = 'ThicknessAnimationCollection']"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'ByteAnimation' or name(.) = 'DecimalAnimation' or name(.) = 'DoubleAnimation' or name(.) = 'Int16Animation' or name(.) = 'Int32Animation' or name(.) = 'Int64Animation' or name(.) = 'LengthAnimation' or name(.) = 'SingleAnimation' or name(.) = 'SizeAnimation' or name(.) = 'ThicknessAnimation']"> - <xsl:choose> - <xsl:when test="../@Path"> - <animate> - <xsl:attribute name="attributeName"><xsl:call-template name="template_animation_path"><xsl:with-param name="target" select="../@Path" /></xsl:call-template></xsl:attribute> - <xsl:call-template name="template_animation" /> - </animate> - </xsl:when> - <xsl:when test="name(..) = concat(name(.), 'Collection')"> - <animate> - <xsl:attribute name="attributeName"><xsl:value-of select="translate(substring-after(name(../..), concat(name(../../..), '.')), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" /></xsl:attribute> - <xsl:call-template name="template_animation" /> - </animate> - </xsl:when> - <xsl:when test="name(..) = concat(name(../..), '.AngleAnimations')"> - <animateTransform attributeName="transform" type="rotate"> - <xsl:call-template name="template_animation" /> - </animateTransform> - </xsl:when> - </xsl:choose> -</xsl:template> - -<xsl:template match="*[name(.) = concat(name(..), '.ColorAnimations')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = concat(name(..), '.AngleAnimations')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'ColorAnimation']"> - <animateColor> - <xsl:if test="../@Path"> - <xsl:attribute name="attributeName"><xsl:call-template name="template_animation_path"><xsl:with-param name="target" select="../@Path" /></xsl:call-template></xsl:attribute> - </xsl:if> - <xsl:if test="name(..) = concat(name(../..), '.ColorAnimations')"> - <xsl:choose> - <xsl:when test="name(../..) = 'SolidColorBrush'"> - <xsl:attribute name="attributeName"> - <xsl:value-of select="translate(substring-after(name(../../..), concat(name(../../../..), '.')), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" /> - </xsl:attribute> - </xsl:when> - </xsl:choose> - </xsl:if> - <xsl:call-template name="template_animation" /> - </animateColor> -</xsl:template> - -<xsl:template match="*[name(.) = 'PointAnimation']"> - <animateMotion> - <xsl:if test="../@Path"> - <xsl:attribute name="attributeName"><xsl:call-template name="template_animation_path"><xsl:with-param name="target" select="../@Path" /></xsl:call-template></xsl:attribute> - </xsl:if> - <xsl:call-template name="template_animation" /> - </animateMotion> -</xsl:template> - -<xsl:template match="*[name(.) = 'RectAnimation']"> -<!-- --> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/brushes.xsl b/share/extensions/xaml2svg/brushes.xsl deleted file mode 100644 index 884d6db35..000000000 --- a/share/extensions/xaml2svg/brushes.xsl +++ /dev/null @@ -1,244 +0,0 @@ -<?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. ---> - -<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" -exclude-result-prefixes="x"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template mode="forward" match="*[name(.) = 'LinearGradientBrush']"> - <linearGradient> - <xsl:attribute name="id"> - <xsl:choose> - <xsl:when test="@x:Key"><xsl:value-of select="@x:Key" /></xsl:when> - <xsl:otherwise><xsl:value-of select="concat('id_', generate-id(..))" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:attribute name="gradientUnits"> - <xsl:choose> - <xsl:when test="@MappingMode = 'RelativeToBoundingBox' or not(@StartPoint and @EndPoint)"><xsl:value-of select="'boundingBox'" /></xsl:when> - <xsl:otherwise><xsl:value-of select="'userSpaceOnUse'" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:if test="@SpreadMethod"> - <xsl:attribute name="spreadMethod"> - <xsl:value-of select="translate(@SpreadMethod, 'PR', 'pr')" /> - </xsl:attribute> - </xsl:if> - <xsl:choose> - <xsl:when test="@MappingMode = 'Absolute' and @StartPoint and @EndPoint"> - <xsl:attribute name="x1"><xsl:value-of select="substring-before(@StartPoint,',')" /></xsl:attribute> - <xsl:attribute name="x1"><xsl:value-of select="substring-before(@StartPoint,',')" /></xsl:attribute> - <xsl:attribute name="y1"><xsl:value-of select="substring-after(@StartPoint,',')" /></xsl:attribute> - <xsl:attribute name="x2"><xsl:value-of select="substring-before(@EndPoint,',')" /></xsl:attribute> - <xsl:attribute name="y2"><xsl:value-of select="substring-after(@EndPoint,',')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@StartPoint and @EndPoint"> - <xsl:attribute name="x1"><xsl:value-of select="concat(100 * number(substring-before(@StartPoint,',')), '%')" /></xsl:attribute> - <xsl:attribute name="y1"><xsl:value-of select="concat(100 * number(substring-after(@StartPoint,',')), '%')" /></xsl:attribute> - <xsl:attribute name="x2"><xsl:value-of select="concat(100 * number(substring-before(@EndPoint,',')), '%')" /></xsl:attribute> - <xsl:attribute name="y2"><xsl:value-of select="concat(100 * number(substring-after(@EndPoint,',')), '%')" /></xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="x1"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="y1"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="x2"><xsl:value-of select="'100%'" /></xsl:attribute> - <xsl:attribute name="y2"><xsl:value-of select="'100%'" /></xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:call-template name="template_gradienttransform" /> - <xsl:apply-templates select="*[name(.) != 'Brush.Transform' and name(.) != concat(name(..), '.Transform') and name(.) != 'Brush.RelativeTransform' and name(.) != concat(name(..), '.RelativeTransform')]" /> - </linearGradient> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'RadialGradientBrush']"> - <radialGradient> - <xsl:attribute name="id"> - <xsl:choose> - <xsl:when test="@x:Key"><xsl:value-of select="@x:Key" /></xsl:when> - <xsl:otherwise><xsl:value-of select="concat('id_', generate-id(..))" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:attribute name="gradientUnits"> - <xsl:choose> - <xsl:when test="@MappingMode = 'RelativeToBoundingBox' or not(@StartPoint and @EndPoint)"><xsl:value-of select="'boundingBox'" /></xsl:when> - <xsl:otherwise><xsl:value-of select="'userSpaceOnUse'" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:if test="@SpreadMethod"> - <xsl:attribute name="spreadMethod"> - <xsl:value-of select="translate(@SpreadMethod, 'PR', 'pr')" /> - </xsl:attribute> - </xsl:if> - <xsl:if test="@Center"> - <xsl:attribute name="cx"><xsl:value-of select="substring-before(@Center, ',')" /></xsl:attribute> - <xsl:attribute name="cy"><xsl:value-of select="substring-after(@Center, ',')" /></xsl:attribute> - </xsl:if> - <xsl:if test="@GradientOrigin"> - <xsl:attribute name="fx"><xsl:value-of select="substring-before(@GradientOrigin, ',')" /></xsl:attribute> - <xsl:attribute name="fy"><xsl:value-of select="substring-after(@GradientOrigin, ',')" /></xsl:attribute> - </xsl:if> - <!-- Xamlon uses Focus --> - <xsl:if test="@Focus"> - <xsl:attribute name="fx"><xsl:value-of select="substring-before(@Focus, ',')" /></xsl:attribute> - <xsl:attribute name="fy"><xsl:value-of select="substring-after(@Focus, ',')" /></xsl:attribute> - </xsl:if> - <xsl:attribute name="r"><xsl:value-of select="@RadiusX" /></xsl:attribute> - <xsl:call-template name="template_gradienttransform" /> - <xsl:apply-templates select="*[name(.) != 'Brush.Transform' and name(.) != concat(name(..), '.Transform') and name(.) != 'Brush.RelativeTransform' and name(.) != concat(name(..), '.RelativeTransform')]" /> - </radialGradient> -</xsl:template> - -<xsl:template match="*[name(.) = 'GradientStopCollection' or name(.) = 'GradientBrush.GradientStops' or name(.) = concat(name(..), '.GradientStops')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'GradientStop']"> - <stop> - <xsl:if test="@Offset"><xsl:attribute name="offset"><xsl:value-of select="@Offset" /></xsl:attribute></xsl:if> - <xsl:if test="@Color"> - <xsl:attribute name="stop-color"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@Color" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@Color" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"><xsl:attribute name="stop-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute></xsl:if> - </xsl:if> - </stop> -</xsl:template> - -<xsl:template match="*[name(.) = 'SolidColorBrush']"> - <xsl:call-template name="template_properties" /> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'ImageBrush']"> - <defs> - <pattern> - <xsl:choose> - <xsl:when test="@TileMode != 'none' and @Viewport and @ViewportUnits = 'Absolute'"> - <xsl:attribute name="patternUnits">userSpaceOnUse</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="substring-before(@Viewport, ',')" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="substring-before(substring-after(@Viewport, ','), ',')" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@TileMode != 'none' and @Viewport"> - <xsl:attribute name="patternUnits">boundingBox</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="concat(100 * number(substring-before(@Viewport, ',')), '%')" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="concat(100 * number(substring-before(substring-after(@Viewport, ','), ',')), '%')" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="concat(100 * number(substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="concat(100 * number(substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@Viewport and ../../@Width and ../../@Height"> - <xsl:attribute name="patternUnits">userSpaceOnUse</xsl:attribute> - <xsl:attribute name="x">0</xsl:attribute> - <xsl:attribute name="y">0</xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="../../@Width" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="../../@Height" /></xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="patternUnits">boundingBox </xsl:attribute> - <xsl:attribute name="x">0</xsl:attribute> - <xsl:attribute name="y">0</xsl:attribute> - <xsl:attribute name="width">100%</xsl:attribute> - <xsl:attribute name="height">100%</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:attribute name="id"><xsl:value-of select="concat('id_', generate-id(..))" /></xsl:attribute> - <image> - <xsl:attribute name="xlink:href"><xsl:value-of select="@ImageSource" /></xsl:attribute> - <xsl:choose> - <xsl:when test="@Viewport and @ViewportUnits = 'Absolute'"> - <xsl:attribute name="patternUnits">userSpaceOnUse</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@Viewport"> - <xsl:attribute name="patternUnits">boundingBox</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="0" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="concat(100 * number(substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="concat(100 * number(substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="patternUnits">boundingBox</xsl:attribute> - <xsl:attribute name="x">0</xsl:attribute> - <xsl:attribute name="y">0</xsl:attribute> - <xsl:attribute name="width">100%</xsl:attribute> - <xsl:attribute name="height">100%</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:attribute name="style">opacity:1</xsl:attribute> - <xsl:attribute name="image-rendering">optimizeSpeed</xsl:attribute> - </image> - </pattern> - </defs> -</xsl:template> - -<xsl:template match="*[name(.) = 'DrawingBrush']"> - <pattern> - <xsl:choose> - <xsl:when test="@TileMode != 'none' and @Viewport and @ViewportUnits = 'Absolute'"> - <xsl:attribute name="patternUnits">userSpaceOnUse</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="substring-before(@Viewport, ',')" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="substring-before(substring-after(@Viewport, ','), ',')" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@TileMode != 'none' and @Viewport"> - <xsl:attribute name="patternUnits">boundingBox</xsl:attribute> - <xsl:attribute name="x"><xsl:value-of select="concat(100 * number(substring-before(@Viewport, ',')), '%')" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="concat(100 * number(substring-before(substring-after(@Viewport, ','), ',')), '%')" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="concat(100 * number(substring-before(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="concat(100 * number(substring-after(substring-after(substring-after(@Viewport, ','), ','), ',')), '%')" /></xsl:attribute> - </xsl:when> - <xsl:when test="@Viewport and ../../@Width and ../../@Height"> - <xsl:attribute name="patternUnits">userSpaceOnUse</xsl:attribute> - <xsl:attribute name="x">0</xsl:attribute> - <xsl:attribute name="y">0</xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="../../@Width" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="../../@Height" /></xsl:attribute> - </xsl:when> - <xsl:otherwise> - <xsl:attribute name="patternUnits">boundingBox</xsl:attribute> - <xsl:attribute name="x">0</xsl:attribute> - <xsl:attribute name="y">0</xsl:attribute> - <xsl:attribute name="width">100%</xsl:attribute> - <xsl:attribute name="height">100%</xsl:attribute> - </xsl:otherwise> - </xsl:choose> - <xsl:attribute name="id"><xsl:value-of select="concat('id_', generate-id(..))" /></xsl:attribute> - <xsl:apply-templates mode="forward" /> - </pattern> -</xsl:template> - -<xsl:template match="*[name(.) = 'DrawingBrush.Drawing']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/canvas.xsl b/share/extensions/xaml2svg/canvas.xsl deleted file mode 100644 index e67f0e225..000000000 --- a/share/extensions/xaml2svg/canvas.xsl +++ /dev/null @@ -1,80 +0,0 @@ -<?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. ---> - -<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"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template mode="forward" match="*[name(.) = 'Canvas' or name(.) = 'Window' or name(.) = 'StackPanel']"> - <svg> - <xsl:choose> - <!-- - <xsl:when test="@ID"><xsl:attribute name="id"><xsl:value-of select="@ID" /></xsl:attribute></xsl:when> - --> - <xsl:when test="@x:Key"><xsl:attribute name="id"><xsl:value-of select="@x:Key" /></xsl:attribute></xsl:when> - <xsl:when test="@Name"><xsl:attribute name="id"><xsl:value-of select="@Name" /></xsl:attribute></xsl:when> - </xsl:choose> - <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="@Canvas.Left"><xsl:attribute name="x"><xsl:value-of select="@Canvas.Left" /></xsl:attribute></xsl:if> - <xsl:if test="@Canvas.Top"><xsl:attribute name="y"><xsl:value-of select="@Canvas.Top" /></xsl:attribute></xsl:if> - <xsl:call-template name="template_properties" /> - <xsl:choose> - <xsl:when test="@Transform or *[name(.) = 'UIElement.RenderTransform' or name(.) = 'Shape.RenderTransform' or name(.) = concat(name(..), '.RenderTransform')]"> - <g> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates select="*[name(.) = 'UIElement.RenderTransform' or name(.) = 'Shape.RenderTransform' or name(.) = concat(name(..), '.RenderTransform')]" /> - <xsl:apply-templates mode="svg" /> - </g> - </xsl:when> - <xsl:otherwise><xsl:apply-templates mode="svg" /></xsl:otherwise> - </xsl:choose> - </svg> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Border']"> - <rect> - <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="@BorderThickness"><xsl:attribute name="stroke-width"><xsl:value-of select="@BorderThickness" /></xsl:attribute></xsl:if> - <xsl:if test="@Background"> - <xsl:attribute name="fill"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@Background" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@Background" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"><xsl:attribute name="fill-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute></xsl:if> - </xsl:if> - <xsl:if test="@BorderBrush"> - <xsl:attribute name="stroke"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@BorderBrush" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@BorderBrush" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"><xsl:attribute name="stroke-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute></xsl:if> - </xsl:if> - <xsl:call-template name="template_properties" /> - </rect> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/geometry.xsl b/share/extensions/xaml2svg/geometry.xsl deleted file mode 100644 index c28e6a67c..000000000 --- a/share/extensions/xaml2svg/geometry.xsl +++ /dev/null @@ -1,272 +0,0 @@ -<?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. ---> - -<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:def="Definition" -exclude-result-prefixes="def"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template mode="forward" match="*[name(.) = 'ClipGeometry']"> -<!-- --> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'GlyphRunDrawing']"> -<!-- --> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'ImageDrawing']"> - <image> - <xsl:if test="@ImageSource"><xsl:attribute name="xlink:href"><xsl:value-of select="@ImageSource" /></xsl:attribute></xsl:if> - <xsl:if test="@Rect"> - <xsl:attribute name="x"><xsl:value-of select="substring-before(@Rect, ',')" /></xsl:attribute> - <xsl:attribute name="y"><xsl:value-of select="substring-before(substring-after(@Rect, ','), ',')" /></xsl:attribute> - <xsl:attribute name="width"><xsl:value-of select="substring-before(substring-after(substring-after(@Rect, ','), ','), ',')" /></xsl:attribute> - <xsl:attribute name="height"><xsl:value-of select="substring-after(substring-after(substring-after(@Rect, ','), ','), ',')" /></xsl:attribute> - </xsl:if> - </image> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'DrawingGroup']"> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'EllipseGeometry']"> - <xsl:variable name="cx" select="substring-before(@Center, ',')" /> - <xsl:variable name="cy" select="substring-after(@Center, ',')" /> - <xsl:value-of select="concat('M ', $cx + @RadiusX, ',', $cy, ' ')" /> - <xsl:value-of select="concat('A ', @RadiusX, ',', @RadiusY, ' 0 0 1 ', $cx, ',', $cy + @RadiusY, ' ')" /> - <xsl:value-of select="concat('A ', @RadiusX, ',', @RadiusY, ' 0 0 1 ', $cx - @RadiusX, ',', $cy, ' ')" /> - <xsl:value-of select="concat('A ', @RadiusX, ',', @RadiusY, ' 0 0 1 ', $cx, ',', $cy - @RadiusY, ' ')" /> - <xsl:value-of select="concat('A ', @RadiusX, ',', @RadiusY, ' 0 0 1 ', $cx + @RadiusX, ',', $cy, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'LineGeometry']"> - <xsl:value-of select="concat('M ', @StartPoint, ' ')" /> - <xsl:value-of select="concat('L ', @EndPoint, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathGeometry']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathGeometry.Figures']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathFigureCollection']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathFigure']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathFigure.Segments']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PathSegmentCollection']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'StartSegment']"> - <xsl:value-of select="concat('M ', @Point, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'CloseSegment']"> - <xsl:value-of select="'z '" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'LineSegment']"> - <xsl:value-of select="concat('L ', @Point, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'ArcSegment']"> - <xsl:value-of select="concat('A ', substring-before(@Size, ','), ',', substring-after(@Size, ','), ' ', @XRotation, ' ', number(@LargeArc = 'True'), ' ', number(@Sweepflag = 'True'), ' ', @Point, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'BezierSegment']"> - <xsl:value-of select="concat('C ', @Point1, ' ', @Point2, ' ', @Point3, ' ')" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'QuadraticBezierSegment']"> - <xsl:value-of select="concat('Q ', @Point1, ' ', @Point2, ' ', @Point3, ' ')" /> -</xsl:template> - -<xsl:template name="PrintPolyBezierPoints"> - <xsl:param name="segments" /> - <xsl:param name="segmentsize" /> - <xsl:param name="cursor" /> - <xsl:text>C </xsl:text> - <xsl:value-of select="concat(substring-before($segments, ','), ',')" /> - <xsl:variable name="segments1"><xsl:value-of select="substring-after($segments, ',')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments1, ' '), ' ')" /> - <xsl:variable name="segments2"><xsl:value-of select="substring-after($segments1, ' ')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments2, ','), ',')" /> - <xsl:variable name="segments3"><xsl:value-of select="substring-after($segments2, ',')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments3, ' '), ' ')" /> - <xsl:variable name="segments4"><xsl:value-of select="substring-after($segments3, ' ')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments4, ','), ',')" /> - <xsl:variable name="segments5"><xsl:value-of select="substring-after($segments4, ',')" /></xsl:variable> - <xsl:choose> - <xsl:when test="contains($segments5, ' ')"> - <xsl:value-of select="concat(substring-before($segments5, ' '), ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$segments5" /> - </xsl:otherwise> - </xsl:choose> - <xsl:variable name="segments6"><xsl:value-of select="substring-after($segments5, ' ')" /></xsl:variable> - <xsl:if test="contains($segments6, ' ')"> - <xsl:call-template name="PrintPolyBezierPoints"> - <xsl:with-param name="segments" select="$segments6" /> - </xsl:call-template> - </xsl:if> -</xsl:template> - -<xsl:template name="PrintPolyLinePoints"> - <xsl:param name="segments" /> - <xsl:text>L </xsl:text> - <xsl:value-of select="concat(substring-before($segments, ','), ',')" /> - <xsl:variable name="segments1"><xsl:value-of select="substring-after($segments, ',')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments1, ' '), ' ')" /> - <xsl:variable name="segments2"><xsl:value-of select="substring-after($segments1, ' ')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments2, ','), ',')" /> - <xsl:variable name="segments3"><xsl:value-of select="substring-after($segments2, ',')" /></xsl:variable> - <xsl:choose> - <xsl:when test="contains($segments3, ' ')"> - <xsl:value-of select="concat(substring-before($segments3, ' '), ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$segments3" /> - </xsl:otherwise> - </xsl:choose> - <xsl:variable name="segments4"><xsl:value-of select="substring-after($segments3, ' ')" /></xsl:variable> - <xsl:if test="contains($segments4, ' ')"> - <xsl:call-template name="PrintPolyLinePoints"> - <xsl:with-param name="segments" select="$segments4" /> - </xsl:call-template> - </xsl:if> -</xsl:template> - -<xsl:template name="PrintQuadraticBezierPoints"> - <xsl:param name="segments" /> - <xsl:text>Q </xsl:text> - <xsl:value-of select="concat(substring-before($segments, ','), ',')" /> - <xsl:variable name="segments1"><xsl:value-of select="substring-after($segments, ',')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments1, ' '), ' ')" /> - <xsl:variable name="segments2"><xsl:value-of select="substring-after($segments1, ' ')" /></xsl:variable> - <xsl:value-of select="concat(substring-before($segments2, ','), ',')" /> - <xsl:variable name="segments3"><xsl:value-of select="substring-after($segments2, ',')" /></xsl:variable> - <xsl:choose> - <xsl:when test="contains($segments3, ' ')"> - <xsl:value-of select="concat(substring-before($segments3, ' '), ' ')" /> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="$segments3" /> - </xsl:otherwise> - </xsl:choose> - <xsl:variable name="segments4"><xsl:value-of select="substring-after($segments3, ' ')" /></xsl:variable> - <xsl:if test="contains($segments4, ' ')"> - <xsl:call-template name="PrintQuadraticBezierPoints"> - <xsl:with-param name="segments" select="$segments4" /> - </xsl:call-template> - </xsl:if> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PolyBezierSegment']"> - <xsl:call-template name="PrintPolyBezierPoints"> - <xsl:with-param name="segments" select="@Points" /> - </xsl:call-template> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PolyLineSegment']"> - <xsl:call-template name="PrintPolyLinePoints"> - <xsl:with-param name="segments" select="@Points" /> - </xsl:call-template> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'PolyQuadraticBezierSegment']"> - <xsl:call-template name="PrintQuadraticBezierPoints"> - <xsl:with-param name="segments" select="@Points" /> - </xsl:call-template> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'RectangleGeometry']"> - <xsl:variable name="rect" select="RectangleGeometry.Rect/Rect" /> - <xsl:choose> - <xsl:when test="$rect"> - <xsl:value-of select="concat('M ', $rect/@X, ',', $rect/@Y, ' ')" /> - <xsl:value-of select="concat('H ', $rect/@X + $rect/@Width, ' V ', $rect/@Y + $rect/@Height, ' H ', $rect/@X,' V ', $rect/@Y, ' ')" /> - </xsl:when> - <xsl:when test="@Rect"> - <xsl:variable name="x" select="substring-before(substring-before(@Rect, ' '), ',')" /> - <xsl:variable name="y" select="substring-after(substring-before(@Rect, ' '), ',')" /> - <xsl:variable name="width" select="substring-before(substring-after(@Rect, ' '), ',')" /> - <xsl:variable name="height" select="substring-after(substring-after(@Rect, ' '), ',')" /> - <xsl:value-of select="concat('M ', $x, ',', $y, ' ')" /> - <xsl:value-of select="concat('H ', $x + $width, ' V ', $y + $height, ' H ', $x,' V ', $y, ' ')" /> - </xsl:when> - </xsl:choose> -</xsl:template> - -<!-- -<xsl:template mode="forward" match="*[name(.) = 'GeometryCollection']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> ---> - -<xsl:template mode="forward" match="*[name(.) = 'GeometryGroup']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'GeometryDrawing']"> - <path> - <xsl:attribute name="d"><xsl:apply-templates select="*[name(.) = 'GeometryDrawing.Geometry']" mode="forward" /></xsl:attribute> - <xsl:attribute name="fill"><xsl:value-of select="@Brush" /></xsl:attribute> - <xsl:apply-templates mode="forward" select="*[name(.) = 'GeometryDrawing.Pen']" /> - </path> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'GeometryDrawing.Geometry']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'GeometryDrawing.Pen']"> - <xsl:variable name="pen" select="*[name(.) = 'Pen']" /> - <xsl:if test="$pen/@Brush"><xsl:attribute name="stroke"><xsl:value-of select="$pen/@Brush" /></xsl:attribute></xsl:if> - <xsl:if test="$pen/@Thickness"><xsl:attribute name="stroke-width"><xsl:value-of select="$pen/@Thickness" /></xsl:attribute></xsl:if> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'CombinedGeometry' or name(.) = 'CombinedGeometry.Geometry1' or name(.) = 'CombinedGeometry.Geometry2']"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/properties.xsl b/share/extensions/xaml2svg/properties.xsl deleted file mode 100644 index 75d0aea26..000000000 --- a/share/extensions/xaml2svg/properties.xsl +++ /dev/null @@ -1,286 +0,0 @@ -<?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 TemplateBinding in template_color - ---> - -<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="ISO-8859-1"/> - -<xsl:template mode="boundingbox" match="*"> -<xsl:if test="system-property('xsl:vendor') = 'Microsoft'"> - <xsl:choose> - <xsl:when test="@Canvas.Left and @Canvas.Top and @Width and @Height"> - <boundingbox> - <xsl:attribute name="x1"> - <xsl:value-of select="@Canvas.Left" /> - </xsl:attribute> - <xsl:attribute name="x2"> - <xsl:value-of select="@Canvas.Left + @Width" /> - </xsl:attribute> - <xsl:attribute name="y1"> - <xsl:value-of select="@Canvas.Top" /> - </xsl:attribute> - <xsl:attribute name="y2"> - <xsl:value-of select="@Canvas.Top + @Height" /> - </xsl:attribute> - </boundingbox> - </xsl:when> - <xsl:when test="count(*) > 0"> - <xsl:variable name="boundingboxes"><xsl:apply-templates mode="boundingbox" select="*" /> - </xsl:variable> - <boundingbox> - <xsl:attribute name="x1"> - <xsl:for-each select="msxsl:node-set($boundingboxes)/boundingbox"> - <xsl:sort data-type="number" select="@x1" order="ascending"/> - <xsl:if test="position() = 1"><xsl:value-of select="@x1" /></xsl:if> - </xsl:for-each> - </xsl:attribute> - <xsl:attribute name="x2"> - <xsl:for-each select="msxsl:node-set($boundingboxes)/boundingbox"> - <xsl:sort data-type="number" select="@x2" order="descending"/> - <xsl:if test="position() = 1"><xsl:value-of select="@x2" /></xsl:if> - </xsl:for-each> - </xsl:attribute> - <xsl:attribute name="y1"> - <xsl:for-each select="msxsl:node-set($boundingboxes)/boundingbox"> - <xsl:sort data-type="number" select="@y1" order="ascending"/> - <xsl:if test="position() = 1"><xsl:value-of select="@y1" /></xsl:if> - </xsl:for-each> - </xsl:attribute> - <xsl:attribute name="y2"> - <xsl:for-each select="msxsl:node-set($boundingboxes)/boundingbox"> - <xsl:sort data-type="number" select="@y2" order="descending"/> - <xsl:if test="position() = 1"><xsl:value-of select="@y2" /></xsl:if> - </xsl:for-each> - </xsl:attribute> - </boundingbox> - </xsl:when> - </xsl:choose> -</xsl:if> -</xsl:template> - -<xsl:template mode="svg" match="*"> - <xsl:choose> - <xsl:when test="false() and name(.) != 'Canvas' and name(.) != 'Image' and name(.) != 'Rect' and name(.) != 'Ellipse' and name(.) != 'Text' and name(.) != 'TextBlock' and (@Canvas.Left or @Canvas.Top)"> - <svg> - <xsl:if test="@Canvas.Left and @Canvas.Top and @Width and @Height"> - <xsl:attribute name="viewBox"> - <xsl:value-of select="concat(@Canvas.Left, ' ')" /> - <xsl:value-of select="concat(@Canvas.Top, ' ')" /> - <xsl:value-of select="concat(@Width - @Canvas.Left, ' ')" /> - <xsl:value-of select="@Height - @Canvas.Top" /> - </xsl:attribute> - </xsl:if> - <xsl:if test="@Canvas.Left"><xsl:attribute name="x"><xsl:value-of select="@Canvas.Left" /></xsl:attribute></xsl:if> - <xsl:if test="@Canvas.Top"><xsl:attribute name="y"><xsl:value-of select="@Canvas.Top" /></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:apply-templates mode="g" select="." /> - </svg> - </xsl:when> - <xsl:otherwise><xsl:apply-templates mode="g" select="." /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<xsl:template mode="g" match="*"> - <xsl:choose> - <xsl:when test="*[(name(.) = 'Shape.Fill' or name(.) = concat(name(..), '.Fill')) and not(*[name(.) = 'SolidColorBrush']) or (name(.) = 'Shape.Stroke' or name(.) = concat(name(..), '.Stroke')) and not(*[name(.) = 'SolidColorBrush']) or name(.) = 'UIElement.OpacityMask' or name(.) = concat(name(..), '.OpacityMask') or name(.) = 'UIElement.Clip' or name(.) = concat(name(..), '.Clip')]"> - <g> - <xsl:apply-templates mode="defs" select="." /> - <xsl:apply-templates mode="forward" select="." /> - </g> - </xsl:when> - <xsl:otherwise><xsl:apply-templates mode="forward" select="." /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<xsl:template name="template_color"> - <xsl:param name="colorspec" /> - <xsl:choose> - <xsl:when test="contains($colorspec, '#') and (string-length($colorspec) = 7 or string-length($colorspec) = 9)"> - <xsl:value-of select="concat('#', substring($colorspec, string-length($colorspec) - 5, 6))" /> - </xsl:when> - <xsl:when test="contains($colorspec, '#') and (string-length($colorspec) = 4 or string-length($colorspec) = 5)"> - <xsl:value-of select="concat('#', substring($colorspec, string-length($colorspec) - 5, 3))" /> - </xsl:when> - <xsl:when test="contains($colorspec, '{StaticResource ')"><xsl:value-of select="concat('url(#', substring-before(substring-after($colorspec, '{StaticResource '), '}'), ')')" /></xsl:when> - <xsl:when test="contains($colorspec, '{TemplateBinding ')"><xsl:value-of select="concat('url(#', substring-before(substring-after($colorspec, '{TemplateBinding '), '}'), ')')" /></xsl:when> - <xsl:otherwise><xsl:value-of select="$colorspec" /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<xsl:template name="template_opacity"> - <xsl:param name="colorspec" /> - <xsl:if test="contains($colorspec, '#') and (string-length($colorspec) = 4 or string-length($colorspec) = 9)"> - <xsl:variable name="opacityspec"><xsl:value-of select="translate(substring($colorspec, 2, 2), 'abcdefgh', 'ABCDEFGH')" /></xsl:variable> - <xsl:choose> - <xsl:when test="$opacityspec != 'FF'"> - <xsl:value-of select="format-number(number(string-length(substring-before('0123456789ABCDEF', substring($colorspec, 2, 1))) * 16 + string-length(substring-before('0123456789ABCDEF', substring($colorspec, 3, 1)))) div 255, '#0.00')" /> - </xsl:when> - <xsl:otherwise><xsl:value-of select="''"/></xsl:otherwise> - </xsl:choose> - </xsl:if> -</xsl:template> - -<xsl:template name="template_properties"> - <xsl:choose> - <!-- - <xsl:when test="@ID"><xsl:attribute name="id"><xsl:value-of select="@ID" /></xsl:attribute></xsl:when> - --> - <xsl:when test="@x:Key"><xsl:attribute name="id"><xsl:value-of select="@x:Key" /></xsl:attribute></xsl:when> - <xsl:when test="@Name"><xsl:attribute name="id"><xsl:value-of select="@Name" /></xsl:attribute></xsl:when> - </xsl:choose> - <xsl:choose> - <xsl:when test="@Fill"> - <xsl:attribute name="fill"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@Fill" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@Fill" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"> - <xsl:attribute name="fill-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute> - </xsl:if> - </xsl:when> - <xsl:when test="not(name(.) = 'Canvas') and not(@Foreground or *[name(.) = 'Shape.Fill' or name(.) = concat(name(..), '.Fill')])"><xsl:attribute name="fill">none</xsl:attribute></xsl:when> - </xsl:choose> - <xsl:if test="@Stroke"> - <xsl:attribute name="stroke"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@Stroke" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@Stroke" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"><xsl:attribute name="stroke-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute></xsl:if> - </xsl:if> - <xsl:if test="@StrokeThickness"><xsl:attribute name="stroke-width"><xsl:value-of select="@StrokeThickness" /></xsl:attribute></xsl:if> - <xsl:if test="@StrokeMiterLimit"><xsl:attribute name="stroke-miterlimit"><xsl:value-of select="@StrokeMiterLimit" /></xsl:attribute></xsl:if> - <xsl:if test="@StrokeDashArray"><xsl:attribute name="stroke-dasharray"><xsl:value-of select="@StrokeDashArray" /></xsl:attribute></xsl:if> - <xsl:if test="@StrokeDashOffset"><xsl:attribute name="stroke-dashoffset"><xsl:value-of select="@StrokeDashOffset" /></xsl:attribute></xsl:if> - <xsl:if test="@StrokeLineJoin"><xsl:attribute name="stroke-linejoin"><xsl:value-of select="@StrokeLineJoin" /></xsl:attribute></xsl:if> - <xsl:if test="@StrokeEndLineCap"><xsl:attribute name="stroke-linecap"><xsl:value-of select="@StrokeEndLineCap" /></xsl:attribute></xsl:if> - <xsl:if test="@Opacity"><xsl:attribute name="fill-opacity"><xsl:value-of select="@Opacity" /></xsl:attribute></xsl:if> - <xsl:if test="@Color"> - <xsl:attribute name="fill"><xsl:call-template name="template_color"><xsl:with-param name="colorspec" select="@Color" /></xsl:call-template></xsl:attribute> - <xsl:variable name="test_opacity"><xsl:call-template name="template_opacity"><xsl:with-param name="colorspec" select="@Color" /></xsl:call-template></xsl:variable> - <xsl:if test="string-length($test_opacity) > 0"><xsl:attribute name="fill-opacity"><xsl:value-of select="$test_opacity" /></xsl:attribute></xsl:if> - </xsl:if> - <xsl:if test="@Clip"> - <xsl:choose> - <xsl:when test="contains(@Clip, '{')"><xsl:attribute name="fill"><xsl:value-of select="concat('url(#', substring-before(substring-after(@Clip, '{'), '}'), ')')" /></xsl:attribute></xsl:when> - <xsl:otherwise> - <xsl:attribute name="clip-path"><xsl:value-of select="concat('url(#clippath_', generate-id(.),')')" /></xsl:attribute> - <defs> - <clipPath> - <xsl:attribute name="id"><xsl:value-of select="concat('clippath_', generate-id(.))" /></xsl:attribute> - <path> - <xsl:attribute name="d"> - <xsl:choose> - <xsl:when test="contains(@Clip, 'F1')"><xsl:value-of select="substring-after(@Clip, 'F1')" /></xsl:when> - <xsl:otherwise><xsl:value-of select="@Clip" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute></path> - </clipPath> - </defs> - </xsl:otherwise> - </xsl:choose> - </xsl:if> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = concat(name(..), '.Resources')]"> - <defs><xsl:apply-templates mode="forward" /></defs> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = concat(name(..), '.Children')]"> - <xsl:apply-templates mode="forward" /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Shape.Fill' or name(.) = concat(name(..), '.Fill')]"> - <xsl:choose> - <xsl:when test="not(*[name(.) = 'SolidColorBrush'])"> - <xsl:attribute name="fill"><xsl:value-of select="concat('url(#id_', generate-id(.), ')')" /></xsl:attribute> - </xsl:when> - <xsl:otherwise><xsl:apply-templates select="*[name(.) = 'SolidColorBrush']" /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<xsl:template mode="defs" match="*[(name(.) = 'Shape.Fill' or name(.) = concat(name(..), '.Fill')) and not(*[name(.) = 'SolidColorBrush'])]"> - <defs><xsl:apply-templates mode="forward" /></defs> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Shape.Opacity' or name(.) = concat(name(..), '.Opacity')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = concat(name(..), '.Height') or name(.) = concat(name(..), '.Width')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Shape.Stroke' or name(.) = concat(name(..), '.Stroke')]"> - <xsl:choose> - <xsl:when test="not(*[name(.) = 'SolidColorBrush'])"> - <xsl:attribute name="stroke"><xsl:value-of select="concat('url(#id_', generate-id(.), ')')" /></xsl:attribute> - </xsl:when> - <xsl:otherwise><xsl:apply-templates select="*[name(.) = 'SolidColorBrush']" /></xsl:otherwise> - </xsl:choose> -</xsl:template> - -<xsl:template mode="defs" match="*[(name(.) = 'Shape.Stroke' or name(.) = concat(name(..), '.Stroke')) and not(*[name(.) = 'SolidColorBrush'])]"> - <defs><xsl:apply-templates mode="forward" /></defs> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'UIElement.Clip' or name(.) = concat(name(..), '.Clip')]"> - <xsl:attribute name="clip-path"><xsl:value-of select="concat('url(#clippath_', generate-id(.),')')" /></xsl:attribute> -</xsl:template> - -<xsl:template mode="defs" match="*[name(.) = 'UIElement.Clip' or name(.) = concat(name(..), '.Clip')]"> - <defs> - <clipPath> - <xsl:attribute name="id"><xsl:value-of select="concat('clippath_', generate-id(.))" /></xsl:attribute> - <path> - <xsl:attribute name="d"> - <xsl:apply-templates mode="forward" /> - </xsl:attribute> - </path> - </clipPath> - </defs> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'UIElement.OpacityMask' or name(.) = concat(name(..), '.OpacityMask')]"> - <xsl:attribute name="mask"><xsl:value-of select="concat('url(#mask_', generate-id(.),')')" /></xsl:attribute> -</xsl:template> - -<xsl:template mode="defs" match="*[name(.) = 'UIElement.OpacityMask' or name(.) = concat(name(..), '.OpacityMask')]"> - <defs> - <mask> - <xsl:attribute name="id"><xsl:value-of select="concat('mask_', generate-id(.))" /></xsl:attribute> - <xsl:apply-templates mode="svg" /> - </mask> - </defs> -</xsl:template> - - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/shapes.xsl b/share/extensions/xaml2svg/shapes.xsl deleted file mode 100644 index c28b027e1..000000000 --- a/share/extensions/xaml2svg/shapes.xsl +++ /dev/null @@ -1,171 +0,0 @@ -<?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 starts-with(@Data, 'F0 ') to strip of F0 from path data -20070912 nonzero and evenodd were outside xsl:attribute (reported by bulia byak and Ted Gould) - ---> - -<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:def="Definition" -exclude-result-prefixes="def"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template mode="forward" match="*[name(.) = 'Path']"> - <path> - <xsl:if test="@Data"> - <xsl:attribute name="d"> - <xsl:choose> - <xsl:when test="starts-with(@Data, 'F0 ')"><xsl:value-of select="substring-after(@Data, 'F0 ')" /></xsl:when> - <xsl:when test="starts-with(@Data, 'F1 ')"><xsl:value-of select="substring-after(@Data, 'F1 ')" /></xsl:when> - <xsl:otherwise><xsl:value-of select="@Data" /></xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> - <xsl:choose> - <xsl:when test="@FillRule = 'nonzero' or starts-with(@Data, 'F1 ')"><xsl:attribute name="fill-rule">nonzero</xsl:attribute></xsl:when> - <xsl:when test="@FillRule = 'evenodd' or starts-with(@Data, 'F0 ')"><xsl:attribute name="fill-rule">evenodd</xsl:attribute></xsl:when> - </xsl:choose> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </path> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Path.Data']"> - <xsl:attribute name="d"> - <xsl:apply-templates mode="forward" /> - </xsl:attribute> - <xsl:if test="@FillRule"> - <xsl:attribute name="fill-rule"> - <xsl:choose> - <xsl:when test="@FillRule = 'nonzero'">nonzero</xsl:when> - <xsl:otherwise>evenodd</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - </xsl:if> -</xsl:template> - -<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:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </line> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Ellipse']"> - <ellipse> - <xsl:if test="@Width"> - <xsl:attribute name="rx"><xsl:value-of select="@Width div 2" /></xsl:attribute> - <xsl:if test="@Canvas.Left"> - <xsl:attribute name="cx"><xsl:value-of select="@Canvas.Left + @Width div 2" /></xsl:attribute> - </xsl:if> - </xsl:if> - <xsl:if test="@Height"> - <xsl:attribute name="ry"><xsl:value-of select="@Height div 2" /></xsl:attribute> - <xsl:if test="@Canvas.Top"> - <xsl:attribute name="cy"><xsl:value-of select="@Canvas.Top + @Height div 2" /></xsl:attribute> - </xsl:if> - </xsl:if> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </ellipse> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Rectangle']"> - <rect> - <xsl:if test="@Canvas.Left"><xsl:attribute name="x"><xsl:value-of select="@Canvas.Left" /></xsl:attribute></xsl:if> - <xsl:if test="@Canvas.Top"><xsl:attribute name="y"><xsl:value-of select="@Canvas.Top" /></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="@RadiusX"><xsl:attribute name="rx"><xsl:value-of select="@RadiusX" /></xsl:attribute></xsl:if> - <xsl:if test="@RadiusY"><xsl:attribute name="ry"><xsl:value-of select="@RadiusY" /></xsl:attribute></xsl:if> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:call-template name="template_timeline_animations" /> - <xsl:apply-templates mode="forward" /> - </rect> -</xsl:template> - -<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:attribute name="fill-rule"> - <xsl:choose> - <xsl:when test="@FillRule = 'nonzero'">nonzero</xsl:when> - <xsl:when test="@FillRule = 'evenodd'">evenodd</xsl:when> - </xsl:choose> - </xsl:attribute> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </polyline> -</xsl:template> - -<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:attribute name="fill-rule"> - <xsl:choose> - <xsl:when test="@FillRule = 'nonzero'">nonzero</xsl:when> - <xsl:when test="@FillRule = 'evenodd'">evenodd</xsl:when> - </xsl:choose> - </xsl:attribute> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:apply-templates mode="forward" /> - </polygon> -</xsl:template> - -<xsl:template mode="forward" match="*[name(.) = 'Glyphs']"> - <defs> - <font-face> - <xsl:attribute name="font-family"><xsl:value-of select="concat('TrueType ', generate-id(.))" /></xsl:attribute> - <font-face-src><font-face-uri><xsl:attribute name="xlink:href"><xsl:value-of select="@FontUri" /></xsl:attribute></font-face-uri></font-face-src> - </font-face> - </defs> - <text> - <xsl:if test="@FontRenderingEmSize"><xsl:attribute name="font-size"><xsl:value-of select="@FontRenderingEmSize" /></xsl:attribute></xsl:if> - <xsl:if test="@OriginX"><xsl:attribute name="x"><xsl:value-of select="@OriginX" /></xsl:attribute></xsl:if> - <xsl:if test="@OriginY"><xsl:attribute name="y"><xsl:value-of select="@OriginY" /></xsl:attribute></xsl:if> - <xsl:attribute name="font-family"><xsl:value-of select="concat('TrueType ', generate-id(.))" /></xsl:attribute> - <xsl:call-template name="template_properties" /> - <xsl:call-template name="template_transform" /> - <xsl:if test="@UnicodeString"><xsl:value-of select="@UnicodeString" /></xsl:if> - </text> -</xsl:template> - -</xsl:stylesheet> diff --git a/share/extensions/xaml2svg/transform.xsl b/share/extensions/xaml2svg/transform.xsl deleted file mode 100644 index 3d41cf408..000000000 --- a/share/extensions/xaml2svg/transform.xsl +++ /dev/null @@ -1,120 +0,0 @@ -<?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. ---> - -<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:def="Definition" -exclude-result-prefixes="def"> -<xsl:strip-space elements="*" /> -<xsl:output method="xml" encoding="ISO-8859-1"/> - -<xsl:template name="template_transform"> - <xsl:variable name="transform_value"> - <xsl:if test="@Transform"><xsl:value-of select="@Transform" /></xsl:if> - <xsl:apply-templates select="*[name(.) = 'UIElement.RenderTransform' or name(.) = 'Shape.RenderTransform' or name(.) = concat(name(..), '.RenderTransform')]/*" /> - </xsl:variable> - <xsl:if test="string-length($transform_value) > 0"><xsl:attribute name="transform"><xsl:value-of select="$transform_value" /></xsl:attribute></xsl:if> -</xsl:template> - -<xsl:template name="template_gradienttransform"> - <xsl:variable name="transform_value"> - <xsl:if test="@Canvas.Left and @Canvas.Top"><xsl:value-of select="concat('translate(', @Canvas.Left, ',', @Canvas.Top, ')')" /></xsl:if> - <xsl:if test="@Transform"><xsl:value-of select="@Transform" /></xsl:if> - <xsl:apply-templates select="*[name(.) = 'Brush.Transform' or name(.) = concat(name(..), '.Transform')]" /> - <xsl:apply-templates select="*[name(.) = 'Brush.RelativeTransform' or name(.) = concat(name(..), '.RelativeTransform')]" /> - </xsl:variable> - <xsl:if test="string-length($transform_value) > 0"><xsl:attribute name="gradientTransform"><xsl:value-of select="$transform_value" /></xsl:attribute></xsl:if> -</xsl:template> - -<xsl:template match="*[name(.) = 'UIElement.RenderTransform' or name(.) = 'Shape.RenderTransform' or name(.) = concat(name(..), '.RenderTransform')]"> - <!-- xsl:apply-templates /--> -</xsl:template> - -<xsl:template match="*[name(.) = 'Brush.Transform' or name(.) = concat(name(..), '.Transform')]"> - <xsl:apply-templates /> -</xsl:template> - -<xsl:template match="*[name(.) = 'Brush.RelativeTransform' or name(.) = concat(name(..), '.RelativeTransform')]"> - <xsl:apply-templates /> -</xsl:template> - -<!-- -<xsl:template match="*[name(.) = 'TransformCollection' or name(.) = 'TransformGroup']"> - <xsl:apply-templates /> -</xsl:template> ---> -<xsl:template match="*[name(.) = 'TransformGroup']"> - <xsl:apply-templates /> -</xsl:template> - - -<!-- -<xsl:template mode="forward" match="*[name(.) = 'TransformDecorator']"> - <g> - <xsl:attribute name="transform"> - <xsl:if test="@Transform"><xsl:value-of select="@Transform" /></xsl:if> - <xsl:apply-templates select="*[name(.) = 'TransformDecorator.Transform']/*" /> - </xsl:attribute> - <xsl:apply-templates select="*[name(.) = 'TransformDecorator.Transform']/*/*" /> - <xsl:apply-templates mode="forward" select="*[name(.) != 'TransformDecorator.Transform']" /> - </g> -</xsl:template> ---> - -<xsl:template match="*[name(.) = 'TranslateTransform']"> - <xsl:if test="@X"> - <xsl:value-of select="concat('translate(', @X)" /> - <xsl:if test="@Y"><xsl:value-of select="concat(', ', @Y)" /></xsl:if> - <xsl:value-of select="') '" /> - </xsl:if> -</xsl:template> - -<xsl:template match="*[name(.) = 'ScaleTransform']"> - <xsl:if test="@ScaleX"> - <xsl:value-of select="concat('scale(', @ScaleX)" /> - <xsl:if test="@ScaleY"><xsl:value-of select="concat(', ', @ScaleY)" /></xsl:if> - <xsl:value-of select="') '" /> - </xsl:if> -</xsl:template> - -<xsl:template match="*[name(.) = 'RotateTransform']"> - <xsl:if test="@Angle"> - <xsl:value-of select="concat('rotate(', @Angle)" /> - <xsl:if test="@Center"><xsl:value-of select="concat(',', @Center)" /></xsl:if> - <xsl:value-of select="') '" /> - </xsl:if> -</xsl:template> - -<xsl:template match="*[name(.) = 'SkewTransform']"> - <xsl:if test="@AngleX"><xsl:value-of select="concat('skewX(', @AngleX,') ')" /></xsl:if> - <xsl:if test="@AngleY"><xsl:value-of select="concat('skewY(', @AngleY,') ')" /></xsl:if> -</xsl:template> - -<xsl:template match="*[name(.) = 'MatrixTransform']"> - <xsl:if test="@Matrix"><xsl:value-of select="concat('matrix(', @Matrix,') ')" /></xsl:if> -</xsl:template> - -</xsl:stylesheet> |
