mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Revolve multiple faces, improved Scale issue #15
This commit is contained in:
parent
a375a37cc6
commit
6e5b6fc215
4 changed files with 60 additions and 41 deletions
|
|
@ -80,7 +80,7 @@ with BuildSketch() as build:
|
||||||
Add(build_text.sketch)
|
Add(build_text.sketch)
|
||||||
|
|
||||||
logo = cq.Assembly(None, name="logo")
|
logo = cq.Assembly(None, name="logo")
|
||||||
logo.add(one.line_as_wire, name="one")
|
logo.add(one.wires()[0], name="one")
|
||||||
logo.add(two.sketch, name="two")
|
logo.add(two.sketch, name="two")
|
||||||
logo.add(three_d.part, name="three_d")
|
logo.add(three_d.part, name="three_d")
|
||||||
for line in extension_lines.line:
|
for line in extension_lines.line:
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ license:
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
"""
|
"""
|
||||||
from build123d import *
|
from build123d import *
|
||||||
from cadquery import Plane
|
|
||||||
|
|
||||||
segment_count = 6
|
segment_count = 6
|
||||||
|
|
||||||
|
|
@ -40,7 +39,7 @@ with BuildPart() as handle:
|
||||||
tangent_scalars=(1.5, 1.5),
|
tangent_scalars=(1.5, 1.5),
|
||||||
)
|
)
|
||||||
# Record the center line for display and workplane creation
|
# Record the center line for display and workplane creation
|
||||||
handle_path = handle_center_line.line_as_wire
|
handle_path = handle_center_line.wires()[0]
|
||||||
|
|
||||||
# Create the cross sections - added to pending_faces
|
# Create the cross sections - added to pending_faces
|
||||||
for i in range(segment_count + 1):
|
for i in range(segment_count + 1):
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ class Scale(Compound):
|
||||||
self,
|
self,
|
||||||
*objects: Shape,
|
*objects: Shape,
|
||||||
by: Union[float, tuple[float, float, float]],
|
by: Union[float, tuple[float, float, float]],
|
||||||
mode: Mode = Mode.ADD,
|
mode: Mode = Mode.REPLACE,
|
||||||
):
|
):
|
||||||
context: Builder = Builder._get_context()
|
context: Builder = Builder._get_context()
|
||||||
|
|
||||||
|
|
@ -486,7 +486,14 @@ class Scale(Compound):
|
||||||
[0.0, 0.0, 00.0, 1.0],
|
[0.0, 0.0, 00.0, 1.0],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
new_objects = [o.transformGeometry(scale_matrix) for o in objects]
|
new_objects = []
|
||||||
|
for obj in objects:
|
||||||
|
current_location = obj.location()
|
||||||
|
obj_at_origin = obj.located(Location(Vector()))
|
||||||
|
new_objects.append(
|
||||||
|
obj_at_origin.transformGeometry(scale_matrix).locate(current_location)
|
||||||
|
)
|
||||||
|
|
||||||
context._add_to_context(*new_objects, mode=mode)
|
context._add_to_context(*new_objects, mode=mode)
|
||||||
|
|
||||||
super().__init__(Compound.makeCompound(new_objects).wrapped)
|
super().__init__(Compound.makeCompound(new_objects).wrapped)
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ class CounterBoreHole(Compound):
|
||||||
new_solids = []
|
new_solids = []
|
||||||
for location in LocationList._get_context().locations:
|
for location in LocationList._get_context().locations:
|
||||||
hole_depth = (
|
hole_depth = (
|
||||||
context.part.fuse(Solid.makeBox(1, 1, 1).move(location))
|
context.part.fuse(Solid.makeBox(1, 1, 1).locate(location))
|
||||||
.BoundingBox()
|
.BoundingBox()
|
||||||
.DiagonalLength
|
.DiagonalLength
|
||||||
if not depth
|
if not depth
|
||||||
|
|
@ -338,7 +338,7 @@ class CounterBoreHole(Compound):
|
||||||
(0, 0, 1),
|
(0, 0, 1),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.move(location)
|
.locate(location)
|
||||||
)
|
)
|
||||||
context._add_to_context(*new_solids, mode=mode)
|
context._add_to_context(*new_solids, mode=mode)
|
||||||
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
@ -371,7 +371,7 @@ class CounterSinkHole(Compound):
|
||||||
|
|
||||||
for location in LocationList._get_context().locations:
|
for location in LocationList._get_context().locations:
|
||||||
hole_depth = (
|
hole_depth = (
|
||||||
context.part.fuse(Solid.makeBox(1, 1, 1).move(location))
|
context.part.fuse(Solid.makeBox(1, 1, 1).locate(location))
|
||||||
.BoundingBox()
|
.BoundingBox()
|
||||||
.DiagonalLength
|
.DiagonalLength
|
||||||
if not depth
|
if not depth
|
||||||
|
|
@ -394,7 +394,7 @@ class CounterSinkHole(Compound):
|
||||||
counter_sink_radius, hole_depth, (0, 0, 0), (0, 0, 1)
|
counter_sink_radius, hole_depth, (0, 0, 0), (0, 0, 1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.move(location)
|
.locate(location)
|
||||||
]
|
]
|
||||||
context._add_to_context(*new_solids, mode=mode)
|
context._add_to_context(*new_solids, mode=mode)
|
||||||
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
@ -563,7 +563,7 @@ class Hole(Compound):
|
||||||
for location in LocationList._get_context().locations:
|
for location in LocationList._get_context().locations:
|
||||||
hole_depth = (
|
hole_depth = (
|
||||||
2
|
2
|
||||||
* context.part.fuse(Solid.makeBox(1, 1, 1).move(location))
|
* context.part.fuse(Solid.makeBox(1, 1, 1).locate(location))
|
||||||
.BoundingBox()
|
.BoundingBox()
|
||||||
.DiagonalLength
|
.DiagonalLength
|
||||||
if not depth
|
if not depth
|
||||||
|
|
@ -573,7 +573,7 @@ class Hole(Compound):
|
||||||
new_solids.append(
|
new_solids.append(
|
||||||
Solid.makeCylinder(
|
Solid.makeCylinder(
|
||||||
radius, hole_depth, hole_start, (0, 0, -1), 360
|
radius, hole_depth, hole_start, (0, 0, -1), 360
|
||||||
).move(location)
|
).locate(location)
|
||||||
)
|
)
|
||||||
context._add_to_context(*new_solids, mode=mode)
|
context._add_to_context(*new_solids, mode=mode)
|
||||||
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
@ -599,6 +599,7 @@ class Loft(Solid):
|
||||||
|
|
||||||
if not sections:
|
if not sections:
|
||||||
loft_wires = [face.outerWire() for face in context.pending_faces]
|
loft_wires = [face.outerWire() for face in context.pending_faces]
|
||||||
|
context.pending_faces = []
|
||||||
else:
|
else:
|
||||||
loft_wires = [section.outerWire() for section in sections]
|
loft_wires = [section.outerWire() for section in sections]
|
||||||
new_solid = Solid.makeLoft(loft_wires, ruled)
|
new_solid = Solid.makeLoft(loft_wires, ruled)
|
||||||
|
|
@ -606,12 +607,11 @@ class Loft(Solid):
|
||||||
# Try to recover an invalid loft
|
# Try to recover an invalid loft
|
||||||
if not new_solid.isValid():
|
if not new_solid.isValid():
|
||||||
new_solid = Solid.makeSolid(
|
new_solid = Solid.makeSolid(
|
||||||
CqShell.makeShell(new_solid.Faces() + list(sections))
|
Shell.makeShell(new_solid.Faces() + list(sections))
|
||||||
).clean()
|
).clean()
|
||||||
if not new_solid.isValid():
|
if not new_solid.isValid():
|
||||||
raise RuntimeError("Failed to create valid loft")
|
raise RuntimeError("Failed to create valid loft")
|
||||||
|
|
||||||
context.pending_faces = []
|
|
||||||
context._add_to_context(new_solid, mode=mode)
|
context._add_to_context(new_solid, mode=mode)
|
||||||
super().__init__(new_solid.wrapped)
|
super().__init__(new_solid.wrapped)
|
||||||
|
|
||||||
|
|
@ -622,10 +622,10 @@ class Revolve(Compound):
|
||||||
Revolve the profile or pending sketches/face about the given axis.
|
Revolve the profile or pending sketches/face about the given axis.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
profile (Face, optional): 2D profile to revolve. Defaults to None.
|
profiles (Face, optional): sequence of 2D profile to revolve.
|
||||||
revolution_arc (float, optional): angular size of revolution. Defaults to 360.0.
|
|
||||||
axis_origin (VectorLike, optional): axis start in local coordinates. Defaults to (0, 0, 0).
|
axis_origin (VectorLike, optional): axis start in local coordinates. Defaults to (0, 0, 0).
|
||||||
axis_direction (VectorLike, optional): axis direction. Defaults to (0, 1, 0).
|
axis_direction (VectorLike, optional): axis direction. Defaults to (0, 1, 0).
|
||||||
|
revolution_arc (float, optional): angular size of revolution. Defaults to 360.0.
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
|
|
@ -634,50 +634,63 @@ class Revolve(Compound):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
*profiles: Face,
|
||||||
axis_origin: VectorLike,
|
axis_origin: VectorLike,
|
||||||
axis_direction: VectorLike,
|
axis_direction: VectorLike,
|
||||||
profile: Face = None,
|
|
||||||
revolution_arc: float = 360.0,
|
revolution_arc: float = 360.0,
|
||||||
mode: Mode = Mode.ADD,
|
mode: Mode = Mode.ADD,
|
||||||
):
|
):
|
||||||
context: BuildPart = BuildPart._get_context()
|
context: BuildPart = BuildPart._get_context()
|
||||||
|
|
||||||
validate_inputs(self, context)
|
validate_inputs(self, context, profiles)
|
||||||
|
|
||||||
# Make sure we account for users specifying angles larger than 360 degrees, and
|
# Make sure we account for users specifying angles larger than 360 degrees, and
|
||||||
# for OCCT not assuming that a 0 degree revolve means a 360 degree revolve
|
# for OCCT not assuming that a 0 degree revolve means a 360 degree revolve
|
||||||
angle = revolution_arc % 360.0
|
angle = revolution_arc % 360.0
|
||||||
angle = 360.0 if angle == 0 else angle
|
angle = 360.0 if angle == 0 else angle
|
||||||
|
|
||||||
if not profile:
|
if not profiles:
|
||||||
profile = context.pending_faces.pop()
|
profiles = context.pending_faces
|
||||||
|
context.pending_faces = []
|
||||||
|
|
||||||
axis_origin = Vector(axis_origin)
|
axis_origin = Vector(axis_origin)
|
||||||
axis_direction = Vector(axis_direction)
|
axis_direction = Vector(axis_direction)
|
||||||
|
|
||||||
# axis_origin must be on the same plane as profile
|
self.profiles = profiles
|
||||||
face_occt_pln = gp_Pln(
|
self.axis_origin = axis_origin
|
||||||
profile.Center().toPnt(), profile.normalAt(profile.Center()).toDir()
|
self.axis_direction = axis_direction
|
||||||
)
|
self.revolution_arc = revolution_arc
|
||||||
if not face_occt_pln.Contains(axis_origin.toPnt(), 1e-5):
|
self.mode = mode
|
||||||
raise ValueError(
|
|
||||||
"axis_origin must be on the same plane as the face to revolve"
|
|
||||||
)
|
|
||||||
if not face_occt_pln.Contains(
|
|
||||||
gp_Lin(axis_origin.toPnt(), axis_direction.toDir()), 1e-5, 1e-5
|
|
||||||
):
|
|
||||||
raise ValueError("axis must be in the same plane as the face to revolve")
|
|
||||||
|
|
||||||
new_solid = Solid.revolve(
|
new_solids = []
|
||||||
profile,
|
for profile in profiles:
|
||||||
angle,
|
# axis_origin must be on the same plane as profile
|
||||||
axis_origin,
|
face_occt_pln = gp_Pln(
|
||||||
axis_origin + axis_direction,
|
profile.Center().toPnt(), profile.normalAt(profile.Center()).toDir()
|
||||||
)
|
)
|
||||||
new_solids = [
|
if not face_occt_pln.Contains(axis_origin.toPnt(), 1e-5):
|
||||||
new_solid.moved(location)
|
raise ValueError(
|
||||||
for location in LocationList._get_context().locations
|
"axis_origin must be on the same plane as the face to revolve"
|
||||||
]
|
)
|
||||||
|
if not face_occt_pln.Contains(
|
||||||
|
gp_Lin(axis_origin.toPnt(), axis_direction.toDir()), 1e-5, 1e-5
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
"axis must be in the same plane as the face to revolve"
|
||||||
|
)
|
||||||
|
|
||||||
|
new_solid = Solid.revolve(
|
||||||
|
profile,
|
||||||
|
angle,
|
||||||
|
axis_origin,
|
||||||
|
axis_origin + axis_direction,
|
||||||
|
)
|
||||||
|
new_solids.extend(
|
||||||
|
[
|
||||||
|
new_solid.moved(location)
|
||||||
|
for location in LocationList._get_context().locations
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
context._add_to_context(*new_solids, mode=mode)
|
context._add_to_context(*new_solids, mode=mode)
|
||||||
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue