Repository: abey79/vpype

Issue:
`read` should discard invisible geometries



Discussion:
@tatarize do you happen to have a good heuristic to determine if a given SVG element should be visible or not? I see there is at least the `visibility` and `display` attributes. Anything else? Is that something you already have somewhere?
The only thing regularly seen is visibility='hidden'. Which is element.values['visibility'] == 'hidden', likely in a try block. Oddly enough I don't correctly deal with the display attribute in svgelements, in theory if it says display="none", it shouldn't block the return the actual parsing. Since it actually means that it prevents rendering. In theory there's also rectangles that if they have 0 width they don't actually become paths, but really blank paths.
OK so I need to implement `visibility` and wait for meerk40t/svgelements#70
You could also check for display, but I've generally not seen it come up. I was just double-checking here and realized that it's actually the case that that means do not render on my part. But, yeah, you would check visibility on your end since that's a real rendered item but is hidden. Whereas display is not rendered at all, even invisibly. 
Apparently for not-going-to-happen completeness `if element.values['visibility'] in ('hidden', 'collapse'):` According to the spec the CSS for tables to collapse something if applied to an SVG should have the same effect as hidden.
The meerk40t/svgelements#70 should be finished. Added solid test coverage for it too. Also properly corrected the width/height thing the zerodivideerror was the failure of the viewbox. WIth a viewbox zero we get infinite length with the width/height zero we everything scales into a singularity in the origin, but notably wouldn't throw an error since multipling everything by zero is fine. Added test coverage for everything and published 1.3.4 on pypi as well as the project page.
Awesome, thanks!

Resolving patch:
diff --git a/vpype/io.py b/vpype/io.py
--- a/vpype/io.py
+++ b/vpype/io.py
@@ -174,6 +174,9 @@ def _extract_paths(group: svgelements.Group, recursive) -> _PathListType:
         everything = group
     paths = []
     for elem in everything:
+        if elem.values.get("visibility", "") in ("hidden", "collapse"):
+            continue
+
         if isinstance(elem, svgelements.Path):
             if len(elem) != 0:
                 paths.append(elem)


Test patch:
diff --git a/tests/test_files.py b/tests/test_files.py
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -58,3 +58,47 @@ def test_write_is_idempotent(runner, path, tmp_path):
         for line in difflib.unified_diff(txt1.split("\n"), txt2.split("\n"), lineterm=""):
             print(line)
         assert False
+
+
+@pytest.mark.parametrize(
+    ("svg_content", "line_count"),
+    [
+        ('<circle cx="500" cy="500" r="40"/>', 1),
+        ('<circle cx="500" cy="500" r="40" style="visibility:collapse"/>', 0),
+        ('<circle cx="500" cy="500" r="40" style="visibility:hidden"/>', 0),
+        ('<circle cx="500" cy="500" r="40" style="display:none"/>', 0),
+        ('<g style="visibility: hidden"><circle cx="500" cy="500" r="40"/></g>', 0),
+        ('<g style="visibility: collapse"><circle cx="500" cy="500" r="40"/></g>', 0),
+        (
+            """<g style="visibility: collapse">
+            <circle cx="500" cy="500" r="40" style="visibility:visible" />
+            </g>""",
+            1,
+        ),
+        (
+            """<g style="visibility: hidden">
+            <circle cx="500" cy="500" r="40" style="visibility:visible" />
+            </g>""",
+            1,
+        ),
+        (
+            """<g style="display: none">
+            <circle cx="500" cy="500" r="40" style="visibility:visible" />
+            </g>""",
+            0,
+        ),
+    ],
+)
+def test_read_svg_visibility(svg_content, line_count, tmp_path):
+    svg = f"""<?xml version="1.0"?>
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"
+    width="1000" height="1000">
+        {svg_content}
+</svg>
+"""
+    path = str(tmp_path / "file.svg")
+    with open(path, "w") as fp:
+        fp.write(svg)
+
+    lc, _, _ = vp.read_svg(path, 1.0)
+    assert len(lc) == line_count