mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Add->add, restored context logging and validation
This commit is contained in:
parent
cb05ee97b6
commit
92979fc29c
21 changed files with 210 additions and 239 deletions
|
|
@ -60,7 +60,7 @@ if "show" in locals():
|
||||||
|
|
||||||
b = Box(1, 2, 3)
|
b = Box(1, 2, 3)
|
||||||
with BuildPart() as bp:
|
with BuildPart() as bp:
|
||||||
Add(b)
|
add(b)
|
||||||
|
|
||||||
if "show" in locals():
|
if "show" in locals():
|
||||||
show(bp)
|
show(bp)
|
||||||
|
|
@ -70,7 +70,7 @@ if "show" in locals():
|
||||||
b = Box(1, 2, 3) + Cylinder(0.75, 2.5)
|
b = Box(1, 2, 3) + Cylinder(0.75, 2.5)
|
||||||
|
|
||||||
with BuildPart() as bp:
|
with BuildPart() as bp:
|
||||||
Add(b)
|
add(b)
|
||||||
Cylinder(0.4, 6, mode=Mode.SUBTRACT)
|
Cylinder(0.4, 6, mode=Mode.SUBTRACT)
|
||||||
|
|
||||||
c = bp.part - Plane.YZ * Cylinder(0.2, 6)
|
c = bp.part - Plane.YZ * Cylinder(0.2, 6)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ if "show" in locals():
|
||||||
b = Rectangle(1, 2) + Circle(0.75)
|
b = Rectangle(1, 2) + Circle(0.75)
|
||||||
|
|
||||||
with BuildSketch() as sk:
|
with BuildSketch() as sk:
|
||||||
Add(b)
|
add(b)
|
||||||
Circle(0.1, mode=Mode.SUBTRACT)
|
Circle(0.1, mode=Mode.SUBTRACT)
|
||||||
|
|
||||||
c = sk.sketch - Pos(0, 0.5) * Circle(0.2)
|
c = sk.sketch - Pos(0, 0.5) * Circle(0.2)
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,9 @@ with BuildLine() as extension_lines:
|
||||||
(logo_width, -ext_line_length - font_height * 0.1),
|
(logo_width, -ext_line_length - font_height * 0.1),
|
||||||
)
|
)
|
||||||
with Locations(l1 @ 0.5):
|
with Locations(l1 @ 0.5):
|
||||||
Add(*arrow_left.line)
|
add(*arrow_left.line)
|
||||||
with Locations(l2 @ 0.5):
|
with Locations(l2 @ 0.5):
|
||||||
Add(*arrow_left.line, rotation=180.0)
|
add(*arrow_left.line, rotation=180.0)
|
||||||
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
|
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
|
||||||
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
|
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
|
||||||
|
|
||||||
|
|
@ -87,12 +87,12 @@ with BuildSketch() as build:
|
||||||
(l1 @ 0.5 + l2 @ 0.5) / 2
|
(l1 @ 0.5 + l2 @ 0.5) / 2
|
||||||
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
|
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
|
||||||
):
|
):
|
||||||
Add(build_text.sketch)
|
add(build_text.sketch)
|
||||||
# add the customizable text to the build text sketch
|
# add the customizable text to the build text sketch
|
||||||
with Locations(
|
with Locations(
|
||||||
(l1 @ 1 + l2 @ 1) / 2 - Vector((cust_vertices[-1].X + cust_vertices[0].X), 1.4)
|
(l1 @ 1 + l2 @ 1) / 2 - Vector((cust_vertices[-1].X + cust_vertices[0].X), 1.4)
|
||||||
):
|
):
|
||||||
Add(cust_text.sketch)
|
add(cust_text.sketch)
|
||||||
|
|
||||||
cmpd = Compound.make_compound(
|
cmpd = Compound.make_compound(
|
||||||
[three_d.part, two.sketch, one.line, build.sketch, extension_lines.line]
|
[three_d.part, two.sketch, one.line, build.sketch, extension_lines.line]
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,9 @@ with BuildLine() as extension_lines:
|
||||||
(logo_width, -ext_line_length - font_height * 0.1),
|
(logo_width, -ext_line_length - font_height * 0.1),
|
||||||
)
|
)
|
||||||
with Locations(l1 @ 0.5):
|
with Locations(l1 @ 0.5):
|
||||||
Add(*arrow_left.line)
|
add(*arrow_left.line)
|
||||||
with Locations(l2 @ 0.5):
|
with Locations(l2 @ 0.5):
|
||||||
Add(*arrow_left.line, rotation=180.0)
|
add(*arrow_left.line, rotation=180.0)
|
||||||
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
|
Line(l1 @ 0.5, l1 @ 0.5 + Vector(dim_line_length, 0))
|
||||||
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
|
Line(l2 @ 0.5, l2 @ 0.5 - Vector(dim_line_length, 0))
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ with BuildSketch() as build:
|
||||||
(l1 @ 0.5 + l2 @ 0.5) / 2
|
(l1 @ 0.5 + l2 @ 0.5) / 2
|
||||||
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
|
- Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
|
||||||
):
|
):
|
||||||
Add(build_text.sketch)
|
add(build_text.sketch)
|
||||||
|
|
||||||
# logo = Assembly(None, name="logo")
|
# logo = Assembly(None, name="logo")
|
||||||
# logo.add(one.wires()[0], name="one")
|
# logo.add(one.wires()[0], name="one")
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ with BuildSketch() as minute_indicator:
|
||||||
with BuildSketch() as clock_face:
|
with BuildSketch() as clock_face:
|
||||||
Circle(clock_radius)
|
Circle(clock_radius)
|
||||||
with PolarLocations(0, 60):
|
with PolarLocations(0, 60):
|
||||||
Add(minute_indicator.sketch, mode=Mode.SUBTRACT)
|
add(minute_indicator.sketch, mode=Mode.SUBTRACT)
|
||||||
with PolarLocations(clock_radius * 0.875, 12):
|
with PolarLocations(clock_radius * 0.875, 12):
|
||||||
SlotOverall(clock_radius * 0.05, clock_radius * 0.025, mode=Mode.SUBTRACT)
|
SlotOverall(clock_radius * 0.05, clock_radius * 0.025, mode=Mode.SUBTRACT)
|
||||||
for hour in range(1, 13):
|
for hour in range(1, 13):
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ with BuildPart() as box_builder:
|
||||||
box = box_builder.part
|
box = box_builder.part
|
||||||
|
|
||||||
with BuildPart() as lid_builder:
|
with BuildPart() as lid_builder:
|
||||||
Add(box_plan.sketch)
|
add(box_plan.sketch)
|
||||||
extrude(amount=pocket_t / 2 + bottom_t)
|
extrude(amount=pocket_t / 2 + bottom_t)
|
||||||
with BuildSketch() as pocket:
|
with BuildSketch() as pocket:
|
||||||
offset(box_plan.sketch, amount=-(wall_t - lip_t), mode=Mode.ADD)
|
offset(box_plan.sketch, amount=-(wall_t - lip_t), mode=Mode.ADD)
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ with BuildPart() as box_builder:
|
||||||
fillet(*plan.vertices(), radius=card_width / 15)
|
fillet(*plan.vertices(), radius=card_width / 15)
|
||||||
extrude(amount=wall / 2)
|
extrude(amount=wall / 2)
|
||||||
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as walls:
|
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as walls:
|
||||||
Add(plan.sketch)
|
add(plan.sketch)
|
||||||
offset(plan.sketch, amount=-wall, mode=Mode.SUBTRACT)
|
offset(plan.sketch, amount=-wall, mode=Mode.SUBTRACT)
|
||||||
extrude(amount=deck / 2)
|
extrude(amount=deck / 2)
|
||||||
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as inset_walls:
|
with BuildSketch(box_builder.faces().sort_by(Axis.Z)[-1]) as inset_walls:
|
||||||
|
|
@ -130,11 +130,11 @@ with BuildPart() as box_builder:
|
||||||
|
|
||||||
with BuildPart() as lid_builder:
|
with BuildPart() as lid_builder:
|
||||||
with BuildSketch() as outset_walls:
|
with BuildSketch() as outset_walls:
|
||||||
Add(plan.sketch)
|
add(plan.sketch)
|
||||||
offset(plan.sketch, amount=-(wall - gap) / 2, mode=Mode.SUBTRACT)
|
offset(plan.sketch, amount=-(wall - gap) / 2, mode=Mode.SUBTRACT)
|
||||||
extrude(amount=deck / 2)
|
extrude(amount=deck / 2)
|
||||||
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]) as top:
|
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]) as top:
|
||||||
Add(plan.sketch)
|
add(plan.sketch)
|
||||||
extrude(amount=wall / 2)
|
extrude(amount=wall / 2)
|
||||||
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]):
|
with BuildSketch(lid_builder.faces().sort_by(Axis.Z)[-1]):
|
||||||
holes = GridLocations(
|
holes = GridLocations(
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ from build123d.build_common import *
|
||||||
from build123d.build_line import *
|
from build123d.build_line import *
|
||||||
from build123d.build_sketch import *
|
from build123d.build_sketch import *
|
||||||
from build123d.build_part import *
|
from build123d.build_part import *
|
||||||
from build123d.build_generic import *
|
|
||||||
from build123d.geometry import *
|
from build123d.geometry import *
|
||||||
from build123d.topology import *
|
from build123d.topology import *
|
||||||
from build123d.build_enums import ApproxOption
|
from build123d.build_enums import *
|
||||||
from build123d.importers import *
|
from build123d.importers import *
|
||||||
from build123d.operations_generic import *
|
from build123d.operations_generic import *
|
||||||
from build123d.operations_part import *
|
from build123d.operations_part import *
|
||||||
|
|
@ -41,7 +40,6 @@ __all__ = [
|
||||||
"Unit",
|
"Unit",
|
||||||
"Until",
|
"Until",
|
||||||
# Builders,
|
# Builders,
|
||||||
"Add",
|
|
||||||
"HexLocations",
|
"HexLocations",
|
||||||
"PolarLocations",
|
"PolarLocations",
|
||||||
"Locations",
|
"Locations",
|
||||||
|
|
@ -129,6 +127,7 @@ __all__ = [
|
||||||
# Other functions
|
# Other functions
|
||||||
"polar",
|
"polar",
|
||||||
# Operations
|
# Operations
|
||||||
|
"add",
|
||||||
"bounding_box",
|
"bounding_box",
|
||||||
"chamfer",
|
"chamfer",
|
||||||
"extrude",
|
"extrude",
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,13 @@ from build123d.build_enums import Align, Mode, Select
|
||||||
from build123d.geometry import Axis, Location, Plane, Vector, VectorLike
|
from build123d.geometry import Axis, Location, Plane, Vector, VectorLike
|
||||||
from build123d.topology import (
|
from build123d.topology import (
|
||||||
Compound,
|
Compound,
|
||||||
|
Curve,
|
||||||
Edge,
|
Edge,
|
||||||
Face,
|
Face,
|
||||||
|
Part,
|
||||||
Shape,
|
Shape,
|
||||||
ShapeList,
|
ShapeList,
|
||||||
|
Sketch,
|
||||||
Solid,
|
Solid,
|
||||||
Vertex,
|
Vertex,
|
||||||
Wire,
|
Wire,
|
||||||
|
|
@ -75,6 +78,25 @@ FT = 12 * IN
|
||||||
THOU = IN / 1000
|
THOU = IN / 1000
|
||||||
|
|
||||||
|
|
||||||
|
operations_apply_to = {
|
||||||
|
"add": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"bounding_box": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"chamfer": ["BuildPart", "BuildSketch"],
|
||||||
|
"extrude": ["BuildPart"],
|
||||||
|
"fillet": ["BuildPart", "BuildSketch"],
|
||||||
|
"loft": ["BuildPart"],
|
||||||
|
"make_face": ["BuildSketch"],
|
||||||
|
"make_hull": ["BuildSketch"],
|
||||||
|
"mirror": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"offset": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"revolve": ["BuildPart"],
|
||||||
|
"scale": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"section": ["BuildPart"],
|
||||||
|
"split": ["BuildPart", "BuildSketch", "BuildLine"],
|
||||||
|
"sweep": ["BuildPart"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Builder(ABC):
|
class Builder(ABC):
|
||||||
"""Builder
|
"""Builder
|
||||||
|
|
||||||
|
|
@ -194,33 +216,19 @@ class Builder(ABC):
|
||||||
return NotImplementedError # pragma: no cover
|
return NotImplementedError # pragma: no cover
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_context(cls, caller=None) -> Self:
|
def _get_context(cls, caller: Union[Builder, str] = None, log: bool = True) -> Self:
|
||||||
"""Return the instance of the current builder"""
|
"""Return the instance of the current builder"""
|
||||||
result = cls._current.get(None)
|
result = cls._current.get(None)
|
||||||
|
context_name = "None" if result is None else type(result).__name__
|
||||||
|
|
||||||
current_builder = inspect.currentframe().f_back.f_locals.get("self", None)
|
if log:
|
||||||
|
if isinstance(caller, (Part, Sketch, Curve, Wire)):
|
||||||
if not isinstance(current_builder, Builder):
|
caller_name = caller.__class__.__name__
|
||||||
current_builder = None
|
elif isinstance(caller, str):
|
||||||
|
caller_name = caller
|
||||||
if not isinstance(caller, Builder):
|
else:
|
||||||
caller = None
|
caller_name = "None"
|
||||||
|
logger.info("%s context requested by %s", context_name, caller_name)
|
||||||
# print(f"{result=}, {current_builder=}, {caller=}")
|
|
||||||
if current_builder is None:
|
|
||||||
logger.info("Context requested by None")
|
|
||||||
else:
|
|
||||||
logger.info(
|
|
||||||
"Context requested by %s",
|
|
||||||
type(current_builder).__name__,
|
|
||||||
)
|
|
||||||
|
|
||||||
if caller is not None and result is None:
|
|
||||||
if hasattr(caller, "_applies_to"):
|
|
||||||
raise RuntimeError(
|
|
||||||
f"No valid context found, use one of {caller._applies_to}"
|
|
||||||
)
|
|
||||||
raise RuntimeError("No valid context found-common")
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -322,14 +330,23 @@ class Builder(ABC):
|
||||||
objects = [objects]
|
objects = [objects]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
validating_class is not None
|
isinstance(validating_class, (Part, Sketch, Curve, Wire))
|
||||||
and not self._tag() in validating_class._applies_to
|
and self._tag() not in validating_class._applies_to
|
||||||
):
|
):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"{self.__class__.__name__} doesn't have a "
|
f"{self.__class__.__name__} doesn't have a "
|
||||||
f"{validating_class.__class__.__name__} object or operation "
|
f"{validating_class.__class__.__name__} object or operation "
|
||||||
f"({validating_class.__class__.__name__} applies to {validating_class._applies_to})"
|
f"({validating_class.__class__.__name__} applies to {validating_class._applies_to})"
|
||||||
)
|
)
|
||||||
|
elif (
|
||||||
|
isinstance(validating_class, str)
|
||||||
|
and self.__class__.__name__ not in operations_apply_to[validating_class]
|
||||||
|
):
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{self.__class__.__name__} doesn't have a "
|
||||||
|
f"{validating_class} object or operation "
|
||||||
|
f"({validating_class} applies to {operations_apply_to[validating_class]})"
|
||||||
|
)
|
||||||
# Check for valid object inputs
|
# Check for valid object inputs
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj is None:
|
if obj is None:
|
||||||
|
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
"""
|
|
||||||
BuildGeneric
|
|
||||||
|
|
||||||
name: build_generic.py
|
|
||||||
by: Gumyr
|
|
||||||
date: July 12th 2022
|
|
||||||
|
|
||||||
desc:
|
|
||||||
This python module is a library of generic classes used by other
|
|
||||||
build123d builders.
|
|
||||||
|
|
||||||
license:
|
|
||||||
|
|
||||||
Copyright 2022 Gumyr
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from build123d.build_common import Builder, LocationList, WorkplaneList, validate_inputs
|
|
||||||
from build123d.build_enums import Mode
|
|
||||||
from build123d.build_line import BuildLine
|
|
||||||
from build123d.build_part import BuildPart
|
|
||||||
from build123d.build_sketch import BuildSketch
|
|
||||||
from build123d.geometry import Axis, Rotation, RotationLike
|
|
||||||
from build123d.topology import Compound, Edge, Face, Solid, Wire
|
|
||||||
|
|
||||||
logging.getLogger("build123d").addHandler(logging.NullHandler())
|
|
||||||
logger = logging.getLogger("build123d")
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Objects
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class Add(Compound):
|
|
||||||
"""Generic Object: Add Object to Part or Sketch
|
|
||||||
|
|
||||||
Add an object to the builder.
|
|
||||||
|
|
||||||
if BuildPart:
|
|
||||||
Edges and Wires are added to pending_edges. Compounds of Face are added to
|
|
||||||
pending_faces. Solids or Compounds of Solid are combined into the part.
|
|
||||||
elif BuildSketch:
|
|
||||||
Edges and Wires are added to pending_edges. Compounds of Face are added to sketch.
|
|
||||||
elif BuildLine:
|
|
||||||
Edges and Wires are added to line.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
|
|
||||||
rotation (Union[float, RotationLike], optional): rotation angle for sketch,
|
|
||||||
rotation about each axis for part. Defaults to None.
|
|
||||||
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_applies_to = [BuildPart._tag(), BuildSketch._tag(), BuildLine._tag()]
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
*objects: Union[Edge, Wire, Face, Solid, Compound],
|
|
||||||
rotation: Union[float, RotationLike] = None,
|
|
||||||
mode: Mode = Mode.ADD,
|
|
||||||
):
|
|
||||||
context: Builder = Builder._get_context(self)
|
|
||||||
if context is None:
|
|
||||||
raise RuntimeError("Add must have an active builder context")
|
|
||||||
validate_inputs(context, self, objects)
|
|
||||||
|
|
||||||
if isinstance(context, BuildPart):
|
|
||||||
if rotation is None:
|
|
||||||
rotation = Rotation(0, 0, 0)
|
|
||||||
elif isinstance(rotation, float):
|
|
||||||
raise ValueError("Float values of rotation are not valid for BuildPart")
|
|
||||||
elif isinstance(rotation, tuple):
|
|
||||||
rotation = Rotation(*rotation)
|
|
||||||
|
|
||||||
objects = [obj.moved(rotation) for obj in objects]
|
|
||||||
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
|
|
||||||
new_wires = [obj for obj in objects if isinstance(obj, Wire)]
|
|
||||||
new_faces = [obj for obj in objects if isinstance(obj, Face)]
|
|
||||||
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
|
|
||||||
for compound in filter(lambda o: isinstance(o, Compound), objects):
|
|
||||||
new_edges.extend(compound.get_type(Edge))
|
|
||||||
new_wires.extend(compound.get_type(Wire))
|
|
||||||
new_faces.extend(compound.get_type(Face))
|
|
||||||
new_solids.extend(compound.get_type(Solid))
|
|
||||||
for new_wire in new_wires:
|
|
||||||
new_edges.extend(new_wire.edges())
|
|
||||||
|
|
||||||
# Add the pending Edges in one group
|
|
||||||
if not LocationList._get_context():
|
|
||||||
raise RuntimeError("There is no active Locations context")
|
|
||||||
located_edges = [
|
|
||||||
edge.moved(location)
|
|
||||||
for edge in new_edges
|
|
||||||
for location in LocationList._get_context().locations
|
|
||||||
]
|
|
||||||
context._add_to_pending(*located_edges)
|
|
||||||
new_objects = located_edges
|
|
||||||
|
|
||||||
# Add to pending Faces batched by workplane
|
|
||||||
for workplane in WorkplaneList._get_context().workplanes:
|
|
||||||
faces_per_workplane = []
|
|
||||||
for location in LocationList._get_context().locations:
|
|
||||||
for face in new_faces:
|
|
||||||
faces_per_workplane.append(face.moved(location))
|
|
||||||
context._add_to_pending(*faces_per_workplane, face_plane=workplane)
|
|
||||||
new_objects.extend(faces_per_workplane)
|
|
||||||
|
|
||||||
# Add to context Solids
|
|
||||||
located_solids = [
|
|
||||||
solid.moved(location)
|
|
||||||
for solid in new_solids
|
|
||||||
for location in LocationList._get_context().locations
|
|
||||||
]
|
|
||||||
context._add_to_context(*located_solids, mode=mode)
|
|
||||||
new_objects.extend(located_solids)
|
|
||||||
|
|
||||||
elif isinstance(context, (BuildLine, BuildSketch)):
|
|
||||||
rotation_angle = rotation if isinstance(rotation, (int, float)) else 0.0
|
|
||||||
new_objects = []
|
|
||||||
for obj in objects:
|
|
||||||
new_objects.extend(
|
|
||||||
[
|
|
||||||
obj.rotate(Axis.Z, rotation_angle).moved(location)
|
|
||||||
for location in LocationList._get_context().local_locations
|
|
||||||
]
|
|
||||||
)
|
|
||||||
context._add_to_context(*new_objects, mode=mode)
|
|
||||||
|
|
||||||
super().__init__(Compound.make_compound(new_objects).wrapped)
|
|
||||||
|
|
@ -63,7 +63,7 @@ class BuildLine(Builder):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _tag() -> str:
|
def _tag() -> str:
|
||||||
return BuildLine
|
return "BuildLine"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _obj(self):
|
def _obj(self):
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class BuildPart(Builder):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _tag() -> str:
|
def _tag() -> str:
|
||||||
return BuildPart
|
return "BuildPart"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _obj(self):
|
def _obj(self):
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class BaseLineObject(Wire):
|
||||||
curve: Union[Edge, Wire],
|
curve: Union[Edge, Wire],
|
||||||
mode: Mode = Mode.ADD,
|
mode: Mode = Mode.ADD,
|
||||||
):
|
):
|
||||||
context: BuildLine = BuildLine._get_context(self)
|
context: BuildLine = BuildLine._get_context(self, log=False)
|
||||||
|
|
||||||
if context is not None:
|
if context is not None:
|
||||||
context._add_to_context(*curve.edges(), mode=mode)
|
context._add_to_context(*curve.edges(), mode=mode)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ class BasePartObject(Part):
|
||||||
align_offset.append(-bbox.max.to_tuple()[i])
|
align_offset.append(-bbox.max.to_tuple()[i])
|
||||||
solid.move(Location(Vector(*align_offset)))
|
solid.move(Location(Vector(*align_offset)))
|
||||||
|
|
||||||
context: BuildPart = BuildPart._get_context(self)
|
context: BuildPart = BuildPart._get_context(self, log=False)
|
||||||
if context is None:
|
if context is None:
|
||||||
new_solids = [solid]
|
new_solids = [solid]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class BaseSketchObject(Sketch):
|
||||||
align_offset.append(-bbox.max.to_tuple()[i])
|
align_offset.append(-bbox.max.to_tuple()[i])
|
||||||
obj.move(Location(Vector(*align_offset)))
|
obj.move(Location(Vector(*align_offset)))
|
||||||
|
|
||||||
context: BuildSketch = BuildSketch._get_context(self)
|
context: BuildSketch = BuildSketch._get_context(self, log=False)
|
||||||
if context is None:
|
if context is None:
|
||||||
new_faces = obj.faces()
|
new_faces = obj.faces()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,19 @@ license:
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from build123d.build_enums import Mode, Kind, Keep
|
|
||||||
|
from build123d.build_common import Builder, LocationList, WorkplaneList, validate_inputs
|
||||||
|
from build123d.build_enums import Keep, Kind, Mode
|
||||||
|
from build123d.build_line import BuildLine
|
||||||
|
from build123d.build_part import BuildPart
|
||||||
|
from build123d.build_sketch import BuildSketch
|
||||||
from build123d.geometry import (
|
from build123d.geometry import (
|
||||||
|
Axis,
|
||||||
Location,
|
Location,
|
||||||
Matrix,
|
Matrix,
|
||||||
Plane,
|
Plane,
|
||||||
|
Rotation,
|
||||||
|
RotationLike,
|
||||||
Vector,
|
Vector,
|
||||||
)
|
)
|
||||||
from build123d.topology import (
|
from build123d.topology import (
|
||||||
|
|
@ -41,9 +49,9 @@ from build123d.topology import (
|
||||||
Curve,
|
Curve,
|
||||||
Edge,
|
Edge,
|
||||||
Face,
|
Face,
|
||||||
|
Matrix,
|
||||||
Part,
|
Part,
|
||||||
Plane,
|
Plane,
|
||||||
Matrix,
|
|
||||||
Shape,
|
Shape,
|
||||||
Sketch,
|
Sketch,
|
||||||
Solid,
|
Solid,
|
||||||
|
|
@ -51,15 +59,101 @@ from build123d.topology import (
|
||||||
Wire,
|
Wire,
|
||||||
)
|
)
|
||||||
|
|
||||||
from build123d.build_common import Builder, validate_inputs
|
|
||||||
|
|
||||||
logging.getLogger("build123d").addHandler(logging.NullHandler())
|
logging.getLogger("build123d").addHandler(logging.NullHandler())
|
||||||
logger = logging.getLogger("build123d")
|
logger = logging.getLogger("build123d")
|
||||||
|
|
||||||
|
|
||||||
#
|
def add(
|
||||||
# Operations
|
*objects: Union[Edge, Wire, Face, Solid, Compound],
|
||||||
#
|
rotation: Union[float, RotationLike] = None,
|
||||||
|
mode: Mode = Mode.ADD,
|
||||||
|
) -> Compound:
|
||||||
|
"""Generic Object: Add Object to Part or Sketch
|
||||||
|
|
||||||
|
Add an object to a builder.
|
||||||
|
|
||||||
|
if BuildPart:
|
||||||
|
Edges and Wires are added to pending_edges. Compounds of Face are added to
|
||||||
|
pending_faces. Solids or Compounds of Solid are combined into the part.
|
||||||
|
elif BuildSketch:
|
||||||
|
Edges and Wires are added to pending_edges. Compounds of Face are added to sketch.
|
||||||
|
elif BuildLine:
|
||||||
|
Edges and Wires are added to line.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
|
||||||
|
rotation (Union[float, RotationLike], optional): rotation angle for sketch,
|
||||||
|
rotation about each axis for part. Defaults to None.
|
||||||
|
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
|
||||||
|
"""
|
||||||
|
context: Builder = Builder._get_context(None)
|
||||||
|
if context is None:
|
||||||
|
raise RuntimeError("Add must have an active builder context")
|
||||||
|
validate_inputs(context, None, objects)
|
||||||
|
|
||||||
|
if isinstance(context, BuildPart):
|
||||||
|
if rotation is None:
|
||||||
|
rotation = Rotation(0, 0, 0)
|
||||||
|
elif isinstance(rotation, float):
|
||||||
|
raise ValueError("Float values of rotation are not valid for BuildPart")
|
||||||
|
elif isinstance(rotation, tuple):
|
||||||
|
rotation = Rotation(*rotation)
|
||||||
|
|
||||||
|
objects = [obj.moved(rotation) for obj in objects]
|
||||||
|
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
|
||||||
|
new_wires = [obj for obj in objects if isinstance(obj, Wire)]
|
||||||
|
new_faces = [obj for obj in objects if isinstance(obj, Face)]
|
||||||
|
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
|
||||||
|
for compound in filter(lambda o: isinstance(o, Compound), objects):
|
||||||
|
new_edges.extend(compound.get_type(Edge))
|
||||||
|
new_wires.extend(compound.get_type(Wire))
|
||||||
|
new_faces.extend(compound.get_type(Face))
|
||||||
|
new_solids.extend(compound.get_type(Solid))
|
||||||
|
for new_wire in new_wires:
|
||||||
|
new_edges.extend(new_wire.edges())
|
||||||
|
|
||||||
|
# Add the pending Edges in one group
|
||||||
|
if not LocationList._get_context():
|
||||||
|
raise RuntimeError("There is no active Locations context")
|
||||||
|
located_edges = [
|
||||||
|
edge.moved(location)
|
||||||
|
for edge in new_edges
|
||||||
|
for location in LocationList._get_context().locations
|
||||||
|
]
|
||||||
|
context._add_to_pending(*located_edges)
|
||||||
|
new_objects = located_edges
|
||||||
|
|
||||||
|
# Add to pending Faces batched by workplane
|
||||||
|
for workplane in WorkplaneList._get_context().workplanes:
|
||||||
|
faces_per_workplane = []
|
||||||
|
for location in LocationList._get_context().locations:
|
||||||
|
for face in new_faces:
|
||||||
|
faces_per_workplane.append(face.moved(location))
|
||||||
|
context._add_to_pending(*faces_per_workplane, face_plane=workplane)
|
||||||
|
new_objects.extend(faces_per_workplane)
|
||||||
|
|
||||||
|
# Add to context Solids
|
||||||
|
located_solids = [
|
||||||
|
solid.moved(location)
|
||||||
|
for solid in new_solids
|
||||||
|
for location in LocationList._get_context().locations
|
||||||
|
]
|
||||||
|
context._add_to_context(*located_solids, mode=mode)
|
||||||
|
new_objects.extend(located_solids)
|
||||||
|
|
||||||
|
elif isinstance(context, (BuildLine, BuildSketch)):
|
||||||
|
rotation_angle = rotation if isinstance(rotation, (int, float)) else 0.0
|
||||||
|
new_objects = []
|
||||||
|
for obj in objects:
|
||||||
|
new_objects.extend(
|
||||||
|
[
|
||||||
|
obj.rotate(Axis.Z, rotation_angle).moved(location)
|
||||||
|
for location in LocationList._get_context().local_locations
|
||||||
|
]
|
||||||
|
)
|
||||||
|
context._add_to_context(*new_objects, mode=mode)
|
||||||
|
|
||||||
|
return Compound.make_compound(new_objects)
|
||||||
|
|
||||||
|
|
||||||
def bounding_box(
|
def bounding_box(
|
||||||
|
|
@ -76,8 +170,8 @@ def bounding_box(
|
||||||
objects (Shape): sequence of objects
|
objects (Shape): sequence of objects
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("bounding_box")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "bounding_box", objects)
|
||||||
|
|
||||||
if (not objects and context is None) or (
|
if (not objects and context is None) or (
|
||||||
not objects and context is not None and not context._obj
|
not objects and context is not None and not context._obj
|
||||||
|
|
@ -141,12 +235,13 @@ def chamfer(
|
||||||
target (Union[Face, Sketch, Solid, Part], optional): object to chamfer. Defaults to None.
|
target (Union[Face, Sketch, Solid, Part], optional): object to chamfer. Defaults to None.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
|
ValueError: no objects provided
|
||||||
ValueError: objects must be Edges
|
ValueError: objects must be Edges
|
||||||
ValueError: objects must be Vertices
|
ValueError: objects must be Vertices
|
||||||
ValueError: missing target object
|
ValueError: missing target object
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("chamfer")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "chamfer", objects)
|
||||||
|
|
||||||
if (not objects and context is None) or (
|
if (not objects and context is None) or (
|
||||||
not objects and context is not None and not context._obj
|
not objects and context is not None and not context._obj
|
||||||
|
|
@ -204,8 +299,8 @@ def fillet(
|
||||||
ValueError: objects must be Vertices
|
ValueError: objects must be Vertices
|
||||||
ValueError: missing target object
|
ValueError: missing target object
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("fillet")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "fillet", objects)
|
||||||
|
|
||||||
if (not objects and context is None) or (
|
if (not objects and context is None) or (
|
||||||
not objects and context is not None and not context._obj
|
not objects and context is not None and not context._obj
|
||||||
|
|
@ -262,8 +357,8 @@ def mirror(
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: missing objects
|
ValueError: missing objects
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("mirror")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "mirror", objects)
|
||||||
|
|
||||||
if not objects:
|
if not objects:
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
@ -314,8 +409,8 @@ def offset(
|
||||||
ValueError: missing objects
|
ValueError: missing objects
|
||||||
ValueError: Invalid object type
|
ValueError: Invalid object type
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("offset")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "offset", objects)
|
||||||
|
|
||||||
if not objects:
|
if not objects:
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
@ -404,8 +499,8 @@ def scale(
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: missing objects
|
ValueError: missing objects
|
||||||
"""
|
"""
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("scale")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "scale", objects)
|
||||||
|
|
||||||
if not objects:
|
if not objects:
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
@ -491,8 +586,8 @@ def split(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
context: Builder = Builder._get_context(None)
|
context: Builder = Builder._get_context("split")
|
||||||
validate_inputs(context, None, objects)
|
validate_inputs(context, "split", objects)
|
||||||
|
|
||||||
if not objects:
|
if not objects:
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,8 @@ def extrude(
|
||||||
Returns:
|
Returns:
|
||||||
Part: extruded object
|
Part: extruded object
|
||||||
"""
|
"""
|
||||||
context: BuildPart = BuildPart._get_context(None)
|
context: BuildPart = BuildPart._get_context("extrude")
|
||||||
validate_inputs(context, None, to_extrude)
|
validate_inputs(context, "extrude", to_extrude)
|
||||||
|
|
||||||
to_extrude_faces: list[Face]
|
to_extrude_faces: list[Face]
|
||||||
|
|
||||||
|
|
@ -173,7 +173,8 @@ def loft(
|
||||||
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
context: BuildPart = BuildPart._get_context(None)
|
context: BuildPart = BuildPart._get_context("loft")
|
||||||
|
validate_inputs(context, "loft", sections)
|
||||||
|
|
||||||
if not sections:
|
if not sections:
|
||||||
loft_wires = [face.outer_wire() for face in context.pending_faces]
|
loft_wires = [face.outer_wire() for face in context.pending_faces]
|
||||||
|
|
@ -222,7 +223,8 @@ def revolve(
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: Invalid axis of revolution
|
ValueError: Invalid axis of revolution
|
||||||
"""
|
"""
|
||||||
context: BuildPart = BuildPart._get_context(None)
|
context: BuildPart = BuildPart._get_context("revolve")
|
||||||
|
validate_inputs(context, "revolve", 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
|
||||||
|
|
@ -279,7 +281,8 @@ def section(
|
||||||
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.INTERSECT.
|
mode (Mode, optional): combination mode. Defaults to Mode.INTERSECT.
|
||||||
"""
|
"""
|
||||||
context: BuildPart = BuildPart._get_context(None)
|
context: BuildPart = BuildPart._get_context("section")
|
||||||
|
validate_inputs(context, "section", None)
|
||||||
|
|
||||||
if context is not None and obj is None:
|
if context is not None and obj is None:
|
||||||
max_size = context.part.bounding_box().diagonal
|
max_size = context.part.bounding_box().diagonal
|
||||||
|
|
@ -341,7 +344,8 @@ def sweep(
|
||||||
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
clean (bool, optional): Remove extraneous internal structure. Defaults to True.
|
||||||
mode (Mode, optional): combination. Defaults to Mode.ADD.
|
mode (Mode, optional): combination. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
context: BuildPart = BuildPart._get_context(None)
|
context: BuildPart = BuildPart._get_context("sweep")
|
||||||
|
validate_inputs(context, "sweep", sections)
|
||||||
|
|
||||||
if path is None:
|
if path is None:
|
||||||
path_wire = context.pending_edges_as_wire
|
path_wire = context.pending_edges_as_wire
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ def make_face(*edges: Edge, mode: Mode = Mode.ADD) -> Sketch:
|
||||||
edges (Edge): sequence of perimeter edges
|
edges (Edge): sequence of perimeter edges
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
context: BuildSketch = BuildSketch._get_context(None)
|
context: BuildSketch = BuildSketch._get_context("make_face")
|
||||||
validate_inputs(context, None, edges)
|
validate_inputs(context, "make_face", edges)
|
||||||
|
|
||||||
if edges:
|
if edges:
|
||||||
outer_edges = list(edges)
|
outer_edges = list(edges)
|
||||||
|
|
@ -71,8 +71,8 @@ def make_hull(*edges: Edge, mode: Mode = Mode.ADD) -> Sketch:
|
||||||
pending and sketch edges.
|
pending and sketch edges.
|
||||||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||||
"""
|
"""
|
||||||
context: BuildSketch = BuildSketch._get_context(None)
|
context: BuildSketch = BuildSketch._get_context("make_hull")
|
||||||
validate_inputs(context, None, edges)
|
validate_inputs(context, "make_hull", edges)
|
||||||
|
|
||||||
if edges:
|
if edges:
|
||||||
hull_edges = list(edges)
|
hull_edges = list(edges)
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,7 @@ class TestValidateInputs(unittest.TestCase):
|
||||||
with BuildPart() as p:
|
with BuildPart() as p:
|
||||||
Box(1, 1, 1)
|
Box(1, 1, 1)
|
||||||
with BuildSketch():
|
with BuildSketch():
|
||||||
Add(p)
|
add(p)
|
||||||
|
|
||||||
def test_no_sequence(self):
|
def test_no_sequence(self):
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
|
|
|
||||||
|
|
@ -67,28 +67,28 @@ class AddTests(unittest.TestCase):
|
||||||
def test_add_to_line(self):
|
def test_add_to_line(self):
|
||||||
# Add Edge
|
# Add Edge
|
||||||
with BuildLine() as test:
|
with BuildLine() as test:
|
||||||
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
||||||
self.assertTupleAlmostEquals((test.wires()[0] @ 1).to_tuple(), (1, 1, 1), 5)
|
self.assertTupleAlmostEquals((test.wires()[0] @ 1).to_tuple(), (1, 1, 1), 5)
|
||||||
# Add Wire
|
# Add Wire
|
||||||
with BuildLine() as wire:
|
with BuildLine() as wire:
|
||||||
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
|
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
|
||||||
with BuildLine() as test:
|
with BuildLine() as test:
|
||||||
Add(wire.wires()[0])
|
add(wire.wires()[0])
|
||||||
self.assertEqual(len(test.line.edges()), 3)
|
self.assertEqual(len(test.line.edges()), 3)
|
||||||
|
|
||||||
def test_add_to_sketch(self):
|
def test_add_to_sketch(self):
|
||||||
with BuildSketch() as test:
|
with BuildSketch() as test:
|
||||||
Add(Face.make_rect(10, 10))
|
add(Face.make_rect(10, 10))
|
||||||
self.assertAlmostEqual(test.sketch.area, 100, 5)
|
self.assertAlmostEqual(test.sketch.area, 100, 5)
|
||||||
|
|
||||||
def test_add_to_part(self):
|
def test_add_to_part(self):
|
||||||
# Add Solid
|
# Add Solid
|
||||||
with BuildPart() as test:
|
with BuildPart() as test:
|
||||||
Add(Solid.make_box(10, 10, 10))
|
add(Solid.make_box(10, 10, 10))
|
||||||
self.assertAlmostEqual(test.part.volume, 1000, 5)
|
self.assertAlmostEqual(test.part.volume, 1000, 5)
|
||||||
# Add Compound
|
# Add Compound
|
||||||
with BuildPart() as test:
|
with BuildPart() as test:
|
||||||
Add(
|
add(
|
||||||
Compound.make_compound(
|
Compound.make_compound(
|
||||||
[
|
[
|
||||||
Solid.make_box(10, 10, 10),
|
Solid.make_box(10, 10, 10),
|
||||||
|
|
@ -101,17 +101,17 @@ class AddTests(unittest.TestCase):
|
||||||
with BuildLine() as wire:
|
with BuildLine() as wire:
|
||||||
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
|
Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1))
|
||||||
with BuildPart() as test:
|
with BuildPart() as test:
|
||||||
Add(wire.wires()[0])
|
add(wire.wires()[0])
|
||||||
self.assertEqual(len(test.pending_edges), 3)
|
self.assertEqual(len(test.pending_edges), 3)
|
||||||
|
|
||||||
def test_errors(self):
|
def test_errors(self):
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
||||||
|
|
||||||
def test_unsupported_builder(self):
|
def test_unsupported_builder(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
with _TestBuilder():
|
with _TestBuilder():
|
||||||
Add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
add(Edge.make_line((0, 0, 0), (1, 1, 1)))
|
||||||
|
|
||||||
def test_local_global_locations(self):
|
def test_local_global_locations(self):
|
||||||
"""Check that add is using a local location list"""
|
"""Check that add is using a local location list"""
|
||||||
|
|
@ -124,7 +124,7 @@ class AddTests(unittest.TestCase):
|
||||||
extrude(amount=10)
|
extrude(amount=10)
|
||||||
topf = mainp.faces().sort_by(Axis.Z)[-1]
|
topf = mainp.faces().sort_by(Axis.Z)[-1]
|
||||||
with BuildSketch(topf):
|
with BuildSketch(topf):
|
||||||
Add(vertwalls.sketch)
|
add(vertwalls.sketch)
|
||||||
extrude(amount=15)
|
extrude(amount=15)
|
||||||
|
|
||||||
self.assertEqual(len(mainp.solids()), 1)
|
self.assertEqual(len(mainp.solids()), 1)
|
||||||
|
|
@ -135,7 +135,7 @@ class AddTests(unittest.TestCase):
|
||||||
]
|
]
|
||||||
with BuildPart(Plane.XY, Plane.YZ) as multiple:
|
with BuildPart(Plane.XY, Plane.YZ) as multiple:
|
||||||
with Locations((1, 1), (-1, -1)) as locs:
|
with Locations((1, 1), (-1, -1)) as locs:
|
||||||
Add(*faces)
|
add(*faces)
|
||||||
self.assertEqual(len(multiple.pending_faces), 16)
|
self.assertEqual(len(multiple.pending_faces), 16)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -283,7 +283,7 @@ class ChamferTests(unittest.TestCase):
|
||||||
self.assertAlmostEqual(test.sketch.area, 200 - 4 * 0.5, 5)
|
self.assertAlmostEqual(test.sketch.area, 200 - 4 * 0.5, 5)
|
||||||
|
|
||||||
def test_errors(self):
|
def test_errors(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(RuntimeError):
|
||||||
with BuildLine():
|
with BuildLine():
|
||||||
chamfer(length=1)
|
chamfer(length=1)
|
||||||
|
|
||||||
|
|
@ -321,7 +321,7 @@ class FilletTests(unittest.TestCase):
|
||||||
self.assertAlmostEqual(test.sketch.area, 200 - 4 + pi, 5)
|
self.assertAlmostEqual(test.sketch.area, 200 - 4 + pi, 5)
|
||||||
|
|
||||||
def test_errors(self):
|
def test_errors(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(RuntimeError):
|
||||||
with BuildLine():
|
with BuildLine():
|
||||||
fillet(radius=1)
|
fillet(radius=1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,11 @@ class TestBuildOnPlanes(unittest.TestCase):
|
||||||
def test_not_coplanar(self):
|
def test_not_coplanar(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with BuildSketch() as error:
|
with BuildSketch() as error:
|
||||||
Add(Face.make_rect(1, 1, Plane.XY.offset(1)))
|
add(Face.make_rect(1, 1, Plane.XY.offset(1)))
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with BuildSketch() as error:
|
with BuildSketch() as error:
|
||||||
Add(Face.make_rect(1, 1, Plane.XZ))
|
add(Face.make_rect(1, 1, Plane.XZ))
|
||||||
|
|
||||||
def test_changing_geometry(self):
|
def test_changing_geometry(self):
|
||||||
with BuildSketch() as s:
|
with BuildSketch() as s:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue