diff --git a/CHANGELOG.md b/CHANGELOG.md index eee9817..04296cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ - Fixing error on treating polylines and polygones - Verbose option to add name of shapes and layers - Converting line tag +- Transformation matrix for nodes ### Security ## v2.1.0 - 2023/06/28 diff --git a/svg2tikz/tikz_export.py b/svg2tikz/tikz_export.py index a9eb8b8..751bbcc 100644 --- a/svg2tikz/tikz_export.py +++ b/svg2tikz/tikz_export.py @@ -390,6 +390,14 @@ def marking_interpret(marker): return raw_marker +def options_to_str(options: list) -> str: + """ + Convert a list of options to a str with comma separated value. + If the list is empty, return an empty str + """ + return f"[{','.join(options)}]" if len(options) > 0 else "" + + def return_arg_parser_doc(): """ Methode to return the arg parser of TikzPathExporter to help generate the doc @@ -858,7 +866,7 @@ def style_to_tz(self, node=None): return options - def trans_to_tz(self, node=None): + def trans_to_tz(self, node=None, is_node=False): """ Convert inkex transform to tikz code """ @@ -876,9 +884,13 @@ def trans_to_tz(self, node=None): if trans.is_translate(): tr = self.convert_unit_coord(Vector2d(trans.e, trans.f), False) - if not self.options.noreversey: + # Global scale do not impact transform + if not self.options.noreversey or is_node: tr.y *= -1 + tr.x *= self.options.scale + tr.y *= self.options.scale + options.append("shift={" + self.coord_to_tz(tr) + "}") # Rotation @@ -905,20 +917,25 @@ def trans_to_tz(self, node=None): options.append(f"xscale={x},yscale={y}") elif "matrix" in str(trans): + # print(trans) tr = self.convert_unit_coord(Vector2d(trans.e, trans.f), False) a = self.round_value(trans.a) b = self.round_value(trans.b) c = self.round_value(trans.c) d = self.round_value(trans.d) - if not self.options.noreversey: + # globalscale do not impact transform + if not self.options.noreversey or is_node: + tr.y *= -1 b *= -1 c *= -1 - tr.y *= -1 + if not self.options.noreversey and not is_node: tr.x += -c * self.update_height(0) - tr.y += self.update_height(0) * (1 - d) + tr.y += (1 - d) * self.update_height(0) + tr.x *= self.options.scale + tr.y *= self.options.scale options.append(f"cm={{ {a},{b},{c}" f",{d},{self.coord_to_tz(tr)}}}") # Not possible to get them directly @@ -1235,9 +1252,11 @@ def _handle_text(self, node): if trans.is_rotate(): # get angle ang = atan2(trans.b, trans.a) - p = self.rotate_coord(p, ang) + p = self.convert_unit_coord(self.rotate_coord(p, ang)) - p = self.round_coord(self.convert_unit_coord(p)) + # scale do not impact node + if self.options.noreversey: + p.y *= -1 return f"({node.get_id()}) at {self.coord_to_tz(p)}" + "{" + f"{textstr}" + "}" @@ -1245,6 +1264,7 @@ def get_text(self, node): """Return content of a text node as string""" return etree.tostring(node, method="text").decode("utf-8") + # pylint: disable=too-many-branches def _output_group(self, group): """Process a group of SVG nodes and return corresponding TikZ code @@ -1266,7 +1286,9 @@ def _output_group(self, group): string += self._handle_group(node) continue try: - goptions = self.style_to_tz(node) + self.trans_to_tz(node) + goptions = self.style_to_tz(node) + self.trans_to_tz( + node, node.TAG in ["text", "flowRoot", "image"] + ) except AttributeError as msg: attr = msg.args[0].split("attribute")[1].split(".")[0] logging.warning("%s attribute cannot be represented", attr) @@ -1277,7 +1299,7 @@ def _output_group(self, group): string += self.text_indent + f"%{node.get_id()}\n" if node.TAG == "path": - optionscode = f"[{','.join(goptions)}]" if len(goptions) > 0 else "" + optionscode = options_to_str(goptions) pathcode = f"\\path{optionscode} {self.convert_path_to_tikz(node.path)}" @@ -1285,8 +1307,7 @@ def _output_group(self, group): # Add indent pathcode, options = self._handle_shape(node) - goptions += options - optionscode = f"[{','.join(goptions)}]" if len(goptions) > 0 else "" + optionscode = options_to_str(goptions + options) pathcode = f"\\path{optionscode} {pathcode}" @@ -1301,7 +1322,7 @@ def _output_group(self, group): if not contains_anchor: goptions += ["anchor=south west"] - optionscode = f"[{','.join(goptions)}]" if len(goptions) > 0 else "" + optionscode = options_to_str(goptions) # Convert a rotate around to a rotate option if "rotate around={" in optionscode: splited_options = optionscode.split("rotate around={") diff --git a/tests/test_complete_files.py b/tests/test_complete_files.py index db12ae9..90e06f4 100644 --- a/tests/test_complete_files.py +++ b/tests/test_complete_files.py @@ -127,6 +127,11 @@ def test_wrap(self): filename = "rectangle_wrap" create_test_from_filename(filename, self, wrap=True) + def test_nodes_and_transform(self): + """Test complete convert transformation on nodes""" + filename = "nodes_and_transform" + create_test_from_filename(filename, self) + if __name__ == "__main__": unittest.main() diff --git a/tests/testfiles/nodes_and_transform.svg b/tests/testfiles/nodes_and_transform.svg new file mode 100644 index 0000000..999530a --- /dev/null +++ b/tests/testfiles/nodes_and_transform.svg @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Glabron + Manchuria + No. 457 + No. 462 + No. 475 + Peatland + Svansota + Trebi + Velvet + Wisconsin No. 38 + + + + + + variety + + + + + + + + + diff --git a/tests/testfiles/nodes_and_transform.tex b/tests/testfiles/nodes_and_transform.tex new file mode 100644 index 0000000..39e4978 --- /dev/null +++ b/tests/testfiles/nodes_and_transform.tex @@ -0,0 +1,124 @@ + +\documentclass{article} +\usepackage[utf8]{inputenc} +\usepackage{tikz} + +\begin{document} +\definecolor{c888888}{RGB}{136,136,136} + + +\def \globalscale {1.000000} +\begin{tikzpicture}[y=1cm, x=1cm, yscale=\globalscale,xscale=\globalscale, every node/.append style={scale=\globalscale}, inner sep=0pt, outer sep=0pt] + \begin{scope}[miter limit=10.0,shift={(5.9796, -0.2646)}] + \begin{scope}[miter limit=10.0] + \begin{scope}[miter limit=10.0] + \begin{scope}[miter limit=10.0] + \begin{scope}[miter limit=10.0] + \begin{scope}[miter limit=10.0,shift={(0.0265, -0.0265)}] + \begin{scope}[miter limit=10.0] + \begin{scope}[miter limit=10.0] + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -0.5292)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -1.5875)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -2.6458)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -3.7042)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -4.7625)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -5.8208)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -6.8792)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -7.9375)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -8.9958)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \path[draw=c888888,line width=0.0529cm,miter limit=10.0,shift={(0.0, -10.0542)}] (0.0, 12.8058) -- (-0.2646, 12.8058); + + + + \end{scope} + \begin{scope}[miter limit=10.0] + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -0.6615)}] (text34) at (0.0, 12.8058){Glabron}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -1.7198)}] (text35) at (0.0, 12.8058){Manchuria}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -2.7781)}] (text36) at (0.0, 12.8058){No. 457}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -3.8365)}] (text37) at (0.0, 12.8058){No. 462}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -4.8948)}] (text38) at (0.0, 12.8058){No. 475}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -5.9531)}] (text39) at (0.0, 12.8058){Peatland}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -7.0115)}] (text40) at (0.0, 12.8058){Svansota}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -8.0698)}] (text41) at (0.0, 12.8058){Trebi}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -9.1281)}] (text42) at (0.0, 12.8058){Velvet}; + + + + \node[text=black,anchor=south east,miter limit=10.0,shift={(-0.3704, -10.1865)}] (text43) at (0.0, 12.8058){Wisconsin No. 38}; + + + + \end{scope} + \begin{scope}[miter limit=10.0] + \path[draw=c888888,line width=0.0529cm,miter limit=10.0] (0.0, 12.8058) -- (0.0, 2.2225); + + + + \end{scope} + \begin{scope}[miter limit=10.0] + \node[text=black,anchor=south,miter limit=10.0,cm={ 0.0,1.0,-1.0,0.0,(-5.2211, -3.175)}] (text44) at (0.0, 12.8058){variety}; + + + + \end{scope} + \end{scope} + \end{scope} + \end{scope} + \end{scope} + \end{scope} + \end{scope} + \end{scope} + +\end{tikzpicture} +\end{document}