From 2ca55c2d170a914c1c0032ea23f1a2a183322dd3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 28 Aug 2015 01:23:34 +0200 Subject: Fixed empty layers missing from Asymptote export. Empty layers would not be included in the exported Asymptote file, making it hard to work with a set of SVG files with the same layers if some of the SVG files had empty layers. --- support/inkscape/effect.py | 84 +++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 38 deletions(-) (limited to 'support/inkscape') diff --git a/support/inkscape/effect.py b/support/inkscape/effect.py index b7eb771..45a6838 100644 --- a/support/inkscape/effect.py +++ b/support/inkscape/effect.py @@ -2,7 +2,7 @@ Based on code from Aaron Spike. See http://www.bobcookdev.com/inkscape/inkscape-dxf.html """ -import pkgutil, os, re, collections +import pkgutil, os, re, collections, itertools from . import inkex, simpletransform, cubicsuperpath, cspsubdiv, inkscape @@ -32,10 +32,9 @@ class ExportEffect(inkex.Effect): inkex.Effect.__init__(self) self._flatness = float(os.environ['DXF_FLATNESS']) - self._layers = None - self._layers_by_inkscape_name = None - self._paths = [] # Contains (layer : Layer | None, points : List[(float, float)]) + self._layers = None + self._paths = None def _get_user_unit(self): """ @@ -69,19 +68,8 @@ class ExportEffect(inkex.Effect): def _get_document_height_attr(self): return self.document.getroot().xpath('@height', namespaces = inkex.NSS)[0] - def _add_path(self, layer, path): - """ - Warning: Fucks up path. - """ - - cspsubdiv.subdiv(path, self._flatness) - - # path contains two control point coordinates and the actual coordinates per point. - self._paths.append((layer, [i for _, i, _ in path])) - - def _add_shape(self, node, document_transform, element_transform): + def _get_shape_paths(self, node, document_transform, element_transform): shape = cubicsuperpath.parsePath(node.get('d')) - layer = self._layers_by_inkscape_name.get(self._get_inkscape_layer_name(node)) transform = simpletransform.composeTransform( document_transform, @@ -89,21 +77,34 @@ class ExportEffect(inkex.Effect): simpletransform.applyTransformToPath(transform, shape) - for path in shape: - self._add_path(layer, path) + 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): - self._layers = inkscape.get_inkscape_layers(self.svg_file) - self._layers_by_inkscape_name = { i.inkscape_name: i for i in self._layers } - user_unit = self._get_user_unit() document_height = self._measure_to_pixels(self._get_document_height_attr()) document_transform = [[1, 0, 0], [0, -1, document_height]] element_transform = [[user_unit, 0, 0], [0, user_unit, 0]] - for node in self.document.getroot().xpath('//svg:path', namespaces = inkex.NSS): - self._add_shape(node, document_transform, element_transform) + 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, document_transform, element_transform): + yield layer, path + + self._layers = layers + self._paths = list(iter_paths()) def write_dxf(self, file): document_unit = self._get_document_unit() @@ -115,14 +116,17 @@ class ExportEffect(inkex.Effect): print >> file, code print >> file, value - handle = 256 + 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') - write_instruction(8, layer.export_name) - write_instruction(62, layer_indices.get(layer, 0)) - write_instruction(5, '{:x}'.format(handle)) + + 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 / document_unit)) @@ -131,8 +135,6 @@ class ExportEffect(inkex.Effect): write_instruction(11, repr(x2 / document_unit)) write_instruction(21, repr(y2 / document_unit)) write_instruction(31, 0.0) - - handle += 1 file.write(pkgutil.get_data(__name__, 'dxf_footer.txt')) @@ -142,28 +144,34 @@ class ExportEffect(inkex.Effect): # Scales pixels to points. unit_factor = self._unit_factors['pt'] - lines_by_layer_name = collections.defaultdict(list) + + paths_by_layer = collections.defaultdict(list) + variable_names = [] for layer, path in self._paths: - lines_by_layer_name[self._asymptote_identifier_from_layer(layer)].append(path) + paths_by_layer[layer].append(path) - for layer_name, paths in sorted(lines_by_layer_name.items()): - write_line('path[] {}', layer_name) + 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 from whether Z or z was used to close the path in the SVG document. + # 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({})', layer_name, ' -- '.join(point_strs)) + write_line('{}.push({})', variable_name, ' -- '.join(point_strs)) - if self._asymptote_all_paths_name not in lines_by_layer_name: + if self._asymptote_all_paths_name not in variable_names: write_line('path[] {}', self._asymptote_all_paths_name) - for layer_name in sorted(lines_by_layer_name): - write_line('{}.append({})', self._asymptote_all_paths_name, layer_name) + for i in variable_names: + write_line('{}.append({})', self._asymptote_all_paths_name, i) @classmethod def _parse_measure(cls, string): -- cgit