diff options
Diffstat (limited to 'support')
-rwxr-xr-x | support/generate_kicad.py | 322 | ||||
-rwxr-xr-x | support/inkscape_exporter.py | 65 | ||||
-rwxr-xr-x | support/inkscape_svg_filter_layers.py | 51 | ||||
-rw-r--r-- | support/pogojig/__init__.py | 0 | ||||
-rw-r--r-- | support/pogojig/inkscape/__init__.py | 0 | ||||
-rw-r--r-- | support/pogojig/inkscape/bezmisc.py | 287 | ||||
-rw-r--r-- | support/pogojig/inkscape/cspsubdiv.py | 38 | ||||
-rw-r--r-- | support/pogojig/inkscape/cubicsuperpath.py | 174 | ||||
-rw-r--r-- | support/pogojig/inkscape/dxf_footer.txt | 62 | ||||
-rw-r--r-- | support/pogojig/inkscape/dxf_header.txt | 580 | ||||
-rw-r--r-- | support/pogojig/inkscape/effect.py | 279 | ||||
-rw-r--r-- | support/pogojig/inkscape/ffgeom.py | 137 | ||||
-rw-r--r-- | support/pogojig/inkscape/inkex.py | 363 | ||||
-rw-r--r-- | support/pogojig/inkscape/inkscape.py | 124 | ||||
-rw-r--r-- | support/pogojig/inkscape/simplepath.py | 213 | ||||
-rw-r--r-- | support/pogojig/inkscape/simpletransform.py | 242 | ||||
-rw-r--r-- | support/pogojig/kicad/__init__.py | 0 | ||||
-rw-r--r-- | support/pogojig/kicad/kicad-cache.lib | 21 | ||||
-rw-r--r-- | support/pogojig/kicad/kicad.pro | 34 |
19 files changed, 0 insertions, 2992 deletions
diff --git a/support/generate_kicad.py b/support/generate_kicad.py deleted file mode 100755 index 3e1b614..0000000 --- a/support/generate_kicad.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import time -from os import path -from textwrap import dedent -import pkgutil -import subprocess -import xml.etree.ElementTree as xe - -import ezdxf - - -__version__ = '0.1' - -PIN_TS_BASE = 0x23420000 -TEDIT_BASE = 0x23430000 -PATH_BASE = 0x23440000 - - -def sch_template(name, num_pins, yspace=200): - templ = f''' - EESchema Schematic File Version 5 - EELAYER 30 0 - EELAYER END - $Descr A3 16535 11693 - encoding utf-8 - Sheet 1 1 - Title "{name}" - Date "{time.strftime("%d %b %Y")}" - Rev "" - Comp "" - Comment1 "" - Comment2 "" - Comment3 "" - Comment4 "" - Comment5 "" - Comment6 "" - Comment7 "" - Comment8 "" - Comment9 "" - $EndDescr - {{components}} - $EndSCHEMATC - ''' - - components = [] - for i in range(num_pins): - identifier = f'TP{i}' - value = 'pogopin' - x, y = 1000, 1000 + i*yspace - components.append(dedent(f''' - $Comp - L Connector:Conn_01x01_Female {identifier} - U 1 1 {PIN_TS_BASE + i:08X} - P {x} {y} - F 0 "{identifier}" H {x-50} {y+50} 50 0000 R CNN - F 1 "{value}" H {x+50} {y} 50 0000 L CNN - F 2 "Pogopin:AutogeneratedPogopinFootprint" H {x} {y} 50 0001 C CNN - F 3 "~" H {x} {y} 50 0001 C CNN - 1 {x} {y} - -1 0 0 1 - $EndComp - ''').strip()) - - return dedent(templ).lstrip().format(components='\n'.join(components)) - -def pcb_template(outline, pins, annular=0.5): - pcb_templ = f''' - (kicad_pcb (version 20190605) (host pogojig "({__version__})") - - (general - (thickness 1.6) - (drawings {len(pins)}) - (tracks 0) - (modules {len(pins)}) - (nets {len(pins)+1}) - ) - - (page "A4") - (layers - (0 "F.Cu" signal) - (31 "B.Cu" signal) - (32 "B.Adhes" user) - (33 "F.Adhes" user) - (34 "B.Paste" user) - (35 "F.Paste" user) - (36 "B.SilkS" user) - (37 "F.SilkS" user) - (38 "B.Mask" user) - (39 "F.Mask" user) - (40 "Dwgs.User" user) - (41 "Cmts.User" user) - (42 "Eco1.User" user) - (43 "Eco2.User" user) - (44 "Edge.Cuts" user) - (45 "Margin" user) - (46 "B.CrtYd" user) - (47 "F.CrtYd" user) - (48 "B.Fab" user) - (49 "F.Fab" user) - ) - - (setup - (last_trace_width 0.25) - (trace_clearance 0.2) - (zone_clearance 0.508) - (zone_45_only no) - (trace_min 0.2) - (via_size 0.8) - (via_drill 0.4) - (via_min_size 0.4) - (via_min_drill 0.3) - (uvia_size 0.3) - (uvia_drill 0.1) - (uvias_allowed no) - (uvia_min_size 0.2) - (uvia_min_drill 0.1) - (max_error 0.005) - (defaults - (edge_clearance 0.01) - (edge_cuts_line_width 0.05) - (courtyard_line_width 0.05) - (copper_line_width 0.2) - (copper_text_dims (size 1.5 1.5) (thickness 0.3) keep_upright) - (silk_line_width 0.12) - (silk_text_dims (size 1 1) (thickness 0.15) keep_upright) - (other_layers_line_width 0.1) - (other_layers_text_dims (size 1 1) (thickness 0.15) keep_upright) - ) - (pad_size 3.14159 3.14159) - (pad_drill 1.41421) - (pad_to_mask_clearance 0.051) - (solder_mask_min_width 0.25) - (aux_axis_origin 0 0) - (visible_elements FFFFFF7F) - (pcbplotparams - (layerselection 0x010fc_ffffffff) - (usegerberextensions false) - (usegerberattributes false) - (usegerberadvancedattributes false) - (creategerberjobfile false) - (excludeedgelayer true) - (linewidth 0.100000) - (plotframeref false) - (viasonmask false) - (mode 1) - (useauxorigin false) - (hpglpennumber 1) - (hpglpenspeed 20) - (hpglpendiameter 15.000000) - (psnegative false) - (psa4output false) - (plotreference true) - (plotvalue true) - (plotinvisibletext false) - (padsonsilk false) - (subtractmaskfromsilk false) - (outputformat 1) - (mirror false) - (drillshape 1) - (scaleselection 1) - (outputdirectory "")) - ) - - (net 0 "") - {{net_defs}} - - (net_class "Default" "This is the default net class." - (clearance 0.2) - (trace_width 0.25) - (via_dia 0.8) - (via_drill 0.4) - (uvia_dia 0.3) - (uvia_drill 0.1) - {{net_class_defs}} - ) - - {{module_defs}} - - {{edge_cuts}} - )''' - - module_defs = [] - for i, pin in enumerate(pins): - (x, y), hole_dia = pin # all dimensions in mm here - pad_dia = hole_dia + 2*annular - mod = f''' - (module "Pogopin:AutogeneratedPogopinFootprint" (layer "F.Cu") (tedit {TEDIT_BASE + i:08X}) (tstamp {PIN_TS_BASE + i:08X}) - (at {x} {y}) - (descr "Pogo pin {i}") - (tags "test point plated hole") - (path "/{PATH_BASE + i:08X}") - (attr virtual) - (fp_text reference "TP{i}" (at 0 -{pad_dia/2 + 1}) (layer "F.SilkS") - (effects (font (size 1 1) (thickness 0.15))) - ) - (fp_text value "pogo pin {i}" (at 0 {pad_dia/2 + 1}) (layer "F.Fab") - (effects (font (size 1 1) (thickness 0.15))) - ) - (fp_text user "%R" (at 0 -{pad_dia/2 + 1}) (layer "F.Fab") - (effects (font (size 1 1) (thickness 0.15))) - ) - (fp_circle (center 0 0) (end {pad_dia} 0) (layer "F.CrtYd") (width 0.05)) - (fp_circle (center 0 0) (end 0 -{pad_dia}) (layer "F.SilkS") (width 0.12)) - (pad "1" thru_hole circle (at 0 0) (size {pad_dia} {pad_dia}) (drill {hole_dia}) (layers *.Cu *.Mask) - (net {i+1} "pogo{i}")) - )''' - module_defs.append(mod) - - edge_cuts = [ f'(gr_line (start {x1} {y1}) (end {x2} {y2}) (layer "Edge.Cuts") (width 0.05))' - for (x1, y1), (x2, y2) in outline ] - - net_defs = [ f'(net {i+1} "pogo{i}")' for i, _pin in enumerate(pins) ] - net_class_defs = [ f'(add_net "pogo{i}")' for i, _pin in enumerate(pins) ] - return pcb_templ.format( - net_defs='\n'.join(net_defs), - net_class_defs='\n'.join(net_class_defs), - module_defs='\n'.join(module_defs), - edge_cuts='\n'.join(edge_cuts)) - -def inkscape_query_all(filename): - proc = subprocess.run([ os.environ.get('INKSCAPE', 'inkscape'), filename, '--query-all'], capture_output=True) - proc.check_returncode() - data = [ line.split(',') for line in proc.stdout.decode().splitlines() ] - return { id: (float(x), float(y), float(w), float(h)) for id, x, y, w, h in data } - -SVG_NS = { - 'svg': 'http://www.w3.org/2000/svg', - 'inkscape': 'http://www.inkscape.org/namespaces/inkscape', - 'sodipodi': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' -} - -def svg_find_elements(doc, tag, layer=None): - for i, g in enumerate(doc.findall('svg:g', SVG_NS)): - if g.attrib.get(f'{{{SVG_NS["inkscape"]}}}groupmode') != 'layer': - continue - - label = g.attrib.get(f'{{{SVG_NS["inkscape"]}}}label', '') - if not layer or label == layer: - yield from g.iter(tag) - -# def svg_get_scale(doc): -# w = doc.attrib['width'] -# h = doc.attrib['height'] -# -# if not w.endswith('mm') and h.endswith('mm'): -# raise ValueError('Document dimensions in SVG must be set to millimeters') -# -# w, h = float(w[:-2]), float(h[:-2]) -# _x, _y, vb_w, vb_h = map(float, doc.attrib['viewBox'].split()) -# scale_x, scale_y = vb_w / w, vb_h / h -# assert abs(1 - scale_x/scale_y) < 0.001 -# return scale_x - -def svg_get_viewbox_mm(doc): - w = doc.attrib['width'] - h = doc.attrib['height'] - - if not w.endswith('mm') and h.endswith('mm'): - raise ValueError('Document dimensions in SVG must be set to millimeters') - - w, h = float(w[:-2]), float(h[:-2]) - x, y, vb_w, vb_h = map(float, doc.attrib['viewBox'].split()) - scale_x, scale_y = vb_w / w, vb_h / h - return x/scale_x, y/scale_y, w, h - -if __name__ == '__main__': - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('svg', metavar='pogo_map.svg', help='Input inkscape SVG pogo pin map (use provided template!)') - parser.add_argument('outline', metavar='outline.dxf', help='Board outline DXF generated by OpenSCAD') - parser.add_argument('output', default='kicad', help='Output directory/project name and path') - parser.add_argument('-y', '--yspace', type=int, default=200, help='Schematic pin Y spacing in mil (default: 200)') - parser.add_argument('-a', '--annular', type=float, default=0.5, help='Pogo pin annular ring width in mm (default: 0.5)') - parser.add_argument('-l', '--svg-layer', type=str, default='Test Points', help='Name of SVG layer containing pogo pins') - parser.add_argument('-n', '--name', default='jig', help='Output KiCAD project name') - args = parser.parse_args() - - if not path.exists(args.output): - os.mkdir(args.output) - - if not path.isdir(args.output): - raise SystemError(f'Output path "{args.output}" is not a directory') - - with open(args.svg, 'r') as f: - doc = xe.fromstring(f.read()) - pogo_circle_ids = [ circle.attrib['id'] for circle in svg_find_elements(doc, f'{{{SVG_NS["svg"]}}}circle', args.svg_layer) ] - # scale = svg_get_scale(doc) - page_x, page_y, page_w, page_h = svg_get_viewbox_mm(doc) - MM_PER_IN = 25.4 - SVG_DEF_DPI = 96 - px_to_mm = lambda px: px/SVG_DEF_DPI * MM_PER_IN - query = inkscape_query_all(args.svg) - dims = [ query[id] for id in pogo_circle_ids ] - assert all( abs(1 - w/h) < 0.001 for _x, _y, w, h in dims ) - print('origin:', page_x, page_y) - print('dims:', page_w, page_h) - pins = [ ( - (page_x + px_to_mm(x) + px_to_mm(w)/2, - page_y - page_h + px_to_mm(y) + px_to_mm(w)/2), - px_to_mm(w)) for x, y, w, h in dims ] - - doc = ezdxf.readfile(args.outline) - outline = [] - for line in doc.modelspace().query('LINE'): - (x1, y1, _z1), (x2, y2, _z2) = line.dxf.start, line.dxf.end - outline.append(((x1, -y1), (x2, -y2))) - - with open(path.join(args.output, f'{args.name}.sch'), 'w', encoding='utf8') as sch: - sch.write(sch_template(f'{args.name} generated schematic (PogoJig v{__version__})', len(pins), yspace=args.yspace)) - - with open(path.join(args.output, f'{args.name}.kicad_pcb'), 'w', encoding='utf8') as pcb: - pcb.write(pcb_template(outline, pins, annular=args.annular)) - - with open(path.join(args.output, f'{args.name}.pro'), 'w', encoding='utf8') as f: - f.write(pkgutil.get_data('pogojig.kicad', 'kicad.pro').decode('utf8')) - - with open(path.join(args.output, f'{args.name}-cache.lib'), 'w', encoding='utf8') as f: - f.write(pkgutil.get_data('pogojig.kicad', 'kicad-cache.lib').decode('utf8')) - diff --git a/support/inkscape_exporter.py b/support/inkscape_exporter.py deleted file mode 100755 index 25fcabe..0000000 --- a/support/inkscape_exporter.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import tempfile - -from pogojig.inkscape import effect, inkscape - -from xvfbwrapper import Xvfb - - -def _unfuck_svg_document(temp_svg_path): - """ - Unfucks an SVG document so is can be processed by the better_dxf_export - plugin (or what's left of it). - """ - command_line = inkscape.InkscapeCommandLine(temp_svg_path) - layers = command_line.layers - - command_line.apply_to_document('LayerUnlockAll', 'LayerShowAll') - - layer_copies = [] - - for i in layers: - layer_copy = command_line.duplicate_layer(i) - layer_copies.append(layer_copy) - - command_line.apply_to_layer_content(layer_copy, 'ObjectToPath') - command_line.apply_to_layer_content(layer_copy, 'SelectionUnGroup') - - if not i.use_paths: - command_line.apply_to_layer_content(layer_copy, 'StrokeToPath') - command_line.apply_to_layer_content(layer_copy, 'SelectionUnion') - - for original, copy in zip(layers, layer_copies): - command_line.clear_layer(original) - command_line.move_content(copy, original) - command_line.delete_layer(copy) - - command_line.apply_to_document('FileSave', 'FileClose', 'FileQuit') - command_line.run() - - -if __name__ == '__main__': - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('infile', metavar='input.svg', help='Inkscape SVG input file') - parser.add_argument('outfile', metavar='output.dxf', help='DXF output file') - args = parser.parse_args() - - with Xvfb(): - effect.ExportEffect.check_document_units(args.infile) - - with tempfile.TemporaryDirectory() as tmpdir: - temp_svg_path = os.path.join(tmpdir, os.path.basename(args.infile)) - shutil.copyfile(args.infile, temp_svg_path) - - _unfuck_svg_document(temp_svg_path) - - export_effect = effect.ExportEffect() - export_effect.affect(args=[temp_svg_path], output=False) - - with open(args.outfile, 'w') as f: - export_effect.write_dxf(f) - diff --git a/support/inkscape_svg_filter_layers.py b/support/inkscape_svg_filter_layers.py deleted file mode 100755 index 9301e1e..0000000 --- a/support/inkscape_svg_filter_layers.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -import xml.etree.ElementTree as xe -import argparse -import re - - -if __name__ != '__main__': - raise SystemError('Not running as shell script') - - -parser = argparse.ArgumentParser() -parser.add_argument('infile', metavar='input.svg', type=argparse.FileType('r')) -parser.add_argument('outfile', metavar='output.svg', type=argparse.FileType('wb')) -parser.add_argument('-n', '--name', nargs='+', default=[], help='Remove layers with this exact name (case-insensitive)') -parser.add_argument('-r', '--regex', nargs='+', default=[], help='Remove layers with names matching this regex') -parser.add_argument('-i', '--invisible', action='store_true', help='Remove hidden (invisible) layers') -parser.add_argument('-o', '--only', action='store_true', help='Invert logic, i.e. keep matched layers and discard others') -parser.add_argument('-d', '--strip-defs', action='store_true', help='Also strip any <defs> tags (off by default)') -args = parser.parse_args() - -doc = xe.fromstring(args.infile.read()) -ns = { - 'svg': 'http://www.w3.org/2000/svg', - 'inkscape': 'http://www.inkscape.org/namespaces/inkscape', - 'sodipodi': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' -} - -if args.strip_defs: - for elem in doc.findall('svg:defs', ns): - doc.remove(elem) - -for i, g in enumerate(doc.findall('svg:g', ns)): - if g.attrib.get(f'{{{ns["inkscape"]}}}groupmode') != 'layer': - continue - - label = g.attrib.get(f'{{{ns["inkscape"]}}}label', '') - match = ( - any(label == name for name in args.name) or - any(re.match(regex, label) for regex in args.regex) or - ('display:none' in g.attrib.get('style', '') and args.hidden) - ) - print(f'Layer {i} "{label}": {"match" if match else "not found"}', end='') - - if match != args.only: - print(', removing.') - doc.remove(g) - else: - print() - -args.outfile.write(xe.tostring(doc)) diff --git a/support/pogojig/__init__.py b/support/pogojig/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/support/pogojig/__init__.py +++ /dev/null diff --git a/support/pogojig/inkscape/__init__.py b/support/pogojig/inkscape/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/support/pogojig/inkscape/__init__.py +++ /dev/null diff --git a/support/pogojig/inkscape/bezmisc.py b/support/pogojig/inkscape/bezmisc.py deleted file mode 100644 index 68a338d..0000000 --- a/support/pogojig/inkscape/bezmisc.py +++ /dev/null @@ -1,287 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(points): - #parametric bezier - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = points - 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(line, bezier): - #parametric line - ((lx1,ly1),(lx2,ly2)) = line - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = bezier - 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(xxx_todo_changeme3,t): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme3 - 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(xxx_todo_changeme4,t): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme4 - 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(xxx_todo_changeme5, xxx_todo_changeme6): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme5 - (dy,dx) = xxx_todo_changeme6 - ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))) - #quadratic coefficents 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(xxx_todo_changeme7, xxx_todo_changeme8,t): - (x1,y1) = xxx_todo_changeme7 - (x2,y2) = xxx_todo_changeme8 - return x1+t*(x2-x1),y1+t*(y2-y1) -def beziersplitatt(xxx_todo_changeme9,t): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme9 - 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(xxx_todo_changeme10, xxx_todo_changeme11): - (x1,y1) = xxx_todo_changeme10 - (x2,y2) = xxx_todo_changeme11 - 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 range(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(xxx_todo_changeme12, tolerance = 0.001): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme12 - 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(xxx_todo_changeme13, l = 0.5, tolerance = 0.001): - ((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)) = xxx_todo_changeme13 - 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__': - #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/support/pogojig/inkscape/cspsubdiv.py b/support/pogojig/inkscape/cspsubdiv.py deleted file mode 100644 index 72da473..0000000 --- a/support/pogojig/inkscape/cspsubdiv.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -from .bezmisc import * -from .ffgeom import * - -def maxdist(points): - ((p0x,p0y),(p1x,p1y),(p2x,p2y),(p3x,p3y)) = points - 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/support/pogojig/inkscape/cubicsuperpath.py b/support/pogojig/inkscape/cubicsuperpath.py deleted file mode 100644 index a594660..0000000 --- a/support/pogojig/inkscape/cubicsuperpath.py +++ /dev/null @@ -1,174 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" -from . 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]) - - 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]) - - # Use exact coordinates for the endpoints. This prevents small drifts when relative coordinates are used and guarantees that a path ending with a z command closes perfectly. - p[0][0] = p1[:] - p[0][1] = p1[:] - p[-1][1] = [x2, y2] - p[-1][2] = [x2, y2] - - 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/support/pogojig/inkscape/dxf_footer.txt b/support/pogojig/inkscape/dxf_footer.txt deleted file mode 100644 index a225dd7..0000000 --- a/support/pogojig/inkscape/dxf_footer.txt +++ /dev/null @@ -1,62 +0,0 @@ -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/support/pogojig/inkscape/dxf_header.txt b/support/pogojig/inkscape/dxf_header.txt deleted file mode 100644 index 341cb1b..0000000 --- a/support/pogojig/inkscape/dxf_header.txt +++ /dev/null @@ -1,580 +0,0 @@ -0 -SECTION -2 -HEADER -9 -$ACADVER -1 -AC1014 -9 -$HANDSEED -5 -FFFF -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 -4.25 -22 -5.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 -11 -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 -2 -LAYER -5 -2 -330 -0 -100 -AcDbSymbolTable -70 -1 -0 -LAYER -5 -10 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord -2 -0 -70 -0 -62 -7 -6 -CONTINUOUS -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 diff --git a/support/pogojig/inkscape/effect.py b/support/pogojig/inkscape/effect.py deleted file mode 100644 index 89824e9..0000000 --- a/support/pogojig/inkscape/effect.py +++ /dev/null @@ -1,279 +0,0 @@ -""" -Based on code from Aaron Spike. See -http://www.bobcookdev.com/inkscape/inkscape-dxf.html -""" - -import collections -import itertools -import os -import pkgutil -import re -from lxml import etree - -from . import inkex, simpletransform, cubicsuperpath, cspsubdiv, inkscape - - -def _get_unit_factors_map(): - # Fluctuates somewhat between Inkscape releases _and_ between SVG version. - pixels_per_inch = 96. - pixels_per_mm = pixels_per_inch / 25.4 - - return { - 'px': 1.0, - 'mm': pixels_per_mm, - 'cm': pixels_per_mm * 10, - 'm': pixels_per_mm * 1e3, - 'km': pixels_per_mm * 1e6, - 'pt': pixels_per_inch / 72, - 'pc': pixels_per_inch / 6, - 'in': pixels_per_inch, - 'ft': pixels_per_inch * 12, - 'yd': pixels_per_inch * 36} - - -class ExportEffect(inkex.Effect): - _unit_factors = _get_unit_factors_map() - _asymptote_all_paths_name = 'all' - - def __init__(self): - inkex.Effect.__init__(self) - - self._flatness = float(os.environ.get('INKSCAPE_DXF_FLATNESS', 0.1)) - - self._layers = None - self._paths = None - - def _get_document_scale(self): - """ - Return scaling factor applied to the document because of a viewBox - setting. This currently ignores any setting of a preserveAspectRatio - attribute (like Inkscape). - """ - document_height = self._get_height() - view_box = self._get_view_box() - - if view_box is None or document_height is None: - return 1 - else: - _, _, _, view_box_height = view_box - - return document_height / view_box_height - - def _get_document_height(self): - """ - Get the height of the document in pixels in the document coordinate - system as it is interpreted by Inkscape. - """ - view_box = self._get_view_box() - document_height = self._get_height() - - if view_box is not None: - _, _, _, view_box_height = view_box - - return view_box_height - elif document_height is not None: - return document_height - else: - return 0 - - def _get_height(self): - height_attr = self.document.getroot().get('height') - - if height_attr is None: - return None - else: - return self._measure_to_pixels(height_attr) - - def _get_view_box(self): - view_box_attr = self.document.getroot().get('viewBox') - - if view_box_attr is None: - return None - else: - return [float(i) for i in view_box_attr.split()] - - def _get_shape_paths(self, node, transform): - shape = cubicsuperpath.parsePath(node.get('d')) - - transform = simpletransform.composeTransform( - transform, - simpletransform.composeParents(node, [[1, 0, 0], [0, 1, 0]])) - - simpletransform.applyTransformToPath(transform, shape) - - def iter_paths(): - for path in shape: - cspsubdiv.subdiv(path, self._flatness) - - # path contains two control point coordinates and the actual - # coordinates per point. - yield [i for _, i, _ in path] - - return list(iter_paths()) - - def effect(self): - document_height = self._get_document_height() - document_scale = self._get_document_scale() - - transform = simpletransform.composeTransform( - [[document_scale, 0, 0], [0, document_scale, 0]], - [[1, 0, 0], [0, -1, document_height]]) - - layers = inkscape.get_inkscape_layers(self.svg_file) - layers_by_inkscape_name = {i.inkscape_name: i for i in layers} - - def iter_paths(): - for node in self.document.getroot().xpath('//svg:path', namespaces=inkex.NSS): - layer = layers_by_inkscape_name.get(self._get_inkscape_layer_name(node)) - - for path in self._get_shape_paths(node, transform): - yield layer, path - - self._layers = layers - self._paths = list(iter_paths()) - - def write_dxf(self, file): - # Scales pixels to millimeters. This is the predominant unit in CAD. - unit_factor = self._unit_factors['mm'] - - layer_indices = {l: i for i, l in enumerate(self._layers)} - - file.write(pkgutil.get_data(__name__, 'dxf_header.txt').decode('ASCII')) - - def write_instruction(code, value): - print(code, file=file) - print(value, file=file) - - handle_iter = itertools.count(256) - - for layer, path in self._paths: - for (x1, y1), (x2, y2) in zip(path, path[1:]): - write_instruction(0, 'LINE') - - if layer is not None: - write_instruction(8, layer.export_name) - write_instruction(62, layer_indices.get(layer, 0)) - - write_instruction(5, '{:x}'.format(next(handle_iter))) - write_instruction(100, 'AcDbEntity') - write_instruction(100, 'AcDbLine') - write_instruction(10, repr(x1 / unit_factor)) - write_instruction(20, repr(y1 / unit_factor)) - write_instruction(30, 0.0) - write_instruction(11, repr(x2 / unit_factor)) - write_instruction(21, repr(y2 / unit_factor)) - write_instruction(31, 0.0) - - file.write(pkgutil.get_data(__name__, 'dxf_footer.txt').decode('ASCII')) - - def write_asy(self, file): - def write_line(format, *args): - print >> file, format.format(*args) + ';' - - # Scales pixels to points. Asymptote uses PostScript points (1 / 72 - # inch) by default. - unit_factor = self._unit_factors['pt'] - - paths_by_layer = collections.defaultdict(list) - variable_names = [] - - for layer, path in self._paths: - paths_by_layer[layer].append(path) - - for layer in self._layers + [None]: - paths = paths_by_layer[layer] - variable_name = self._asymptote_identifier_from_layer(layer) - write_line('path[] {}', variable_name) - - variable_names.append(variable_name) - - for path in paths: - point_strs = ['({}, {})'.format(x / unit_factor, y / unit_factor) for x, y in path] - - # Hack. We should determine this from whether Z or z was used - # to close the path in the SVG document. - if path[0] == path[-1]: - point_strs[-1] = 'cycle' - - write_line('{}.push({})', variable_name, ' -- '.join(point_strs)) - - if self._asymptote_all_paths_name not in variable_names: - write_line('path[] {}', self._asymptote_all_paths_name) - - for i in variable_names: - write_line('{}.append({})', self._asymptote_all_paths_name, i) - - @classmethod - def _parse_measure(cls, string): - value_match = re.match(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)', string) - unit_match = re.search('(%s)$' % '|'.join(cls._unit_factors.keys()), string) - - value = float(string[value_match.start():value_match.end()]) - - if unit_match: - unit = string[unit_match.start():unit_match.end()] - else: - unit = None - - return value, unit - - @classmethod - def _measure_to_pixels(cls, string): - """ - Parse a string containing a measure and return it's value converted - to pixels. - """ - value, unit = cls._parse_measure(string) - - return value * cls._get_unit_factor(unit) - - @classmethod - def _get_inkscape_layer_name(cls, node): - while node is not None: - layer = node.get(inkex.addNS('label', 'inkscape')) - - if layer is not None: - return layer - - node = node.getparent() - - return None - - @classmethod - def _get_unit_factor(cls, unit): - if unit is None: - return 1 - else: - return cls._unit_factors[unit] - - @classmethod - def _asymptote_identifier_from_layer(cls, layer): - if layer is None: - return '_' - else: - return re.sub('[^a-zA-Z0-9]', '_', layer.export_name) - - @classmethod - def check_document_units(cls, path): - with open(path, 'r') as file: - p = etree.XMLParser(huge_tree = True) - document = etree.parse(file, parser = p) - - height_attr = document.getroot().get('height') - - if height_attr is None: - raise ValueError( - 'SVG document has no height attribute. See ' - 'https://github.com/Feuermurmel/openscad-template/wiki/Absolute-Measurements') - - _, height_unit = cls._parse_measure(height_attr) - - if height_unit is None or height_unit == 'px': - raise ValueError( - 'Height of SVG document is not an absolute measure. See ' - 'https://github.com/Feuermurmel/openscad-template/wiki/Absolute-Measurements') - - if document.getroot().get('viewBox') is None: - raise ValueError( - 'SVG document has no viewBox attribute. See ' - 'https://github.com/Feuermurmel/openscad-template/wiki/Absolute-Measurements') diff --git a/support/pogojig/inkscape/ffgeom.py b/support/pogojig/inkscape/ffgeom.py deleted file mode 100644 index 368a29a..0000000 --- a/support/pogojig/inkscape/ffgeom.py +++ /dev/null @@ -1,137 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" -import math - -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 math.nan - def intercept(self): - if self.delta_x() != 0: - return self[1]['y'] - (self[0]['x'] * self.slope()) - return math.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 math.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(math.nan, math.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(math.nan, math.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(math.nan, math.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/support/pogojig/inkscape/inkex.py b/support/pogojig/inkscape/inkex.py deleted file mode 100644 index 609ffeb..0000000 --- a/support/pogojig/inkscape/inkex.py +++ /dev/null @@ -1,363 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" -import copy -import gettext -import optparse -import os -import random -import re -import sys -from math import * - -from lxml import etree - -#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.localize() - ... - 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): - if (a-b <= a*eps) and (a-b >= -a*eps): - return True - else: - return False - -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!=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") - - def effect(self): - 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 != None: - try: - stream = open(filename, 'r') - except Exception: - 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 != None: - try: - stream = open(self.svg_file, 'r') - except Exception: - 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.document.getroot().get('height')) - 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 - break - - - 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] - 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} - - # Function returns the unit used for the values in SVG. - # For lack of an attribute in SVG that explicitly defines what units are used for SVG coordinates, - # try to calculate the unit from the SVG width and SVG viewbox. - # Defaults to 'px' units. - def getDocumentUnit(self): - svgunit = 'px' #default to pixels - - svgwidth = self.document.getroot().get('width') - 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/support/pogojig/inkscape/inkscape.py b/support/pogojig/inkscape/inkscape.py deleted file mode 100644 index efe7677..0000000 --- a/support/pogojig/inkscape/inkscape.py +++ /dev/null @@ -1,124 +0,0 @@ -import os -import subprocess -import xml.etree.ElementTree as etree - -def get_inkscape_layers(svg_path): - document = etree.parse(svg_path) - - layers = [] - nodes = document.findall( - '{http://www.w3.org/2000/svg}g[@{http://www.inkscape.org/namespaces/inkscape}groupmode="layer"]') - - for i in nodes: - inkscape_name = i.get('{http://www.inkscape.org/namespaces/inkscape}label').strip() - - if inkscape_name.endswith(']'): - export_name, args = inkscape_name[:-1].rsplit('[', 1) - - export_name = export_name.strip() - args = args.strip() - - use_paths = 'p' in args - else: - use_paths = False - export_name = inkscape_name - - layers.append(Layer(inkscape_name, export_name, use_paths)) - return layers - - -def _inkscape(svg_path, verbs): - subprocess.run([os.environ.get('INKSCAPE', 'inkscape'), *(x for verb in verbs for x in ('--verb', verb)), svg_path]) - - -class Layer(object): - def __init__(self, inkscape_name, export_name, use_paths): - self.inkscape_name = inkscape_name - self.export_name = export_name - self.use_paths = use_paths - - -class InkscapeCommandLine(object): - def __init__(self, path): - self._path = path - self._layers = get_inkscape_layers(path) - self._current_layer_index = None - self._verbs = [] - - def apply_to_document(self, *verb): - self._verbs.extend(verb) - - def apply_to_layer(self, layer, *verb): - self._go_to_layer(layer) - self.apply_to_document(*verb) - - def select_all_in_layer(self, layer): - self.apply_to_layer(layer, 'EditSelectAll') - - def apply_to_layer_content(self, layer, *verbs): - self.select_all_in_layer(layer) - self.apply_to_document(*verbs) - - def _go_to_layer(self, layer, with_selection=False): - if self._current_layer_index is None: - # Initialize to a known state. We cannot assume that any layer is - # selected and thus we need as many LayerPrev as we have layers. - self._current_layer_index = len(self._layers) - self._go_to_layer(self._layers[0]) - - target_index = self._layers.index(layer) - - if with_selection: - next_command = 'LayerMoveToNext' - previous_command = 'LayerMoveToPrev' - else: - next_command = 'LayerNext' - previous_command = 'LayerPrev' - - while self._current_layer_index != target_index: - if self._current_layer_index < target_index: - self.apply_to_document(next_command) - self._current_layer_index += 1 - else: - self.apply_to_document(previous_command) - self._current_layer_index -= 1 - - if with_selection: - # When using LayerMoveToNext and LayerMoveToPrev, inkscape does - # not reliably select the next/previous layer. - self._current_layer_index = None - - def duplicate_layer(self, layer): - self.apply_to_layer(layer, 'LayerDuplicate') - - # Inkscape 0.91 places a duplicated layer above (after) the selected - # one and selects the new layer. - new_layer = Layer(layer.inkscape_name + ' copy', layer.export_name, layer.use_paths) - self._layers.insert(self._current_layer_index + 1, new_layer) - - # Whether the original or the new layer is selected after the operation - # fluctuates between Inkscape versions. - self._current_layer_index = None - - return new_layer - - def delete_layer(self, layer): - self.apply_to_layer(layer, 'LayerDelete') - - # Inkscape 0.91 selects the layer above (after) the deleted layer. - del self._layers[self._current_layer_index] - - def clear_layer(self, layer): - self.select_all_in_layer(layer) - self.apply_to_document('EditDelete') - - def move_content(self, source_layer, target_layer): - self.select_all_in_layer(source_layer) - self._go_to_layer(target_layer, True) - - def run(self): - _inkscape(self._path, self._verbs) - - @property - def layers(self): - return list(self._layers) diff --git a/support/pogojig/inkscape/simplepath.py b/support/pogojig/inkscape/simplepath.py deleted file mode 100644 index 8d4f0a7..0000000 --- a/support/pogojig/inkscape/simplepath.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -""" -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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 ValueError('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 = next(lexer) - except StopIteration: - break - params = [] - needParam = True - if isCommand: - if not lastCommand and token.upper() != 'M': - raise ValueError('Invalid path, must begin with moveto.') - else: - command = token - else: - #command was omited - #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 ValueError('Invalid path, no initial command.') - numParams = pathdefs[command.upper()][1] - while numParams > 0: - if needParam: - try: - token, isCommand = next(lexer) - if isCommand: - raise ValueError('Invalid number of parameters') - except StopIteration: - raise ValueError('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/support/pogojig/inkscape/simpletransform.py b/support/pogojig/inkscape/simpletransform.py deleted file mode 100644 index 610cb57..0000000 --- a/support/pogojig/inkscape/simpletransform.py +++ /dev/null @@ -1,242 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -barraud@math.univ-lille1.fr - -This code defines several functions to make handling of transform -attribute easier. -''' - -import math, re - -from . import inkex, cubicsuperpath - -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 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 - - -# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/support/pogojig/kicad/__init__.py b/support/pogojig/kicad/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/support/pogojig/kicad/__init__.py +++ /dev/null diff --git a/support/pogojig/kicad/kicad-cache.lib b/support/pogojig/kicad/kicad-cache.lib deleted file mode 100644 index a98cd73..0000000 --- a/support/pogojig/kicad/kicad-cache.lib +++ /dev/null @@ -1,21 +0,0 @@ -EESchema-LIBRARY Version 2.4 -#encoding utf-8 -# -# Connector_Conn_01x01_Female -# -DEF Connector_Conn_01x01_Female J 0 40 Y N 1 F N -F0 "J" 0 100 50 H V C CNN -F1 "Connector_Conn_01x01_Female" 0 -100 50 H V C CNN -F2 "" 0 0 50 H I C CNN -F3 "" 0 0 50 H I C CNN -$FPLIST - Connector*:* -$ENDFPLIST -DRAW -A 0 0 20 901 -901 1 1 6 N 0 20 0 -20 -P 2 1 1 6 -50 0 -20 0 N -X Pin_1 1 -200 0 150 R 50 50 1 1 P -ENDDRAW -ENDDEF -# -#End Library diff --git a/support/pogojig/kicad/kicad.pro b/support/pogojig/kicad/kicad.pro deleted file mode 100644 index 5cd0983..0000000 --- a/support/pogojig/kicad/kicad.pro +++ /dev/null @@ -1,34 +0,0 @@ -update=05/04/2019 20:44:53 -version=1 -last_client=kicad -[general] -version=1 -RootSch= -BoardNm= -[pcbnew] -version=1 -LastNetListRead= -UseCmpFile=1 -PadDrill=0.600000000000 -PadDrillOvalY=0.600000000000 -PadSizeH=1.500000000000 -PadSizeV=1.500000000000 -PcbTextSizeV=1.500000000000 -PcbTextSizeH=1.500000000000 -PcbTextThickness=0.300000000000 -ModuleTextSizeV=1.000000000000 -ModuleTextSizeH=1.000000000000 -ModuleTextSizeThickness=0.150000000000 -SolderMaskClearance=0.000000000000 -SolderMaskMinWidth=0.000000000000 -DrawSegmentWidth=0.200000000000 -BoardOutlineThickness=0.100000000000 -ModuleOutlineThickness=0.150000000000 -CopperEdgeClearance=0.000000000000 -[cvpcb] -version=1 -NetIExt=net -[eeschema] -version=1 -LibDir= -[eeschema/libraries] |