build123d icon indicating copy to clipboard operation
build123d copied to clipboard

Extrude faces from SVG sometimes changes direction when applying taper

Open qwelyt opened this issue 1 year ago • 2 comments

import build123d as bd

svg = bd.import_svg("bd_test.svg")
# taper = 0
taper = 10

with bd.BuildPart() as prt:
    with bd.BuildSketch():
        for k in svg:
            with bd.BuildLine():
                bd.add(k)
            bd.make_face()
    bd.extrude(amount=10, taper=taper, dir=bd.Axis.Z.direction)

show(prt)

Depending on what shapes are in the imported SVG, some objects change direction when applying a taper.

This is without taper. Things extrude as expected. 20240218_005027

When applying a taper primitives like rect and cylinder change direction of the extrusion while path behaves like they should. 20240218_005046 bd_test

qwelyt avatar Feb 17 '24 23:02 qwelyt

Thanks for isolating the problem. After removing all of the Python code that I can, here is what happens:

from build123d import *
from ocp_vscode import show
from OCP.LocOpe import LocOpe_DPrism
from math import radians, cos

svg = import_svg("issue-553.svg")
face_to_extrude = -Face(svg[2])
taper = 10

prism_builder = LocOpe_DPrism(
    face_to_extrude.wrapped,
    10 / cos(radians(taper)),
    radians(taper),
)
new_solid = Solid(prism_builder.Shape())

show(face_to_extrude, new_solid)

image the extrude is in the wrong direction and this direction is independent of the face normal (same result with face_to_extrude = Face(svg[2]).

Need to figure out why LocOpe_DPrism is flipping the direction or avoid using this class at all.

gumyr avatar Feb 18 '24 15:02 gumyr

There are a couple solutions to this. One is this:

svg = import_svg("issue-553.svg")
profile = Face(svg[2])
taper = 10

taper_law = Law_Linear()
taper_law.Set(0.0, 1.0, 1.0, 1 - sin(radians(taper)))
outer = profile.outer_wire().wrapped

direction = Vector(0, 0, 10)
spine_p1 = profile.center()
spine_p2 = spine_p1 + Vector(direction)
pipe_shell_spine = Wire(Edge.make_line(spine_p1, spine_p2)).wrapped

extrude_builder = BRepOffsetAPI_MakePipeShell(pipe_shell_spine)
extrude_builder.Add(outer)
extrude_builder.SetLaw(outer, taper_law)
extrude_builder.Build()
extrude_builder.MakeSolid()
taper_solid = extrude_builder.Shape()

show(pipe_shell_spine, taper_solid)

where LocOpe_DPrism is replaced with BRepOffsetAPI_MakePipeShell with a "law" that implements a linear taper.

Alternatively, if I do this:

        if (
            False
            and direction.normalized() == profile.normal_at()
            and Plane(profile).z_dir.Z > 0
            and taper > 0
            and not profile.inner_wires()
        ):

i.e. just disable the use of LocOpe_DPrism in extrude_taper the objects will be created by lofting.

There is an open PR on an improvement to lofting that would allow for holes (but the PR isn't complete), so I'll have to think about which way to go here.

gumyr avatar Feb 18 '24 19:02 gumyr