Revolve multiple faces, improved Scale issue #15

This commit is contained in:
Roger Maitland 2022-09-26 14:39:05 -04:00
parent a375a37cc6
commit 6e5b6fc215
4 changed files with 60 additions and 41 deletions

View file

@ -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:

View file

@ -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):

View file

@ -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)

View file

@ -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)