meerk40t / svgelements

SVG Parsing for Elements, Paths, and other SVG Objects.
MIT License
124 stars 28 forks source link

Feature: measure `Path` areas #254

Open blairfrandeen opened 2 weeks ago

blairfrandeen commented 2 weeks ago

I propose that Path objects should have an area() function that computes the area enclosed by the path. This would be similar to the area() function in svgpathtools, but would work with paths that are not continuous. The application that I need this for is paths with a "hole" in them (like a donut). svgpathtools is not capable of computing areas for these paths, as it does not implement subpaths. See https://github.com/mathandy/svgpathtools/issues/89 for some context.

I successfully implemented this function in my own project, essentially using svgelements.Path and copying the logic from svgpathtools.area(). I validated my solution against a third measurement method (Inkscape's built-in measure path extension), and I have several distinct test cases.

I'm happy to work on a PR towards this goal, but I wanted to verify that this is of interest / in scope before making the effort. Thanks for maintaining this very useful library!

derVedro commented 4 days ago

@blairfrandeen not the right place for me to discuss about svgpathtools and that is a XY-problem nobody wants to hear about, but I solved that kind of issue some time ago like that:

import copy
from svgpathtools import Line, Path

def compute_area(path : Path):

    def closed_path(path: Path) -> Path:
        if path.isclosed():
            path = copy.copy(path)
            path.append(Line(start=path.end, end=path.start))
        return path

    return sum(map(lambda p : closed_path(p).area(), path.continuous_subpaths()))

Somehow continuous_subpaths() returns all subpaths regardless of whether they are closed or not closed. May be I just don't understand what continuous means in this context.

I tested that way of computing area of paths consisting of Lines and CubicBezier. It's working fine.