mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
add align parameter to import_svg
This commit is contained in:
parent
40cf1437ed
commit
8e4aa3370d
3 changed files with 51 additions and 6 deletions
|
|
@ -43,7 +43,7 @@ dependencies = [
|
||||||
"ezdxf >= 1.1.0, < 2",
|
"ezdxf >= 1.1.0, < 2",
|
||||||
"ipython >= 8.0.0, < 9",
|
"ipython >= 8.0.0, < 9",
|
||||||
"py-lib3mf >= 2.3.1",
|
"py-lib3mf >= 2.3.1",
|
||||||
"ocpsvg >= 0.4, < 0.5",
|
"ocpsvg >= 0.5, < 0.6",
|
||||||
"trianglesolver",
|
"trianglesolver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ from OCP.XCAFDoc import (
|
||||||
from ocpsvg import ColorAndLabel, import_svg_document
|
from ocpsvg import ColorAndLabel, import_svg_document
|
||||||
from svgpathtools import svg2paths
|
from svgpathtools import svg2paths
|
||||||
|
|
||||||
from build123d.geometry import Color, Location
|
from build123d.build_enums import Align
|
||||||
|
from build123d.geometry import Color, Location, Vector, to_align_offset
|
||||||
from build123d.topology import (
|
from build123d.topology import (
|
||||||
Compound,
|
Compound,
|
||||||
Edge,
|
Edge,
|
||||||
|
|
@ -337,6 +338,7 @@ def import_svg(
|
||||||
svg_file: str | Path | TextIO,
|
svg_file: str | Path | TextIO,
|
||||||
*,
|
*,
|
||||||
flip_y: bool = True,
|
flip_y: bool = True,
|
||||||
|
align: Align | tuple[Align, Align] | None = Align.MIN,
|
||||||
ignore_visibility: bool = False,
|
ignore_visibility: bool = False,
|
||||||
label_by: Literal["id", "class", "inkscape:label"] | str = "id",
|
label_by: Literal["id", "class", "inkscape:label"] | str = "id",
|
||||||
is_inkscape_label: bool | None = None, # TODO remove for `1.0` release
|
is_inkscape_label: bool | None = None, # TODO remove for `1.0` release
|
||||||
|
|
@ -346,6 +348,8 @@ def import_svg(
|
||||||
Args:
|
Args:
|
||||||
svg_file (Union[str, Path, TextIO]): svg file
|
svg_file (Union[str, Path, TextIO]): svg file
|
||||||
flip_y (bool, optional): flip objects to compensate for svg orientation. Defaults to True.
|
flip_y (bool, optional): flip objects to compensate for svg orientation. Defaults to True.
|
||||||
|
align (Align | tuple[Align, Align] | None, optional): alignment of the SVG's viewbox,
|
||||||
|
if None, the viewbox's origin will be at `(0,0,0)`. Defaults to Align.MIN.
|
||||||
ignore_visibility (bool, optional): Defaults to False.
|
ignore_visibility (bool, optional): Defaults to False.
|
||||||
label_by (str, optional): XML attribute to use for imported shapes' `label` property.
|
label_by (str, optional): XML attribute to use for imported shapes' `label` property.
|
||||||
Defaults to "id".
|
Defaults to "id".
|
||||||
|
|
@ -368,12 +372,18 @@ def import_svg(
|
||||||
label_by = re.sub(
|
label_by = re.sub(
|
||||||
r"^inkscape:(.+)", r"{http://www.inkscape.org/namespaces/inkscape}\1", label_by
|
r"^inkscape:(.+)", r"{http://www.inkscape.org/namespaces/inkscape}\1", label_by
|
||||||
)
|
)
|
||||||
for face_or_wire, color_and_label in import_svg_document(
|
imported = import_svg_document(
|
||||||
svg_file,
|
svg_file,
|
||||||
flip_y=flip_y,
|
flip_y=flip_y,
|
||||||
ignore_visibility=ignore_visibility,
|
ignore_visibility=ignore_visibility,
|
||||||
metadata=ColorAndLabel.Label_by(label_by),
|
metadata=ColorAndLabel.Label_by(label_by),
|
||||||
):
|
)
|
||||||
|
|
||||||
|
doc_xy = Vector(imported.viewbox.x, imported.viewbox.y)
|
||||||
|
doc_wh = Vector(imported.viewbox.width, imported.viewbox.height)
|
||||||
|
offset = to_align_offset(doc_xy, doc_xy + doc_wh, align)
|
||||||
|
|
||||||
|
for face_or_wire, color_and_label in imported:
|
||||||
if isinstance(face_or_wire, TopoDS_Wire):
|
if isinstance(face_or_wire, TopoDS_Wire):
|
||||||
shape = Wire(face_or_wire)
|
shape = Wire(face_or_wire)
|
||||||
elif isinstance(face_or_wire, TopoDS_Face):
|
elif isinstance(face_or_wire, TopoDS_Face):
|
||||||
|
|
@ -381,6 +391,9 @@ def import_svg(
|
||||||
else: # should not happen
|
else: # should not happen
|
||||||
raise ValueError(f"unexpected shape type: {type(face_or_wire).__name__}")
|
raise ValueError(f"unexpected shape type: {type(face_or_wire).__name__}")
|
||||||
|
|
||||||
|
if offset.X != 0 or offset.Y != 0: # avoid copying if we don't need to
|
||||||
|
shape = shape.translate(offset)
|
||||||
|
|
||||||
if shape.wrapped:
|
if shape.wrapped:
|
||||||
shape.color = Color(*color_and_label.color_for(shape.wrapped))
|
shape.color = Color(*color_and_label.color_for(shape.wrapped))
|
||||||
shape.label = color_and_label.label
|
shape.label = color_and_label.label
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ from build123d.importers import (
|
||||||
import_step,
|
import_step,
|
||||||
import_stl,
|
import_stl,
|
||||||
)
|
)
|
||||||
from build123d.geometry import Pos
|
from build123d.geometry import Pos, Vector
|
||||||
from build123d.exporters import ExportSVG
|
from build123d.exporters import ExportSVG
|
||||||
from build123d.exporters3d import export_brep, export_step
|
from build123d.exporters3d import export_brep, export_step
|
||||||
from build123d.build_enums import GeomType
|
from build123d.build_enums import Align, GeomType
|
||||||
|
|
||||||
|
|
||||||
class ImportSVG(unittest.TestCase):
|
class ImportSVG(unittest.TestCase):
|
||||||
|
|
@ -116,6 +116,38 @@ class ImportSVG(unittest.TestCase):
|
||||||
self.assertEqual(str(svg[1].color), str(Color(1, 0, 0, 1)))
|
self.assertEqual(str(svg[1].color), str(Color(1, 0, 0, 1)))
|
||||||
self.assertEqual(str(svg[2].color), str(Color(0, 0, 0, 1)))
|
self.assertEqual(str(svg[2].color), str(Color(0, 0, 0, 1)))
|
||||||
|
|
||||||
|
def test_import_svg_origin(self):
|
||||||
|
svg_src = (
|
||||||
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 1 6 8" width="6" height="8">'
|
||||||
|
'<circle r="1" cx="2" cy="3"/>'
|
||||||
|
"</svg>"
|
||||||
|
)
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=None, flip_y=False)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().center(), Vector(2.0, +3.0))
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=None, flip_y=True)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().center(), Vector(2.0, -3.0))
|
||||||
|
|
||||||
|
def test_import_svg_align(self):
|
||||||
|
svg_src = (
|
||||||
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 1 6 8" width="6" height="8">'
|
||||||
|
'<rect x="1" y="1" width="6" height="8"/>'
|
||||||
|
"</svg>"
|
||||||
|
)
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=Align.MIN, flip_y=False)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().min, Vector(0.0, 0.0))
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=Align.MIN, flip_y=True)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().min, Vector(0, 0))
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=Align.MAX, flip_y=False)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().max, Vector(0.0, 0.0))
|
||||||
|
|
||||||
|
svg = import_svg(StringIO(svg_src), align=Align.MAX, flip_y=True)
|
||||||
|
self.assertAlmostEqual(svg[0].bounding_box().max, Vector(0, 0))
|
||||||
|
|
||||||
|
|
||||||
class ImportBREP(unittest.TestCase):
|
class ImportBREP(unittest.TestCase):
|
||||||
def test_bad_filename(self):
|
def test_bad_filename(self):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue