From 9163069dbeec823169b24c0c0b7426037c9ba11e Mon Sep 17 00:00:00 2001 From: ldevillez Date: Wed, 22 Nov 2023 17:58:02 +0100 Subject: [PATCH 1/5] WIP: rework cm matrix --- svg2tikz/tikz_export.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/svg2tikz/tikz_export.py b/svg2tikz/tikz_export.py index b2330d8..fa16465 100644 --- a/svg2tikz/tikz_export.py +++ b/svg2tikz/tikz_export.py @@ -876,8 +876,10 @@ 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: - tr.y *= -1 + # Global scale do not impact transform + tr.y *= -1 + tr.x *= self.options.scale + tr.y *= self.options.scale options.append("shift={" + self.coord_to_tz(tr) + "}") @@ -905,20 +907,23 @@ 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) + # globalscale do not impact transform + tr.y *= -1 + b *= -1 + c *= -1 if not self.options.noreversey: - b *= -1 - c *= -1 + tr.y += self.update_height(0) tr.y *= -1 - tr.x += -c * self.update_height(0) - tr.y += self.update_height(0) * (1 - d) - + 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 From 69bc5283b46f860d2438c6fe4392987553da6a66 Mon Sep 17 00:00:00 2001 From: ldevillez Date: Thu, 23 Nov 2023 09:09:09 +0100 Subject: [PATCH 2/5] WIP: apply the scale only on nodes --- svg2tikz/tikz_export.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/svg2tikz/tikz_export.py b/svg2tikz/tikz_export.py index fa16465..ef49c02 100644 --- a/svg2tikz/tikz_export.py +++ b/svg2tikz/tikz_export.py @@ -858,7 +858,7 @@ def style_to_tz(self, node=None): return options - def trans_to_tz(self, node=None): + def trans_to_tz(self, node=None, isNode=False): """ Convert inkex transform to tikz code """ @@ -877,7 +877,9 @@ def trans_to_tz(self, node=None): tr = self.convert_unit_coord(Vector2d(trans.e, trans.f), False) # Global scale do not impact transform - tr.y *= -1 + if not self.options.noreversey or isNode: + tr.y *= -1 + tr.x *= self.options.scale tr.y *= self.options.scale @@ -915,9 +917,10 @@ def trans_to_tz(self, node=None): d = self.round_value(trans.d) # globalscale do not impact transform - tr.y *= -1 - b *= -1 - c *= -1 + if not self.options.noreversey or isNode: + tr.y *= -1 + b *= -1 + c *= -1 if not self.options.noreversey: tr.y += self.update_height(0) tr.y *= -1 @@ -1240,9 +1243,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}" + "}" @@ -1271,7 +1276,8 @@ def _output_group(self, group): string += self._handle_group(node) continue try: - goptions = self.style_to_tz(node) + self.trans_to_tz(node) + isNode = node.TAG in ["text", "flowRoot", "image"] + goptions = self.style_to_tz(node) + self.trans_to_tz(node, isNode) except AttributeError as msg: attr = msg.args[0].split("attribute")[1].split(".")[0] logging.warning("%s attribute cannot be represented", attr) From 0cf015ce21bbae68e06eaf429bf70b44d78ca308 Mon Sep 17 00:00:00 2001 From: ldevillez Date: Tue, 28 Nov 2023 00:11:57 +0100 Subject: [PATCH 3/5] fix node transform and add test --- CHANGELOG.md | 1 + svg2tikz/tikz_export.py | 8 +- tests/test_complete_files.py | 5 + tests/testfiles/nodes_and_transform.svg | 266 ++++++++++++++++++++++++ tests/testfiles/nodes_and_transform.tex | 124 +++++++++++ 5 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 tests/testfiles/nodes_and_transform.svg create mode 100644 tests/testfiles/nodes_and_transform.tex diff --git a/CHANGELOG.md b/CHANGELOG.md index e63cfc7..d3751f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,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 ef49c02..ce9e424 100644 --- a/svg2tikz/tikz_export.py +++ b/svg2tikz/tikz_export.py @@ -921,9 +921,11 @@ def trans_to_tz(self, node=None, isNode=False): tr.y *= -1 b *= -1 c *= -1 - if not self.options.noreversey: - tr.y += self.update_height(0) - tr.y *= -1 + + if not self.options.noreversey and not isNode: + tr.x += -c * self.update_height(0) + tr.y += (1 - d) * self.update_height(0) + pass tr.x *= self.options.scale tr.y *= self.options.scale 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..62cc9e9 --- /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, 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} From 78d8eb9a1604831ef85a7a577be111fb56f39561 Mon Sep 17 00:00:00 2001 From: ldevillez Date: Tue, 28 Nov 2023 00:30:17 +0100 Subject: [PATCH 4/5] pylint --- svg2tikz/tikz_export.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/svg2tikz/tikz_export.py b/svg2tikz/tikz_export.py index ce9e424..4330a6a 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, isNode=False): + def trans_to_tz(self, node=None, is_node=False): """ Convert inkex transform to tikz code """ @@ -877,7 +885,7 @@ def trans_to_tz(self, node=None, isNode=False): tr = self.convert_unit_coord(Vector2d(trans.e, trans.f), False) # Global scale do not impact transform - if not self.options.noreversey or isNode: + if not self.options.noreversey or is_node: tr.y *= -1 tr.x *= self.options.scale @@ -917,15 +925,14 @@ def trans_to_tz(self, node=None, isNode=False): d = self.round_value(trans.d) # globalscale do not impact transform - if not self.options.noreversey or isNode: + if not self.options.noreversey or is_node: tr.y *= -1 b *= -1 c *= -1 - if not self.options.noreversey and not isNode: + if not self.options.noreversey and not is_node: tr.x += -c * self.update_height(0) tr.y += (1 - d) * self.update_height(0) - pass tr.x *= self.options.scale tr.y *= self.options.scale @@ -1257,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 @@ -1278,8 +1286,9 @@ def _output_group(self, group): string += self._handle_group(node) continue try: - isNode = node.TAG in ["text", "flowRoot", "image"] - goptions = self.style_to_tz(node) + self.trans_to_tz(node, isNode) + 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) @@ -1290,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)}" @@ -1298,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}" @@ -1314,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={") From 814b774045b89b96cf99012eb6b5d90810e6217b Mon Sep 17 00:00:00 2001 From: ldevillez Date: Tue, 28 Nov 2023 10:25:36 +0100 Subject: [PATCH 5/5] FIX: tests with node scaling --- tests/testfiles/nodes_and_transform.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testfiles/nodes_and_transform.tex b/tests/testfiles/nodes_and_transform.tex index 62cc9e9..39e4978 100644 --- a/tests/testfiles/nodes_and_transform.tex +++ b/tests/testfiles/nodes_and_transform.tex @@ -8,7 +8,7 @@ \def \globalscale {1.000000} -\begin{tikzpicture}[y=1cm, x=1cm, yscale=\globalscale,xscale=\globalscale, inner sep=0pt, outer sep=0pt] +\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]