From ea2c2011925be66b7c934644b7ab3cfd2598cbea Mon Sep 17 00:00:00 2001 From: Roger Maitland Date: Tue, 1 Nov 2022 14:38:53 -0400 Subject: [PATCH] Changed Shape method to properties - Issue #44 --- docs/direct_api_classes.svg | 354 +++++++++++++++++---------------- examples/heat_exchanger.py | 6 +- src/build123d/build_common.py | 6 +- src/build123d/build_generic.py | 2 +- src/build123d/build_line.py | 4 +- src/build123d/build_part.py | 12 +- src/build123d/direct_api.py | 215 ++++++++++---------- src/build123d/hull.py | 4 +- tests/build_common_tests.py | 68 +++---- tests/build_generic_tests.py | 44 ++-- tests/build_line_tests.py | 10 +- tests/build_part_tests.py | 72 +++---- tests/build_sketch_tests.py | 32 +-- tests/direct_api_tests.py | 116 +++++------ 14 files changed, 461 insertions(+), 484 deletions(-) diff --git a/docs/direct_api_classes.svg b/docs/direct_api_classes.svg index 1d0d8fd..4996471 100644 --- a/docs/direct_api_classes.svg +++ b/docs/direct_api_classes.svg @@ -39,19 +39,19 @@ BoundBox -wrapped -xlen -xmax -xmin -ylen -ymax -ymin -zlen -zmax -zmin - -add(obj: Union[tuple[float, float, float], Vector, BoundBox], tol: float): BoundBox -center(): Vector +center +wrapped +xlen +xmax +xmin +ylen +ymax +ymin +zlen +zmax +zmin + +add(obj: Union[tuple[float, float, float], Vector, BoundBox], tol: float): BoundBox diagonal_length(): float find_outside_box_2d(bb1: BoundBox, bb2): Optional[BoundBox] is_inside(b2: BoundBox): bool @@ -141,63 +141,63 @@ Shape -for_construction : bool -label : str -orientation -position -wrapped - -area(): float -bounding_box(tolerance: float): BoundBox -cast(cls: TopoDS_Shape, obj: bool, for_construction): Shape -clean(): Shape -combined_center(objects: CenterOf, center_of): Vector -compounds(): ShapeList['Compound'] -compute_mass(obj): float -copy(): Shape -cut(): Shape -distance(other: Shape): float -distances(): Iterator[float] -edges(): ShapeList['Edge'] -export_brep(f: Union[str, BytesIO]): bool -export_step(file_name: str): IFSelect_ReturnStatus -export_stl(file_name: str, tolerance: float, angular_tolerance: float, ascii: bool): bool -faces(): ShapeList['Face'] -faces_intersected_by_line(point: VectorLike, axis: VectorLike, tol: float, direction: Direction): ShapeList[Face] -find_intersection(point: VectorLike, direction: VectorLike): list[tuple[Vector, Vector]] -fix(): Shape -fuse(): Shape -geom_type(): Geoms -hash_code(): int -import_brep(cls: Union[str, BytesIO], f): Shape -intersect(): Shape -is_equal(other: Shape): bool -is_null(): bool -is_same(other: Shape): bool -is_valid(): bool -locate(loc: Location): Shape -located(loc: Location): Shape -location(): Location -max_fillet(edge_list: Iterable[Edge], tolerance, max_iterations: int): float -mesh(tolerance: float, angular_tolerance: float) -mirror(mirror_plane: Plane): Shape -move(loc: Location): Shape -moved(loc: Location): Shape -project_text(txt: str, fontsize: float, depth: float, path: Union[Wire, Edge], font: str, font_path: str, kind: FontStyle, valign: Valign, start: float): Compound -rotate(axis: Axis, angle: float): Shape -scale(factor: float): Shape -shape_type(): Shapes -shells(): ShapeList['Shell'] -solids(): ShapeList['Solid'] -split(): Shape -tessellate(tolerance: float, angular_tolerance: float): Tuple[list[Vector], list[Tuple[int, int, int]]] -to_vtk_poly_data(tolerance: float, angular_tolerance: float, normals: bool): vtkPolyData -transform_geometry(t_matrix: Matrix): Shape -transform_shape(t_matrix: Matrix): Shape -transformed(rotate: VectorLike, offset: VectorLike): Shape -translate(vector: VectorLike): Shape -vertices(): ShapeList['Vertex'] -volume(): float +area +for_construction : bool +label : str +location +orientation +position +volume +wrapped + +bounding_box(tolerance: float): BoundBox +cast(cls: TopoDS_Shape, obj: bool, for_construction): Shape +clean(): Shape +combined_center(objects: CenterOf, center_of): Vector +compounds(): ShapeList['Compound'] +compute_mass(obj): float +copy(): Shape +cut(): Shape +distance(other: Shape): float +distances(): Iterator[float] +edges(): ShapeList['Edge'] +export_brep(f: Union[str, BytesIO]): bool +export_step(file_name: str): IFSelect_ReturnStatus +export_stl(file_name: str, tolerance: float, angular_tolerance: float, ascii: bool): bool +faces(): ShapeList['Face'] +faces_intersected_by_line(point: VectorLike, axis: VectorLike, tol: float, direction: Direction): ShapeList[Face] +find_intersection(point: VectorLike, direction: VectorLike): list[tuple[Vector, Vector]] +fix(): Shape +fuse(): Shape +geom_type(): Geoms +hash_code(): int +import_brep(cls: Union[str, BytesIO], f): Shape +intersect(): Shape +is_equal(other: Shape): bool +is_null(): bool +is_same(other: Shape): bool +is_valid(): bool +locate(loc: Location): Shape +located(loc: Location): Shape +max_fillet(edge_list: Iterable[Edge], tolerance, max_iterations: int): float +mesh(tolerance: float, angular_tolerance: float) +mirror(mirror_plane: Plane): Shape +move(loc: Location): Shape +moved(loc: Location): Shape +project_text(txt: str, fontsize: float, depth: float, path: Union[Wire, Edge], font: str, font_path: str, kind: FontStyle, valign: Valign, start: float): Compound +rotate(axis: Axis, angle: float): Shape +scale(factor: float): Shape +shape_type(): Shapes +shells(): ShapeList['Shell'] +solids(): ShapeList['Solid'] +split(): Shape +tessellate(tolerance: float, angular_tolerance: float): Tuple[list[Vector], list[Tuple[int, int, int]]] +to_vtk_poly_data(tolerance: float, angular_tolerance: float, normals: bool): vtkPolyData +transform_geometry(t_matrix: Matrix): Shape +transform_shape(t_matrix: Matrix): Shape +transformed(rotate: VectorLike, offset: VectorLike): Shape +translate(vector: VectorLike): Shape +vertices(): ShapeList['Vertex'] wires(): ShapeList['Wire'] @@ -209,90 +209,93 @@ build123d.direct_api.Edge - -Edge - - -arc_center(): Vector -close(): Union[Edge, Wire] -distribute_locations(count: int, start: float, stop: float, positions_only: bool): list[Location] -make_circle(cls: float, radius: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2, orientation): Edge -make_ellipse(cls: float, x_radius: float, y_radius: VectorLike, pnt: VectorLike, dir: VectorLike, xdir: float, angle1: float, angle2: AngularDirection, angular_direction): Edge -make_line(cls: VectorLike, v1: VectorLike, v2): Edge -make_spline(cls: list[VectorLike], points: list[VectorLike], tangents: bool, periodic: list[float], parameters: bool, scale: float, tol): Edge -make_spline_approx(cls: list[VectorLike], points: float, tol: Tuple[float, float, float], smoothing: int, min_deg: int, max_deg): Edge -make_tangent_arc(cls: VectorLike, start: VectorLike, tangent: VectorLike, end): Edge -make_three_point_arc(cls: VectorLike, v1: VectorLike, v2: VectorLike, v3): Edge -project_to_shape(target_object: Shape, direction: VectorLike, center: VectorLike): list[Edge] -to_wire(): Wire + +Edge + +arc_center + +close(): Union[Edge, Wire] +distribute_locations(count: int, start: float, stop: float, positions_only: bool): list[Location] +make_circle(cls: float, radius: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2, orientation): Edge +make_ellipse(cls: float, x_radius: float, y_radius: VectorLike, pnt: VectorLike, dir: VectorLike, xdir: float, angle1: float, angle2: AngularDirection, angular_direction): Edge +make_line(cls: VectorLike, v1: VectorLike, v2): Edge +make_spline(cls: list[VectorLike], points: list[VectorLike], tangents: bool, periodic: list[float], parameters: bool, scale: float, tol): Edge +make_spline_approx(cls: list[VectorLike], points: float, tol: Tuple[float, float, float], smoothing: int, min_deg: int, max_deg): Edge +make_tangent_arc(cls: VectorLike, start: VectorLike, tangent: VectorLike, end): Edge +make_three_point_arc(cls: VectorLike, v1: VectorLike, v2: VectorLike, v3): Edge +project_to_shape(target_object: Shape, direction: VectorLike, center: VectorLike): list[Edge] +to_wire(): Wire build123d.direct_api.Mixin1D - -Mixin1D - - -center(center_of: CenterOf): Vector -end_point(): Vector -is_closed(): bool -length(): float -location_at(distance: float, position_mode: PositionMode, frame_method: FrameMethod, planar: bool): Location -locations(ds: Iterable[float], position_mode: PositionMode, frame_method: FrameMethod, planar: bool): list[Location] -normal(): Vector -param_at(d: float): float -position_at(d: float, position_mode: PositionMode): Vector -positions(ds: Iterable[float], position_mode: PositionMode): list[Vector] -project(face: Face, d: VectorLike, closest: bool): Union[Mixin1D, list[Mixin1D]] -radius(): float -start_point(): Vector -tangent_at(location_param: float, position_mode: PositionMode): Vector + +Mixin1D + +center +center_of_mass +length +radius + +end_point(): Vector +is_closed(): bool +location_at(distance: float, position_mode: PositionMode, frame_method: FrameMethod, planar: bool): Location +locations(ds: Iterable[float], position_mode: PositionMode, frame_method: FrameMethod, planar: bool): list[Location] +normal(): Vector +param_at(d: float): float +position_at(d: float, position_mode: PositionMode): Vector +positions(ds: Iterable[float], position_mode: PositionMode): list[Vector] +project(face: Face, d: VectorLike, closest: bool): Union[Mixin1D, list[Mixin1D]] +start_point(): Vector +tangent_at(location_param: float, position_mode: PositionMode): Vector build123d.direct_api.Edge->build123d.direct_api.Mixin1D - - + + build123d.direct_api.Edge->build123d.direct_api.Shape - - + + build123d.direct_api.Face - -Face - - -center(center_of: CenterOf): Vector -chamfer_2d(d: float, vertices: Iterable[Vertex]): Face -construct_on(cls: Face, f: Wire, outer): Face -fillet_2d(radius: float, vertices: Iterable[Vertex]): Face -inner_wires(): list[Wire] -is_inside(point: VectorLike, tolerance: float): bool -make_from_wires(cls: Wire, outer_wire: list[Wire], inner_wires): Face -make_holes(interior_wires: list[Wire]): Face -make_plane(cls: VectorLike, pnt: VectorLike, dir): Face -make_rect(cls: float, width: float, height: VectorLike, pnt: VectorLike, normal): Face -make_ruled_surface(cls: Edge, edge1: Edge, edge2): Face -make_surface(cls: Union[Wire, list[Edge]], exterior: list[VectorLike], surface_points: list[Wire], interior_wires): Face -make_surface_from_curves(cls, curve1, curve2): Face -make_surface_from_points(cls: list[list[VectorLike]], points: float, tol: Tuple[float, float, float], smoothing: int, min_deg: int, max_deg): Face -normal_at(surface_point: VectorLike): Vector -outer_wire(): Wire -project(other: Face, d: VectorLike): Face -project_to_shape(target_object: Shape, direction: VectorLike, center: VectorLike, internal_face_points: list[Vector]): list[Face] -thicken(depth: float, direction: VectorLike): Solid -to_pln(): gp_Pln + +Face + +center +center_of_geometry +center_of_mass + +chamfer_2d(d: float, vertices: Iterable[Vertex]): Face +construct_on(cls: Face, f: Wire, outer): Face +fillet_2d(radius: float, vertices: Iterable[Vertex]): Face +inner_wires(): list[Wire] +is_inside(point: VectorLike, tolerance: float): bool +make_from_wires(cls: Wire, outer_wire: list[Wire], inner_wires): Face +make_holes(interior_wires: list[Wire]): Face +make_plane(cls: VectorLike, pnt: VectorLike, dir): Face +make_rect(cls: float, width: float, height: VectorLike, pnt: VectorLike, normal): Face +make_ruled_surface(cls: Edge, edge1: Edge, edge2): Face +make_surface(cls: Union[Wire, list[Edge]], exterior: list[VectorLike], surface_points: list[Wire], interior_wires): Face +make_surface_from_curves(cls, curve1, curve2): Face +make_surface_from_points(cls: list[list[VectorLike]], points: float, tol: Tuple[float, float, float], smoothing: int, min_deg: int, max_deg): Face +normal_at(surface_point: VectorLike): Vector +outer_wire(): Wire +project(other: Face, d: VectorLike): Face +project_to_shape(target_object: Shape, direction: VectorLike, center: VectorLike, internal_face_points: list[Vector]): list[Face] +thicken(depth: float, direction: VectorLike): Solid +to_pln(): gp_Pln build123d.direct_api.Face->build123d.direct_api.Shape - - + + @@ -398,37 +401,38 @@ build123d.direct_api.Solid - -Solid - - -center(center_of: CenterOf): Vector -extrude_linear(cls: Union[Face, Wire], section: VectorLike, normal: list[Wire], inner_wires: float, taper): Solid -extrude_linear_with_rotation(cls: Union[Face, Wire], section: VectorLike, center: VectorLike, normal: float, angle: list[Wire], inner_wires): Solid -is_solid(obj): bool -make_box(cls: float, length: float, width: float, height: VectorLike, pnt: VectorLike, dir): Solid -make_cone(cls: float, radius1: float, radius2: float, height: VectorLike, pnt: VectorLike, dir: float, angle): Solid -make_cylinder(cls: float, radius: float, height: VectorLike, pnt: VectorLike, dir: float, angle): Solid -make_loft(cls: list[Wire], list_of_wire: bool, ruled): Solid -make_solid(cls: Shell, shell): Solid -make_sphere(cls: float, radius: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2: float, angle3): Shape -make_torus(cls: float, radius1: float, radius2: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2): Solid -make_wedge(cls: float, dx: float, dy: float, dz: float, xmin: float, zmin: float, xmax: float, zmax: VectorLike, pnt: VectorLike, dir): Solid -revolve(cls: Union[Face, Wire], section: float, angle: Axis, axis: list[Wire], inner_wires): Solid -sweep(cls: Union[Face, Wire], section: Union[Wire, Edge], path: list[Wire], inner_wires: bool, make_solid: bool, is_frenet: Union[Vector, Wire, Edge, None], mode: Transition, transition): Solid -sweep_multi(cls: Iterable[Union[Wire, Face]], profiles: Union[Wire, Edge], path: bool, make_solid: bool, is_frenet: Union[Vector, Wire, Edge, None], mode): Solid + +Solid + +center +center_of_mass + +extrude_linear(cls: Union[Face, Wire], section: VectorLike, normal: list[Wire], inner_wires: float, taper): Solid +extrude_linear_with_rotation(cls: Union[Face, Wire], section: VectorLike, center: VectorLike, normal: float, angle: list[Wire], inner_wires): Solid +is_solid(obj): bool +make_box(cls: float, length: float, width: float, height: VectorLike, pnt: VectorLike, dir): Solid +make_cone(cls: float, radius1: float, radius2: float, height: VectorLike, pnt: VectorLike, dir: float, angle): Solid +make_cylinder(cls: float, radius: float, height: VectorLike, pnt: VectorLike, dir: float, angle): Solid +make_loft(cls: list[Wire], list_of_wire: bool, ruled): Solid +make_solid(cls: Shell, shell): Solid +make_sphere(cls: float, radius: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2: float, angle3): Shape +make_torus(cls: float, radius1: float, radius2: VectorLike, pnt: VectorLike, dir: float, angle1: float, angle2): Solid +make_wedge(cls: float, dx: float, dy: float, dz: float, xmin: float, zmin: float, xmax: float, zmax: VectorLike, pnt: VectorLike, dir): Solid +revolve(cls: Union[Face, Wire], section: float, angle: Axis, axis: list[Wire], inner_wires): Solid +sweep(cls: Union[Face, Wire], section: Union[Wire, Edge], path: list[Wire], inner_wires: bool, make_solid: bool, is_frenet: Union[Vector, Wire, Edge, None], mode: Transition, transition): Solid +sweep_multi(cls: Iterable[Union[Wire, Face]], profiles: Union[Wire, Edge], path: bool, make_solid: bool, is_frenet: Union[Vector, Wire, Edge, None], mode): Solid build123d.direct_api.Solid->build123d.direct_api.Mixin3D - - + + build123d.direct_api.Solid->build123d.direct_api.Shape - - + + @@ -441,18 +445,18 @@ Y Y Z -vector_index : int -wrapped - -add(v: Vector): Vector -center(): Vector -cross(v: Vector): Vector -distance_to_line() -distance_to_plane() -dot(v: Vector): float -get_angle(v: Vector): float -get_signed_angle(v: Vector, normal: Vector): float -length(): float +center +length +vector_index : int +wrapped + +add(v: Vector): Vector +cross(v: Vector): Vector +distance_to_line() +distance_to_plane() +dot(v: Vector): float +get_angle(v: Vector): float +get_signed_angle(v: Vector, normal: Vector): float multiply(scale: float): Vector normalized(): Vector project_to_line(line: Vector): Vector @@ -545,10 +549,10 @@ X Y Z -for_construction : bool -wrapped - -center(): Vector +center +for_construction : bool +wrapped + to_tuple(): tuple[float, float, float] to_vector(): Vector @@ -583,8 +587,8 @@ build123d.direct_api.Wire->build123d.direct_api.Mixin1D - - + + diff --git a/examples/heat_exchanger.py b/examples/heat_exchanger.py index 01d69bb..af2c441 100644 --- a/examples/heat_exchanger.py +++ b/examples/heat_exchanger.py @@ -49,7 +49,7 @@ with Workplanes(Plane.XY): x_count=exchanger_diameter // tube_diameter, y_count=exchanger_diameter // tube_diameter, ) - if l.position.length() < bundle_diameter / 2 + if l.position.length < bundle_diameter / 2 ] tube_count = len(tube_locations) print(f"{tube_count=}") @@ -71,7 +71,7 @@ with BuildPart() as heat_exchanger: with Locations(*tube_locations): Circle(radius=tube_diameter / 2 - tube_wall_thickness, mode=Mode.SUBTRACT) Extrude(amount=plate_thickness) - half_volume_before_fillet = heat_exchanger.part.volume() + half_volume_before_fillet = heat_exchanger.part.volume # Simulate welded tubes by adding a fillet to the outside radius of the tubes Fillet( *heat_exchanger.edges() @@ -80,7 +80,7 @@ with BuildPart() as heat_exchanger: .sort_by(Axis.Z, reverse=True)[2 * tube_count : 3 * tube_count], radius=fillet_radius, ) - half_volume_after_fillet = heat_exchanger.part.volume() + half_volume_after_fillet = heat_exchanger.part.volume Mirror(about=Plane.XY) fillet_volume = 2 * (half_volume_after_fillet - half_volume_before_fillet) diff --git a/src/build123d/build_common.py b/src/build123d/build_common.py index aa4accd..4d37900 100644 --- a/src/build123d/build_common.py +++ b/src/build123d/build_common.py @@ -574,13 +574,13 @@ class Workplanes(WorkplaneList): plane_face = Face.make_rect(1, 1).move(obj) self.workplanes.append( Plane( - origin=plane_face.center(), - z_dir=plane_face.normal_at(plane_face.center()), + origin=plane_face.center, + z_dir=plane_face.normal_at(plane_face.center), ) ) elif isinstance(obj, Face): self.workplanes.append( - Plane(origin=obj.center(), z_dir=obj.normal_at(obj.center())) + Plane(origin=obj.center, z_dir=obj.normal_at(obj.center)) ) else: raise ValueError(f"Workplanes does not accept {type(obj)}") diff --git a/src/build123d/build_generic.py b/src/build123d/build_generic.py index 372d872..fdaea6a 100644 --- a/src/build123d/build_generic.py +++ b/src/build123d/build_generic.py @@ -479,7 +479,7 @@ class Scale(Compound): ) new_objects = [] for obj in objects: - current_location = obj.location() + current_location = obj.location obj_at_origin = obj.located(Location(Vector())) new_objects.append( obj_at_origin.transform_geometry(scale_matrix).locate(current_location) diff --git a/src/build123d/build_line.py b/src/build123d/build_line.py index 8434720..b5b6187 100644 --- a/src/build123d/build_line.py +++ b/src/build123d/build_line.py @@ -343,7 +343,7 @@ class Polyline(Wire): Edge.make_line(lines_pts[i], lines_pts[i + 1]) for i in range(len(lines_pts) - 1) ] - if close and (new_edges[0] @ 0 - new_edges[-1] @ 1).length() > 1e-5: + if close and (new_edges[0] @ 0 - new_edges[-1] @ 1).length > 1e-5: new_edges.append(Edge.make_line(new_edges[-1] @ 1, new_edges[0] @ 0)) context._add_to_context(*new_edges, mode=mode) @@ -378,7 +378,7 @@ class RadiusArc(Edge): end = Vector(end_point) # Calculate the sagitta from the radius - length = end.sub(start).length() / 2.0 + length = end.sub(start).length / 2.0 try: sagitta = abs(radius) - sqrt(radius**2 - length**2) except ValueError as exception: diff --git a/src/build123d/build_part.py b/src/build123d/build_part.py index a87de72..8d882ce 100644 --- a/src/build123d/build_part.py +++ b/src/build123d/build_part.py @@ -129,7 +129,7 @@ class BuildPart(Builder): for face in new_faces: logger.debug( "Adding Face to pending_faces at %s", - face.location(), + face.location, ) self.pending_faces.append(face) self.pending_face_planes.append(face_plane) @@ -138,7 +138,7 @@ class BuildPart(Builder): for edge in new_edges: logger.debug( "Adding Edge to pending_edges at %s", - edge.location(), + edge.location, ) self.pending_edges.append(edge) @@ -469,7 +469,7 @@ class Extrude(Compound): trim_faces = [ f for f in trim_faces - if f.normal_at(f.center()).dot(plane.z_dir) != 0.0 + if f.normal_at(f.center).dot(plane.z_dir) != 0.0 ] # Group the faces into surfaces trim_shells = Shell.make_shell(trim_faces).shells() @@ -480,7 +480,7 @@ class Extrude(Compound): face_directions = Vector(0, 0, 0) for trim_face in trim_shell.faces(): face_directions = face_directions + trim_face.normal_at( - trim_face.center() + trim_face.center ) surface_dirs.append(face_directions.get_angle(plane.z_dir)) if until == Until.NEXT: @@ -501,7 +501,7 @@ class Extrude(Compound): for trim_object, trim_face in zip(trim_objects, trim_faces): if not trim_object.is_valid(): warn( - message=f"Part face with area {trim_face.area()} " + message=f"Part face with area {trim_face.area} " f"creates an invalid extrusion", category=Warning, ) @@ -656,7 +656,7 @@ class Revolve(Compound): for profile in profiles: # axis origin must be on the same plane as profile face_occt_pln = gp_Pln( - profile.center().to_pnt(), profile.normal_at(profile.center()).to_dir() + profile.center.to_pnt(), profile.normal_at(profile.center).to_dir() ) if not face_occt_pln.Contains(axis.position.to_pnt(), 1e-5): raise ValueError( diff --git a/src/build123d/direct_api.py b/src/build123d/direct_api.py index dc9e807..e4453b7 100644 --- a/src/build123d/direct_api.py +++ b/src/build123d/direct_api.py @@ -515,6 +515,7 @@ class Vector: def to_tuple(self) -> tuple[float, float, float]: return (self.X, self.Y, self.Z) + @property def length(self) -> float: return self.wrapped.Magnitude() @@ -568,6 +569,7 @@ class Vector: def normalized(self) -> Vector: return Vector(self.wrapped.Normalized()) + @property def center(self) -> Vector: """center @@ -616,7 +618,7 @@ class Vector: Vector: Returns the projected vector. """ - line_length = line.length() + line_length = line.length return line * (self.dot(line) / (line_length * line_length)) @@ -638,13 +640,13 @@ class Vector: base = plane._origin normal = plane.z_dir - return self - normal * (((self - base).dot(normal)) / normal.length() ** 2) + return self - normal * (((self - base).dot(normal)) / normal.length**2) def __neg__(self) -> Vector: return self * -1 def __abs__(self) -> float: - return self.length() + return self.length def __repr__(self) -> str: return "Vector: " + str((self.X, self.Y, self.Z)) @@ -904,8 +906,9 @@ class BoundBox: self.zmax = z_max self.zlen = z_max - z_min + @property def center(self) -> Vector: - """center""" + """Return center of the bounding box""" return Vector( (self.xmax + self.xmin) / 2, (self.ymax + self.ymin) / 2, @@ -1494,31 +1497,24 @@ class Mixin1D: return return_value - def center(self, center_of: CenterOf = CenterOf.GEOMETRY) -> Vector: - """Center of object + @property + def center(self) -> Vector: + """Return center along Edge/Wire""" + return self.position_at(0.5) - Return the center based on center_of - - Args: - center_of (CenterOf, optional): centering option. Defaults to CenterOf.GEOMETRY. - - Returns: - Vector: center - """ - if center_of == CenterOf.GEOMETRY: - middle = self.position_at(0.5) - elif center_of == CenterOf.MASS: - properties = GProp_GProps() - BRepGProp.LinearProperties_s(self.wrapped, properties) - middle = Vector(properties.CentreOfMass()) - elif center_of == CenterOf.BOUNDING_BOX: - middle = self.bounding_box().center() - return middle + @property + def center_of_mass(self) -> Vector: + """Return center of mass - which may not be on the Edge/Wire""" + properties = GProp_GProps() + BRepGProp.LinearProperties_s(self.wrapped, properties) + return Vector(properties.CentreOfMass()) + @property def length(self) -> float: return GCPnts_AbscissaPoint.Length_s(self._geom_adaptor()) + @property def radius(self) -> float: """Calculate the radius. @@ -1927,6 +1923,16 @@ class Shape: # Helps identify this solid through the use of an ID self.label: str = "" + @property + def location(self) -> Location: + """Get this Shape's Location""" + return Location(self.wrapped.Location()) + + @location.setter + def location(self, value: Location): + """Set Shape's Location to value""" + self.wrapped.Location(value) + @property def position(self) -> Vector: """Get the position component of this Shape's Location""" @@ -2272,8 +2278,7 @@ class Shape: if center_of == CenterOf.MASS: total_mass = sum(Shape.compute_mass(o) for o in objects) weighted_centers = [ - o.center(center_of=CenterOf.MASS).multiply(Shape.compute_mass(o)) - for o in objects + o.center_of_mass.multiply(Shape.compute_mass(o)) for o in objects ] sum_wc = weighted_centers[0] @@ -2285,7 +2290,7 @@ class Shape: weighted_centers = [] for o in objects: - weighted_centers.append(BoundBox._from_topo_ds(o.wrapped).center()) + weighted_centers.append(o.bounding_box().center) sum_wc = weighted_centers[0] for wc in weighted_centers[1:]: @@ -2447,6 +2452,7 @@ class Shape: return ShapeList([Solid(i) for i in self._entities(Solid.__name__)]) + @property def area(self) -> float: """ @@ -2461,6 +2467,7 @@ class Shape: return properties.Mass() + @property def volume(self) -> float: """ @@ -2593,9 +2600,6 @@ class Shape: return new_shape - def location(self) -> Location: - return Location(self.wrapped.Location()) - def locate(self, loc: Location) -> Shape: """Apply a location in absolute sense to self @@ -3112,8 +3116,8 @@ class Shape: """ - path_length = path.length() - shape_center = self.center() + path_length = path.length + shape_center = self.center # Create text faces text_faces = Compound.make_2d_text( @@ -3150,7 +3154,7 @@ class Shape: projected_text = projected_faces else: projected_text = [ - f.thicken(depth, f.center() - shape_center) for f in projected_faces + f.thicken(depth, f.center - shape_center) for f in projected_faces ] logging.debug(f"finished projecting text sting '{txt}'") @@ -3279,7 +3283,7 @@ class ShapeList(list[T]): result = list( filter( lambda o: filter_by.is_parallel( - Axis(o.center(), o.normal_at(None)), tolerance + Axis(o.center, o.normal_at(None)), tolerance ), planar_faces, ) @@ -3335,28 +3339,28 @@ class ShapeList(list[T]): if inclusive == (True, True): objects = filter( lambda o: minimum - <= axis.to_plane().to_local_coords(o).center().Z + <= axis.to_plane().to_local_coords(o).center.Z <= maximum, self, ) elif inclusive == (True, False): objects = filter( lambda o: minimum - <= axis.to_plane().to_local_coords(o).center().Z + <= axis.to_plane().to_local_coords(o).center.Z < maximum, self, ) elif inclusive == (False, True): objects = filter( lambda o: minimum - < axis.to_plane().to_local_coords(o).center().Z + < axis.to_plane().to_local_coords(o).center.Z <= maximum, self, ) elif inclusive == (False, False): objects = filter( lambda o: minimum - < axis.to_plane().to_local_coords(o).center().Z + < axis.to_plane().to_local_coords(o).center.Z < maximum, self, ) @@ -3382,23 +3386,23 @@ class ShapeList(list[T]): groups = {} for obj in self: if isinstance(group_by, Axis): - key = group_by.to_plane().to_local_coords(obj).center().Z + key = group_by.to_plane().to_local_coords(obj).center.Z elif isinstance(group_by, SortBy): if group_by == SortBy.LENGTH: - key = obj.length() + key = obj.length elif group_by == SortBy.RADIUS: - key = obj.radius() + key = obj.radius elif group_by == SortBy.DISTANCE: - key = obj.center().length() + key = obj.center.length elif group_by == SortBy.AREA: - key = obj.area() + key = obj.area elif group_by == SortBy.VOLUME: - key = obj.volume() + key = obj.volume else: raise ValueError(f"Group by {type(group_by)} unsupported") @@ -3431,7 +3435,7 @@ class ShapeList(list[T]): if isinstance(sort_by, Axis): objects = sorted( self, - key=lambda o: sort_by.to_plane().to_local_coords(o).center().Z, + key=lambda o: sort_by.to_plane().to_local_coords(o).center.Z, reverse=reverse, ) @@ -3439,31 +3443,31 @@ class ShapeList(list[T]): if sort_by == SortBy.LENGTH: objects = sorted( self, - key=lambda obj: obj.length(), + key=lambda obj: obj.length, reverse=reverse, ) elif sort_by == SortBy.RADIUS: objects = sorted( self, - key=lambda obj: obj.radius(), + key=lambda obj: obj.radius, reverse=reverse, ) elif sort_by == SortBy.DISTANCE: objects = sorted( self, - key=lambda obj: obj.center().length(), + key=lambda obj: obj.center.length, reverse=reverse, ) elif sort_by == SortBy.AREA: objects = sorted( self, - key=lambda obj: obj.area(), + key=lambda obj: obj.area, reverse=reverse, ) elif sort_by == SortBy.VOLUME: objects = sorted( self, - key=lambda obj: obj.volume(), + key=lambda obj: obj.volume, reverse=reverse, ) @@ -3639,7 +3643,7 @@ class Plane: ValueError: if the specified x_dir is not orthogonal to the provided normal """ self.z_dir = Vector(z_dir) - if self.z_dir.length() == 0.0: + if self.z_dir.length == 0.0: raise ValueError("normal should be non null") self.z_dir = self.z_dir.normalized() @@ -3648,7 +3652,7 @@ class Plane: ax3 = gp_Ax3(Vector(origin).to_pnt(), Vector(z_dir).to_dir()) self.x_dir = Vector(ax3.XDirection()).normalized() else: - if Vector(x_dir).length() == 0.0: + if Vector(x_dir).length == 0.0: raise ValueError("x_dir should be non null") self.x_dir = Vector(x_dir).normalized() self.y_dir = self.z_dir.cross(self.x_dir).normalized() @@ -4072,7 +4076,7 @@ class Compound(Shape, Mixin3D): text_flat = text_flat.translate(t) if text_path is not None: - path_length = text_path.length() + path_length = text_path.length text_flat = Compound.make_compound( [position_face(f) for f in text_flat.faces()] ) @@ -4209,6 +4213,7 @@ class Edge(Shape, Mixin1D): """Edge as Wire""" return Wire.make_wire([self]) + @property def arc_center(self) -> Vector: """center of an underlying circle or ellipse geometry.""" @@ -4626,33 +4631,29 @@ class Face(Shape): return Vector(vn) - def center(self, center_of: CenterOf = CenterOf.GEOMETRY) -> Vector: - """Center of object + @property + def center(self) -> Vector: + """Center of geometry""" + return self.center_of_geometry - Return the center based on center_of + @property + def center_of_mass(self) -> Vector: + """Center of mass""" + properties = GProp_GProps() + BRepGProp.SurfaceProperties_s(self.wrapped, properties) + return Vector(properties.CentreOfMass()) - Args: - center_of (CenterOf, optional): centering option. Defaults to CenterOf.GEOMETRY. + @property + def center_of_geometry(self) -> Vector: + """Center of geometry""" + u0, u1, v0, v1 = self._uv_bounds() + u = 0.5 * (u0 + u1) + v = 0.5 * (v0 + v1) - Returns: - Vector: center - """ - if center_of == CenterOf.MASS: - properties = GProp_GProps() - BRepGProp.LinearProperties_s(self.wrapped, properties) - middle = Vector(properties.CentreOfMass()) - elif center_of == CenterOf.GEOMETRY: - u0, u1, v0, v1 = self._uv_bounds() - u = 0.5 * (u0 + u1) - v = 0.5 * (v0 + v1) - - p = gp_Pnt() - vn = gp_Vec() - BRepGProp_Face(self.wrapped).Normal(u, v, p, vn) - middle = Vector(p) - elif center_of == CenterOf.BOUNDING_BOX: - middle = self.bounding_box().center() - return middle + p = gp_Pnt() + vn = gp_Vec() + BRepGProp_Face(self.wrapped).Normal(u, v, p, vn) + return Vector(p) def outer_wire(self) -> Wire: @@ -5011,7 +5012,7 @@ class Face(Shape): # Check to see if the normal needs to be flipped adjusted_depth = depth if direction is not None: - face_center = self.center() + face_center = self.center face_normal = self.normal_at(face_center).normalized() if face_normal.dot(Vector(direction).normalized()) < 0: adjusted_depth = -depth @@ -5162,7 +5163,7 @@ class Face(Shape): # Not sure if it's always a good idea to add an internal central point so the next # two lines of code can be easily removed without impacting the rest if not internal_face_points: - internal_face_points = [planar_outer_wire.center()] + internal_face_points = [planar_outer_wire.center] if not internal_face_points: projected_grid_points = [] @@ -5297,30 +5298,21 @@ class Solid(Shape, Mixin3D): return True return False - def center(self, center_of: CenterOf = CenterOf.MASS) -> Vector: - """Return center of object + @property + def center(self) -> Vector: + """Return center of mass""" + return self.center_of_mass - Find center of object - - Args: - center_of (CenterOf, optional): center option. Defaults to CenterOf.GEOMETRY. - - Returns: - Vector: center - """ - if center_of == CenterOf.GEOMETRY: - raise ValueError("Center of GEOMETRY is not supported for this object") - if center_of == CenterOf.MASS: - properties = GProp_GProps() - calc_function = shape_properties_LUT[shapetype(self.wrapped)] - if calc_function: - calc_function(self.wrapped, properties) - middle = Vector(properties.CentreOfMass()) - else: - raise NotImplementedError - elif center_of == CenterOf.BOUNDING_BOX: - middle = self.bounding_box(tolerance=1e-6).center - return middle + @property + def center_of_mass(self) -> Vector: + """Return center of mass""" + properties = GProp_GProps() + calc_function = shape_properties_LUT[shapetype(self.wrapped)] + if calc_function: + calc_function(self.wrapped, properties) + return Vector(properties.CentreOfMass()) + else: + raise NotImplementedError @classmethod def make_solid(cls, shell: Shell) -> Solid: @@ -5618,7 +5610,7 @@ class Solid(Shape, Mixin3D): face_normal = section_face.normal_at() d = 1 if normal.get_angle(face_normal) < 90 else -1 prism_builder = LocOpe_DPrism( - section_face.wrapped, d * normal.length(), d * taper * DEG2RAD + section_face.wrapped, d * normal.length, d * taper * DEG2RAD ) return cls(prism_builder.Shape()) @@ -5686,10 +5678,10 @@ class Solid(Shape, Mixin3D): )[0].wrapped # make an auxiliary spine - pitch = 360.0 / angle * normal.length() + pitch = 360.0 / angle * normal.length radius = 1 aux_spine_w = Wire.make_helix( - pitch, normal.length(), radius, center=center, normal=normal + pitch, normal.length, radius, center=center, normal=normal ).wrapped # extrude the outer wire @@ -5925,6 +5917,7 @@ class Vertex(Shape): geom_point = BRep_Tool.Pnt_s(self.wrapped) return (geom_point.X(), geom_point.Y(), geom_point.Z()) + @property def center(self) -> Vector: """The center of a vertex is itself!""" return Vector(self.to_tuple()) @@ -6094,8 +6087,8 @@ class Wire(Shape, Mixin1D): sorted_edges = sorted( unplaced_edges, key=lambda e: min( - (target_point - e.position_at(0)).length(), - (target_point - e.position_at(1)).length(), + (target_point - e.position_at(0)).length, + (target_point - e.position_at(1)).length, ), ) return sorted_edges[0] @@ -6206,7 +6199,7 @@ class Wire(Shape, Mixin1D): Wire: an irregular polygon """ vertices = [Vector(v) for v in vertices] - if (vertices[0] - vertices[-1]).length() > TOLERANCE and close: + if (vertices[0] - vertices[-1]).length > TOLERANCE and close: vertices.append(vertices[0]) wire_builder = BRepBuilderAPI_MakePolygon() @@ -6460,9 +6453,9 @@ class Wire(Shape, Mixin1D): # by distance from the original planar wire if len(output_wires) > 1: output_wires_distances = [] - planar_wire_center = self.center() + planar_wire_center = self.center for output_wire in output_wires: - output_wire_center = output_wire.center() + output_wire_center = output_wire.center if direction_vector is not None: output_wire_direction = ( output_wire_center - planar_wire_center @@ -6471,12 +6464,12 @@ class Wire(Shape, Mixin1D): output_wires_distances.append( ( output_wire, - (output_wire_center - planar_wire_center).length(), + (output_wire_center - planar_wire_center).length, ) ) else: output_wires_distances.append( - (output_wire, (output_wire_center - center_point).length()) + (output_wire, (output_wire_center - center_point).length) ) output_wires_distances.sort(key=lambda x: x[1]) diff --git a/src/build123d/hull.py b/src/build123d/hull.py index 64e2ddc..7854d65 100644 --- a/src/build123d/hull.py +++ b/src/build123d/hull.py @@ -98,8 +98,8 @@ def convert_and_validate(edges: Iterable[Edge]) -> Tuple[List[Arc], List[Point]] points.update((Point(p1.X, p1.Y), Point(p2.X, p2.Y))) elif gt == "CIRCLE": - c = e.arc_center() - r = e.radius() + c = e.arc_center + r = e.radius a1, a2 = e._bounds() arcs.add(Arc(Point(c.X, c.Y), r, a1, a2)) diff --git a/tests/build_common_tests.py b/tests/build_common_tests.py index 2efdde9..0eef2b9 100644 --- a/tests/build_common_tests.py +++ b/tests/build_common_tests.py @@ -108,14 +108,14 @@ class TestShapeList(unittest.TestCase): self.assertTrue(isinstance(edges, ShapeList)) self.assertEqual(len(edges), 4) if axis == Axis.X: - self.assertLessEqual(faces[0].center().x, faces[1].center().x) - self.assertLessEqual(edges[0].center().x, edges[-1].center().x) + self.assertLessEqual(faces[0].center.x, faces[1].center.x) + self.assertLessEqual(edges[0].center.x, edges[-1].center.x) elif axis == Axis.Y: - self.assertLessEqual(faces[0].center().y, faces[1].center().y) - self.assertLessEqual(edges[0].center().y, edges[-1].center().y) + self.assertLessEqual(faces[0].center.y, faces[1].center.y) + self.assertLessEqual(edges[0].center.y, edges[-1].center.y) elif axis == Axis.Z: - self.assertLessEqual(faces[0].center().z, faces[1].center().z) - self.assertLessEqual(edges[0].center().z, edges[-1].center().z) + self.assertLessEqual(faces[0].center.z, faces[1].center.z) + self.assertLessEqual(edges[0].center.z, edges[-1].center.z) # test filter by type with BuildPart() as test: @@ -147,26 +147,14 @@ class TestShapeList(unittest.TestCase): self.assertTrue(isinstance(edges, ShapeList)) self.assertEqual(len(edges), 4 * sum(inclusive) + 4) if axis == Axis.X: - self.assertLessEqual( - faces[0].center().x, faces[-1].center().x - ) - self.assertLessEqual( - edges[0].center().x, edges[-1].center().x - ) + self.assertLessEqual(faces[0].center.x, faces[-1].center.x) + self.assertLessEqual(edges[0].center.x, edges[-1].center.x) elif axis == Axis.Y: - self.assertLessEqual( - faces[0].center().y, faces[-1].center().y - ) - self.assertLessEqual( - edges[0].center().y, edges[-1].center().y - ) + self.assertLessEqual(faces[0].center.y, faces[-1].center.y) + self.assertLessEqual(edges[0].center.y, edges[-1].center.y) elif axis == Axis.Z: - self.assertLessEqual( - faces[0].center().z, faces[-1].center().z - ) - self.assertLessEqual( - edges[0].center().z, edges[-1].center().z - ) + self.assertLessEqual(faces[0].center.z, faces[-1].center.z) + self.assertLessEqual(edges[0].center.z, edges[-1].center.z) def test_sort_by_type(self): """test sorting by different attributes""" @@ -174,22 +162,22 @@ class TestShapeList(unittest.TestCase): with BuildPart() as test: Wedge(1, 1, 1, 0, 0, 0.5, 0.5) faces = test.faces().sort_by(SortBy.AREA) - self.assertEqual(faces[0].area(), 0.25) - self.assertEqual(faces[-1].area(), 1) + self.assertEqual(faces[0].area, 0.25) + self.assertEqual(faces[-1].area, 1) with self.subTest(sort_by=SortBy.LENGTH): with BuildPart() as test: Wedge(1, 1, 1, 0, 0, 0.5, 0.5) edges = test.edges().sort_by(SortBy.LENGTH) - self.assertEqual(edges[0].length(), 0.5) - self.assertAlmostEqual(edges[-1].length(), 1.2247448713915892, 7) + self.assertEqual(edges[0].length, 0.5) + self.assertAlmostEqual(edges[-1].length, 1.2247448713915892, 7) with self.subTest(sort_by=SortBy.DISTANCE): with BuildPart() as test: Box(1, 1, 1, centered=(False, True, True)) faces = test.faces().sort_by(SortBy.DISTANCE) - self.assertAlmostEqual(faces[0].center().length(), 0, 7) - self.assertAlmostEqual(faces[-1].center().length(), 1, 7) + self.assertAlmostEqual(faces[0].center.length, 0, 7) + self.assertAlmostEqual(faces[-1].center.length, 1, 7) with self.subTest(sort_by=SortBy.VOLUME): with BuildPart() as test: @@ -197,36 +185,36 @@ class TestShapeList(unittest.TestCase): with Locations((0, 0, 10)): Box(2, 2, 2) solids = test.solids().sort_by(SortBy.VOLUME) - self.assertAlmostEqual(solids[0].volume(), 1, 7) - self.assertAlmostEqual(solids[-1].volume(), 8, 7) + self.assertAlmostEqual(solids[0].volume, 1, 7) + self.assertAlmostEqual(solids[-1].volume, 8, 7) with self.subTest(sort_by=SortBy.RADIUS): with BuildPart() as test: Cone(1, 0.5, 2) edges = test.edges().filter_by(GeomType.CIRCLE).sort_by(SortBy.RADIUS) - self.assertEqual(edges[0].radius(), 0.5) - self.assertEqual(edges[-1].radius(), 1) + self.assertEqual(edges[0].radius, 0.5) + self.assertEqual(edges[-1].radius, 1) with self.subTest(sort_by="X"): with BuildPart() as test: Box(1, 1, 1) edges = test.edges() > Axis.X - self.assertEqual(edges[0].center().X, -0.5) - self.assertEqual(edges[-1].center().X, 0.5) + self.assertEqual(edges[0].center.X, -0.5) + self.assertEqual(edges[-1].center.X, 0.5) with self.subTest(sort_by="Y"): with BuildPart() as test: Box(1, 1, 1) edges = test.edges() > Axis.Y - self.assertEqual(edges[0].center().Y, -0.5) - self.assertEqual(edges[-1].center().Y, 0.5) + self.assertEqual(edges[0].center.Y, -0.5) + self.assertEqual(edges[-1].center.Y, 0.5) with self.subTest(sort_by="Z"): with BuildPart() as test: Box(1, 1, 1) edges = test.edges() > Axis.Z - self.assertEqual(edges[0].center().Z, -0.5) - self.assertEqual(edges[-1].center().Z, 0.5) + self.assertEqual(edges[0].center.Z, -0.5) + self.assertEqual(edges[-1].center.Z, 0.5) def test_vertices(self): with BuildPart() as test: diff --git a/tests/build_generic_tests.py b/tests/build_generic_tests.py index 11e5f70..c865b8b 100644 --- a/tests/build_generic_tests.py +++ b/tests/build_generic_tests.py @@ -79,13 +79,13 @@ class AddTests(unittest.TestCase): def test_add_to_sketch(self): with BuildSketch() as test: 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): # Add Solid with BuildPart() as test: Add(Solid.make_box(10, 10, 10)) - self.assertAlmostEqual(test.part.volume(), 1000, 5) + self.assertAlmostEqual(test.part.volume, 1000, 5) # Add Compound with BuildPart() as test: Add( @@ -96,7 +96,7 @@ class AddTests(unittest.TestCase): ] ) ) - self.assertEqual(test.part.volume(), 1125, 5) + self.assertEqual(test.part.volume, 1125, 5) # Add Wire with BuildLine() as wire: Polyline((0, 0, 0), (1, 1, 1), (2, 0, 0), (3, 1, 1)) @@ -128,7 +128,7 @@ class TestOffset(unittest.TestCase): Line(l @ 1, (1, 1)) Offset(amount=1) MakeFace() - self.assertAlmostEqual(test.sketch.area(), pi * 1.25 + 3, 5) + self.assertAlmostEqual(test.sketch.area, pi * 1.25 + 3, 5) def test_line_offset(self): with BuildSketch() as test: @@ -137,13 +137,13 @@ class TestOffset(unittest.TestCase): Line(l @ 1, (1, 1)) Offset(*line.line.edges(), amount=1) MakeFace() - self.assertAlmostEqual(test.sketch.area(), pi * 1.25 + 3, 5) + self.assertAlmostEqual(test.sketch.area, pi * 1.25 + 3, 5) def test_face_offset(self): with BuildSketch() as test: Rectangle(1, 1) Offset(amount=1, kind=Kind.INTERSECTION) - self.assertAlmostEqual(test.sketch.area(), 9, 5) + self.assertAlmostEqual(test.sketch.area, 9, 5) def test_box_offset(self): with BuildPart() as test: @@ -152,7 +152,7 @@ class TestOffset(unittest.TestCase): amount=1, kind=Kind.INTERSECTION, ) - self.assertAlmostEqual(test.part.volume(), 3**3 - 1**3, 5) + self.assertAlmostEqual(test.part.volume, 3**3 - 1**3, 5) def test_box_offset_with_opening(self): with BuildPart() as test: @@ -162,7 +162,7 @@ class TestOffset(unittest.TestCase): openings=test.faces() >> Axis.Z, kind=Kind.INTERSECTION, ) - self.assertAlmostEqual(test.part.volume(), 10**3 - 8**2 * 9, 5) + self.assertAlmostEqual(test.part.volume, 10**3 - 8**2 * 9, 5) class BoundingBoxTests(unittest.TestCase): @@ -175,7 +175,7 @@ class BoundingBoxTests(unittest.TestCase): ears = (bb.vertices() > Axis.Y)[:-2] with Locations(*ears): Circle(7) - self.assertAlmostEqual(mickey.sketch.area(), 586.1521145312807, 5) + self.assertAlmostEqual(mickey.sketch.area, 586.1521145312807, 5) """Test Vertices""" with BuildSketch() as test: Rectangle(10, 10) @@ -186,11 +186,11 @@ class BoundingBoxTests(unittest.TestCase): with BuildPart() as test: Sphere(1) BoundingBox(*test.solids()) - self.assertAlmostEqual(test.part.volume(), 8, 5) + self.assertAlmostEqual(test.part.volume, 8, 5) with BuildPart() as test: Sphere(1) BoundingBox(*test.vertices()) - self.assertAlmostEqual(test.part.volume(), (4 / 3) * pi, 5) + self.assertAlmostEqual(test.part.volume, (4 / 3) * pi, 5) def test_errors(self): with self.assertRaises(RuntimeError): @@ -203,13 +203,13 @@ class ChamferTests(unittest.TestCase): with BuildPart() as test: Box(10, 10, 10) Chamfer(*test.edges(), length=1) - self.assertLess(test.part.volume(), 1000) + self.assertLess(test.part.volume, 1000) def test_sketch_chamfer(self): with BuildSketch() as test: Rectangle(10, 10) Chamfer(*test.vertices(), length=1) - self.assertAlmostEqual(test.sketch.area(), 100 - 4 * 0.5, 5) + self.assertAlmostEqual(test.sketch.area, 100 - 4 * 0.5, 5) with BuildSketch() as test: with Locations((-10, 0), (10, 0)): @@ -218,7 +218,7 @@ class ChamferTests(unittest.TestCase): *test.vertices().filter_by_position(Axis.X, minimum=0, maximum=20), length=1 ) - self.assertAlmostEqual(test.sketch.area(), 200 - 4 * 0.5, 5) + self.assertAlmostEqual(test.sketch.area, 200 - 4 * 0.5, 5) def test_errors(self): with self.assertRaises(RuntimeError): @@ -231,13 +231,13 @@ class FilletTests(unittest.TestCase): with BuildPart() as test: Box(10, 10, 10) Fillet(*test.edges(), radius=1) - self.assertLess(test.part.volume(), 1000) + self.assertLess(test.part.volume, 1000) def test_sketch_chamfer(self): with BuildSketch() as test: Rectangle(10, 10) Fillet(*test.vertices(), radius=1) - self.assertAlmostEqual(test.sketch.area(), 100 - 4 + pi, 5) + self.assertAlmostEqual(test.sketch.area, 100 - 4 + pi, 5) with BuildSketch() as test: with Locations((-10, 0), (10, 0)): @@ -246,7 +246,7 @@ class FilletTests(unittest.TestCase): *test.vertices().filter_by_position(Axis.X, minimum=0, maximum=20), radius=1 ) - self.assertAlmostEqual(test.sketch.area(), 200 - 4 + pi, 5) + self.assertAlmostEqual(test.sketch.area, 200 - 4 + pi, 5) def test_errors(self): with self.assertRaises(RuntimeError): @@ -260,7 +260,7 @@ class HexArrayTests(unittest.TestCase): Rectangle(70, 70) with HexLocations(20, 4, 3, centered=(True, True)): Circle(5, mode=Mode.SUBTRACT) - self.assertAlmostEqual(test.sketch.area(), 70**2 - 12 * 25 * pi, 5) + self.assertAlmostEqual(test.sketch.area, 70**2 - 12 * 25 * pi, 5) def test_error(self): with self.assertRaises(ValueError): @@ -329,25 +329,25 @@ class ScaleTests(unittest.TestCase): with BuildLine() as test: Line((0, 0), (1, 0)) Scale(by=2, mode=Mode.REPLACE) - self.assertAlmostEqual(test.edges()[0].length(), 2.0, 5) + self.assertAlmostEqual(test.edges()[0].length, 2.0, 5) def test_sketch(self): with BuildSketch() as test: Rectangle(1, 1) Scale(by=2, mode=Mode.REPLACE) - self.assertAlmostEqual(test.sketch.area(), 4.0, 5) + self.assertAlmostEqual(test.sketch.area, 4.0, 5) def test_part(self): with BuildPart() as test: Box(1, 1, 1) Scale(by=(2, 2, 2), mode=Mode.REPLACE) - self.assertAlmostEqual(test.part.volume(), 8.0, 5) + self.assertAlmostEqual(test.part.volume, 8.0, 5) def test_external_object(self): line = Edge.make_line((0, 0), (1, 0)) with BuildLine() as test: Scale(line, by=2) - self.assertAlmostEqual(test.edges()[0].length(), 2.0, 5) + self.assertAlmostEqual(test.edges()[0].length, 2.0, 5) def test_error_checking(self): with self.assertRaises(ValueError): diff --git a/tests/build_line_tests.py b/tests/build_line_tests.py index 240caa6..ad13d50 100644 --- a/tests/build_line_tests.py +++ b/tests/build_line_tests.py @@ -77,7 +77,7 @@ class BuildLineTests(unittest.TestCase): TangentArc(l6 @ 1, l7 @ 0, tangent=l6 % 1) Mirror(*outline.edges(), about=Plane.YZ) MakeFace(*leaf.pending_edges) - self.assertAlmostEqual(leaf.sketch.area(), 0.2741600685288115, 5) + self.assertAlmostEqual(leaf.sketch.area, 0.2741600685288115, 5) def test_three_d(self): """Test 3D lines with a helix""" @@ -98,7 +98,7 @@ class BuildLineTests(unittest.TestCase): powerup @ 0, tangents=(screw % 1, powerup % 0), ) - self.assertAlmostEqual(roller_coaster.wires()[0].length(), 678.983628932414, 5) + self.assertAlmostEqual(roller_coaster.wires()[0].length, 678.983628932414, 5) def test_polar_line(self): """Test 2D and 3D polar lines""" @@ -131,16 +131,16 @@ class BuildLineTests(unittest.TestCase): with BuildLine() as test: Polyline((0, 0), (1, 0), (1, 1), (0, 1), close=True) self.assertAlmostEqual( - (test.edges()[0] @ 0 - test.edges()[-1] @ 1).length(), 0, 5 + (test.edges()[0] @ 0 - test.edges()[-1] @ 1).length, 0, 5 ) self.assertEqual(len(test.edges()), 4) - self.assertAlmostEqual(test.wires()[0].length(), 4) + self.assertAlmostEqual(test.wires()[0].length, 4) def test_wires_select_last(self): with BuildLine() as test: Line((0, 0), (0, 1)) Polyline((1, 0), (1, 1), (0, 1), (0, 0)) - self.assertAlmostEqual(test.wires(Select.LAST)[0].length(), 3, 5) + self.assertAlmostEqual(test.wires(Select.LAST)[0].length, 3, 5) def test_error_conditions(self): """Test error handling""" diff --git a/tests/build_part_tests.py b/tests/build_part_tests.py index 978c459..938f5b2 100644 --- a/tests/build_part_tests.py +++ b/tests/build_part_tests.py @@ -103,20 +103,20 @@ class BuildPartTests(unittest.TestCase): Box(20, 20, 20) Sphere(10, mode=Mode.SUBTRACT) self.assertTrue(isinstance(test._obj, Compound)) - self.assertAlmostEqual(test.part.volume(), 8000 - (4000 / 3) * pi, 5) + self.assertAlmostEqual(test.part.volume, 8000 - (4000 / 3) * pi, 5) def test_mode_intersect(self): """Note that a negative volume is created""" with BuildPart() as test: Box(20, 20, 20) Sphere(10, mode=Mode.INTERSECT) - self.assertAlmostEqual(abs(test.part.volume()), (4000 / 3) * pi, 5) + self.assertAlmostEqual(abs(test.part.volume), (4000 / 3) * pi, 5) def test_mode_replace(self): with BuildPart() as test: Box(10, 10, 10) Sphere(10, mode=Mode.REPLACE) - self.assertAlmostEqual(test.part.volume(), (4000 / 3) * pi, 5) + self.assertAlmostEqual(test.part.volume, (4000 / 3) * pi, 5) def test_add_pending_faces(self): with BuildPart() as test: @@ -168,34 +168,34 @@ class TestCounterBoreHole(unittest.TestCase): def test_fixed_depth(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): CounterBoreHole(2, 3, 1, 5) - self.assertAlmostEqual(test.part.volume(), 1000 - 4 * 4 * pi - 9 * pi, 5) + self.assertAlmostEqual(test.part.volume, 1000 - 4 * 4 * pi - 9 * pi, 5) def test_through_hole(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): CounterBoreHole(2, 3, 1) - self.assertAlmostEqual(test.part.volume(), 1000 - 4 * 9 * pi - 9 * pi, 5) + self.assertAlmostEqual(test.part.volume, 1000 - 4 * 9 * pi - 9 * pi, 5) class TestCounterSinkHole(unittest.TestCase): def test_fixed_depth(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): CounterSinkHole(2, 4, 5) - self.assertLess(test.part.volume(), 1000, 5) - self.assertGreater(test.part.volume(), 1000 - 16 * 5 * pi, 5) + self.assertLess(test.part.volume, 1000, 5) + self.assertGreater(test.part.volume, 1000 - 16 * 5 * pi, 5) def test_through_hole(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): CounterSinkHole(2, 4) - self.assertLess(test.part.volume(), 1000, 5) - self.assertGreater(test.part.volume(), 1000 - 16 * 10 * pi, 5) + self.assertLess(test.part.volume, 1000, 5) + self.assertGreater(test.part.volume, 1000 - 16 * 10 * pi, 5) class TestExtrude(unittest.TestCase): @@ -209,14 +209,14 @@ class TestExtrude(unittest.TestCase): with BuildSketch() as f: Rectangle(5, 5) Extrude(*f.sketch.faces(), amount=2.5, both=True) - self.assertAlmostEqual(test.part.volume(), 125, 5) + self.assertAlmostEqual(test.part.volume, 125, 5) def test_extrude_both(self): with BuildPart() as test: with BuildSketch(): Rectangle(5, 5) Extrude(amount=2.5, both=True) - self.assertAlmostEqual(test.part.volume(), 125, 5) + self.assertAlmostEqual(test.part.volume, 125, 5) # def test_extrude_until(self): # with BuildPart() as test: @@ -225,23 +225,23 @@ class TestExtrude(unittest.TestCase): # with BuildSketch(): # Rectangle(1, 1) # Extrude(until=Until.NEXT) - # self.assertAlmostEqual(test.part.volume(), 10**3 - 8**3 + 1**2 * 8, 5) + # self.assertAlmostEqual(test.part.volume, 10**3 - 8**3 + 1**2 * 8, 5) class TestHole(unittest.TestCase): def test_fixed_depth(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): Hole(2, 5) - self.assertAlmostEqual(test.part.volume(), 1000 - 4 * 5 * pi, 5) + self.assertAlmostEqual(test.part.volume, 1000 - 4 * 5 * pi, 5) def test_through_hole(self): with BuildPart() as test: Box(10, 10, 10) - with Locations(test.faces().filter_by(Axis.Z)[-1].center()): + with Locations(test.faces().filter_by(Axis.Z)[-1].center): Hole(2) - self.assertAlmostEqual(test.part.volume(), 1000 - 4 * 10 * pi, 5) + self.assertAlmostEqual(test.part.volume, 1000 - 4 * 10 * pi, 5) class TestLoft(unittest.TestCase): @@ -253,8 +253,8 @@ class TestLoft(unittest.TestCase): with BuildSketch(): Circle(10 * sin(i * pi / slice_count) + 5) Loft() - self.assertLess(test.part.volume(), 225 * pi * 30, 5) - self.assertGreater(test.part.volume(), 25 * pi * 30, 5) + self.assertLess(test.part.volume, 225 * pi * 30, 5) + self.assertGreater(test.part.volume, 25 * pi * 30, 5) sections = [ Face.make_from_wires( @@ -270,8 +270,8 @@ class TestLoft(unittest.TestCase): ] with BuildPart() as test: Loft(*sections) - self.assertLess(test.part.volume(), 225 * pi * 30, 5) - self.assertGreater(test.part.volume(), 25 * pi * 30, 5) + self.assertLess(test.part.volume, 225 * pi * 30, 5) + self.assertGreater(test.part.volume, 25 * pi * 30, 5) class TestRevolve(unittest.TestCase): @@ -299,8 +299,8 @@ class TestRevolve(unittest.TestCase): ) MakeFace() Revolve(axis=Axis.Y) - self.assertLess(test.part.volume(), 22**2 * pi * 50, 5) - self.assertGreater(test.part.volume(), 144 * pi * 50, 5) + self.assertLess(test.part.volume, 22**2 * pi * 50, 5) + self.assertGreater(test.part.volume, 144 * pi * 50, 5) def test_revolve_with_axis(self): with BuildPart() as test: @@ -312,8 +312,8 @@ class TestRevolve(unittest.TestCase): l4 = Line(l3 @ 1, l1 @ 0) MakeFace() Revolve(axis=Axis.X) - self.assertLess(test.part.volume(), 244 * pi * 20, 5) - self.assertGreater(test.part.volume(), 100 * pi * 20, 5) + self.assertLess(test.part.volume, 244 * pi * 20, 5) + self.assertGreater(test.part.volume, 100 * pi * 20, 5) def test_invalid_axis_origin(self): with BuildPart(): @@ -335,13 +335,13 @@ class TestSection(unittest.TestCase): with BuildPart() as test: Sphere(10) Section() - self.assertAlmostEqual(test.faces()[-1].area(), 100 * pi, 5) + self.assertAlmostEqual(test.faces()[-1].area, 100 * pi, 5) def test_custom_plane(self): with BuildPart() as test: Sphere(10) Section(Plane.XZ) - self.assertAlmostEqual(test.faces().filter_by(Axis.Y)[-1].area(), 100 * pi, 5) + self.assertAlmostEqual(test.faces().filter_by(Axis.Y)[-1].area, 100 * pi, 5) class TestSplit(unittest.TestCase): @@ -349,7 +349,7 @@ class TestSplit(unittest.TestCase): with BuildPart() as test: Sphere(10) Split(keep=Keep.TOP) - self.assertAlmostEqual(test.part.volume(), (2 / 3) * 1000 * pi, 5) + self.assertAlmostEqual(test.part.volume, (2 / 3) * 1000 * pi, 5) def test_split_both(self): with BuildPart() as test: @@ -361,7 +361,7 @@ class TestSplit(unittest.TestCase): with BuildPart() as test: Sphere(10) Split(bisect_by=Plane.YZ, keep=Keep.TOP) - self.assertAlmostEqual(test.part.volume(), (2 / 3) * 1000 * pi, 5) + self.assertAlmostEqual(test.part.volume, (2 / 3) * 1000 * pi, 5) class TestSweep(unittest.TestCase): @@ -372,7 +372,7 @@ class TestSweep(unittest.TestCase): with BuildSketch(): Rectangle(2, 2) Sweep() - self.assertAlmostEqual(test.part.volume(), 40, 5) + self.assertAlmostEqual(test.part.volume, 40, 5) def test_multi_section(self): segment_count = 6 @@ -401,7 +401,7 @@ class TestSweep(unittest.TestCase): Fillet(*section.vertices(), radius=0.2) # Create the handle by sweeping along the path Sweep(multisection=True) - self.assertAlmostEqual(handle.part.volume(), 54.11246334691092, 5) + self.assertAlmostEqual(handle.part.volume, 54.11246334691092, 5) def test_passed_parameters(self): with BuildLine() as path: @@ -410,14 +410,14 @@ class TestSweep(unittest.TestCase): Rectangle(2, 2) with BuildPart() as test: Sweep(*section.faces(), path=path.wires()[0]) - self.assertAlmostEqual(test.part.volume(), 40, 5) + self.assertAlmostEqual(test.part.volume, 40, 5) class TestTorus(unittest.TestCase): def test_simple_torus(self): with BuildPart() as test: Torus(100, 10) - self.assertAlmostEqual(test.part.volume(), pi * 100 * 2 * pi * 100, 5) + self.assertAlmostEqual(test.part.volume, pi * 100 * 2 * pi * 100, 5) if __name__ == "__main__": diff --git a/tests/build_sketch_tests.py b/tests/build_sketch_tests.py index dde65a6..4d338ed 100644 --- a/tests/build_sketch_tests.py +++ b/tests/build_sketch_tests.py @@ -85,13 +85,13 @@ class BuildSketchTests(unittest.TestCase): with BuildSketch() as test: Circle(10) Rectangle(10, 10, centered=(False, False), mode=Mode.INTERSECT) - self.assertAlmostEqual(test.sketch.area(), 25 * pi, 5) + self.assertAlmostEqual(test.sketch.area, 25 * pi, 5) def test_mode_replace(self): with BuildSketch() as test: Circle(10) Rectangle(10, 10, centered=(False, False), mode=Mode.REPLACE) - self.assertAlmostEqual(test.sketch.area(), 100, 5) + self.assertAlmostEqual(test.sketch.area, 100, 5) class BuildSketchExceptions(unittest.TestCase): @@ -117,7 +117,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(c.radius, 20) self.assertEqual(c.centered, (True, True)) self.assertEqual(c.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), pi * 20**2, 5) + self.assertAlmostEqual(test.sketch.area, pi * 20**2, 5) def test_ellipse(self): with BuildSketch() as test: @@ -127,7 +127,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(e.rotation, 0) self.assertEqual(e.centered, (True, True)) self.assertEqual(e.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), pi * 20 * 10, 5) + self.assertAlmostEqual(test.sketch.area, pi * 20 * 10, 5) def test_polygon(self): with BuildSketch() as test: @@ -136,7 +136,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(p.rotation, 0) self.assertEqual(p.centered, (True, True)) self.assertEqual(p.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), 0.5, 5) + self.assertAlmostEqual(test.sketch.area, 0.5, 5) def test_rectangle(self): with BuildSketch() as test: @@ -146,7 +146,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(r.rotation, 0) self.assertEqual(r.centered, (True, True)) self.assertEqual(r.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), 20 * 10, 5) + self.assertAlmostEqual(test.sketch.area, 20 * 10, 5) def test_regular_polygon(self): with BuildSketch() as test: @@ -156,7 +156,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(r.rotation, 0) self.assertEqual(r.centered, (True, True)) self.assertEqual(r.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), (3 * sqrt(3) / 2) * 2**2, 5) + self.assertAlmostEqual(test.sketch.area, (3 * sqrt(3) / 2) * 2**2, 5) def test_slot_arc(self): with BuildSketch() as test: @@ -167,7 +167,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(s.height, 1) self.assertEqual(s.rotation, 45) self.assertEqual(s.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), 6.186450426893698, 5) + self.assertAlmostEqual(test.sketch.area, 6.186450426893698, 5) def test_slot_center_point(self): with BuildSketch() as test: @@ -177,7 +177,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(s.height, 2) self.assertEqual(s.rotation, 0) self.assertEqual(s.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), pi + 4 * 2, 5) + self.assertAlmostEqual(test.sketch.area, pi + 4 * 2, 5) def test_slot_center_to_center(self): with BuildSketch() as test: @@ -186,7 +186,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(s.height, 2) self.assertEqual(s.rotation, 0) self.assertEqual(s.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), pi + 4 * 2, 5) + self.assertAlmostEqual(test.sketch.area, pi + 4 * 2, 5) def test_slot_overall(self): with BuildSketch() as test: @@ -195,7 +195,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(s.height, 2) self.assertEqual(s.rotation, 0) self.assertEqual(s.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), pi + 4 * 2, 5) + self.assertAlmostEqual(test.sketch.area, pi + 4 * 2, 5) def test_text(self): with BuildSketch() as test: @@ -222,7 +222,7 @@ class BuildSketchObjects(unittest.TestCase): self.assertEqual(t.right_side_angle, 63.434948823) self.assertEqual(t.rotation, 0) self.assertEqual(t.mode, Mode.ADD) - self.assertAlmostEqual(test.sketch.area(), 2 * (6 + 4) / 2, 5) + self.assertAlmostEqual(test.sketch.area, 2 * (6 + 4) / 2, 5) with self.assertRaises(ValueError): with BuildSketch() as test: @@ -233,7 +233,7 @@ class BuildSketchObjects(unittest.TestCase): with BuildSketch() as test: Circle(10) Offset(test.faces()[0], amount=1) - self.assertAlmostEqual(test.edges()[0].radius(), 11) + self.assertAlmostEqual(test.edges()[0].radius, 11) with self.assertRaises(RuntimeError): with BuildSketch() as test: Offset(Location(Vector()), amount=1) @@ -243,7 +243,7 @@ class BuildSketchObjects(unittest.TestCase): with BuildSketch() as test: with Locations((-10, 0), (10, 0)): Circle(1) - self.assertAlmostEqual(sum([f.area() for f in test.faces()]), 2 * pi, 5) + self.assertAlmostEqual(sum([f.area for f in test.faces()]), 2 * pi, 5) def test_hull(self): """Test hull from pending edges and passed edges""" @@ -253,14 +253,14 @@ class BuildSketchObjects(unittest.TestCase): CenterArc((1, 1.5), 0.5, 0, 360) Line((0.0, 2), (-1, 3.0)) MakeHull() - self.assertAlmostEqual(test.sketch.area(), 7.258175622249558, 5) + self.assertAlmostEqual(test.sketch.area, 7.258175622249558, 5) with BuildSketch() as test: with Locations((-10, 0)): Circle(10) with Locations((10, 0)): Circle(7) MakeHull(*test.edges()) - self.assertAlmostEqual(test.sketch.area(), 577.8808734698988, 5) + self.assertAlmostEqual(test.sketch.area, 577.8808734698988, 5) if __name__ == "__main__": diff --git a/tests/direct_api_tests.py b/tests/direct_api_tests.py index ce107c0..0cfbacb 100644 --- a/tests/direct_api_tests.py +++ b/tests/direct_api_tests.py @@ -99,15 +99,13 @@ class TestCadObjects(unittest.TestCase): def test_edge_wrapper_center(self): e = self._make_circle() - self.assertTupleAlmostEquals( - (1.0, 2.0, 3.0), e.center(center_of=CenterOf.MASS).to_tuple(), 3 - ) + self.assertTupleAlmostEquals((1.0, 2.0, 3.0), e.center_of_mass.to_tuple(), 3) def test_edge_wrapper_ellipse_center(self): e = self._make_ellipse() w = Wire.make_wire([e]) self.assertTupleAlmostEquals( - (1.0, 2.0, 3.0), Face.make_from_wires(w).center().to_tuple(), 3 + (1.0, 2.0, 3.0), Face.make_from_wires(w).center.to_tuple(), 3 ) def test_edge_wrapper_make_circle(self): @@ -255,7 +253,7 @@ class TestCadObjects(unittest.TestCase): # ) # self.assertEqual(4, len(s.val().solids())) - # self.assertTupleAlmostEquals((0.0, 0.0, 0.25), s.val().center().to_tuple(), 3) + # self.assertTupleAlmostEquals((0.0, 0.0, 0.25), s.val().center.to_tuple(), 3) def test_matrix_creation_and_access(self): def matrix_vals(m): @@ -398,9 +396,7 @@ class TestCadObjects(unittest.TestCase): e = Edge.make_circle(2, (1, 2, 3)) e2 = e.translate(Vector(0, 0, 1)) - self.assertTupleAlmostEquals( - (1.0, 2.0, 4.0), e2.center(center_of=CenterOf.MASS).to_tuple(), 3 - ) + self.assertTupleAlmostEquals((1.0, 2.0, 4.0), e2.center_of_mass.to_tuple(), 3) def test_vertices(self): e = Shape.cast(BRepBuilderAPI_MakeEdge(gp_Pnt(0, 0, 0), gp_Pnt(1, 1, 0)).Edge()) @@ -577,20 +573,20 @@ class TestCadObjects(unittest.TestCase): # get a radius from a simple circle e0 = Edge.make_circle(2.4) - self.assertAlmostEqual(e0.radius(), 2.4) + self.assertAlmostEqual(e0.radius, 2.4) # radius of an arc e1 = Edge.make_circle(1.8, pnt=(5, 6, 7), dir=(1, 1, 1), angle1=20, angle2=30) - self.assertAlmostEqual(e1.radius(), 1.8) + self.assertAlmostEqual(e1.radius, 1.8) # test value errors e2 = Edge.make_ellipse(10, 20) with self.assertRaises(ValueError): - e2.radius() + e2.radius # radius from a wire w0 = Wire.make_circle(10, Vector(1, 2, 3), (-1, 0, 1)) - self.assertAlmostEqual(w0.radius(), 10) + self.assertAlmostEqual(w0.radius, 10) # radius from a wire with multiple edges rad = 2.3 @@ -603,7 +599,7 @@ class TestCadObjects(unittest.TestCase): Edge.make_circle(rad, pnt, direction, 25, 230), ] ) - self.assertAlmostEqual(w1.radius(), rad) + self.assertAlmostEqual(w1.radius, rad) # test value error from wire w2 = Wire.make_polygon( @@ -614,7 +610,7 @@ class TestCadObjects(unittest.TestCase): ] ) with self.assertRaises(ValueError): - w2.radius() + w2.radius # (I think) the radius of a wire is the radius of it's first edge. # Since this is stated in the docstring better make sure. @@ -625,21 +621,21 @@ class TestCadObjects(unittest.TestCase): ] ) with self.assertRaises(ValueError): - no_rad.radius() + no_rad.radius yes_rad = Wire.make_wire( [ Edge.make_circle(1.0, angle1=90, angle2=270), Edge.make_line(Vector(0, -1, 0), Vector(0, 1, 0)), ] ) - self.assertAlmostEqual(yes_rad.radius(), 1.0) + self.assertAlmostEqual(yes_rad.radius, 1.0) many_rad = Wire.make_wire( [ Edge.make_circle(1.0, angle1=0, angle2=180), Edge.make_circle(3.0, pnt=Vector(2, 0, 0), angle1=180, angle2=359), ] ) - self.assertAlmostEqual(many_rad.radius(), 1.0) + self.assertAlmostEqual(many_rad.radius, 1.0) class TestVector(unittest.TestCase): @@ -698,7 +694,7 @@ class TestVector(unittest.TestCase): def test_center(self): v = Vector(1, 1, 1) - self.assertAlmostEqual(v, v.center()) + self.assertAlmostEqual(v, v.center) # def test_to_vertex(self): # """Verify conversion of Vector to Vertex""" @@ -773,7 +769,7 @@ class TestVector(unittest.TestCase): decimal_places, ) self.assertAlmostEqual( - vec.length() * math.cos(angle), vecLineProjection.length(), decimal_places + vec.length * math.cos(angle), vecLineProjection.length, decimal_places ) def test_vector_not_implemented(self): @@ -861,17 +857,13 @@ class TestMixin1D(unittest.TestCase): def test_center(self): c = Edge.make_circle(1, angle1=0, angle2=180) + self.assertTupleAlmostEquals(c.center.to_tuple(), (0, 1, 0), 5) self.assertTupleAlmostEquals( - c.center(center_of=CenterOf.GEOMETRY).to_tuple(), (0, 1, 0), 5 - ) - self.assertTupleAlmostEquals( - c.center(center_of=CenterOf.MASS).to_tuple(), + c.center_of_mass.to_tuple(), (0, 0.6366197723675814, 0), 5, ) - self.assertTupleAlmostEquals( - c.center(center_of=CenterOf.BOUNDING_BOX).to_tuple(), (0, 0.5, 0), 5 - ) + self.assertTupleAlmostEquals(c.bounding_box().center.to_tuple(), (0, 0.5, 0), 5) # TODO: Test after upgrade # def test_location_at(self): @@ -886,8 +878,8 @@ class TestMixin1D(unittest.TestCase): target = Face.make_rect(10, 10) source = Face.make_from_wires(Wire.make_circle(1, (0, 0, 1), (0, 0, 1))) shadow = source.project(target, d=(0, 0, -1)) - self.assertTupleAlmostEquals(shadow.center().to_tuple(), (0, 0, 0), 5) - self.assertAlmostEqual(shadow.area(), math.pi, 5) + self.assertTupleAlmostEquals(shadow.center.to_tuple(), (0, 0, 0), 5) + self.assertAlmostEqual(shadow.area, math.pi, 5) class TestMixin3D(unittest.TestCase): @@ -896,11 +888,11 @@ class TestMixin3D(unittest.TestCase): def test_chamfer(self): box = Solid.make_box(1, 1, 1) chamfer_box = box.chamfer(0.1, 0.2, box.edges().sort_by(Axis.Z)[-1:]) - self.assertAlmostEqual(chamfer_box.volume(), 1 - 0.01, 5) + self.assertAlmostEqual(chamfer_box.volume, 1 - 0.01, 5) def test_shell(self): shell_box = Solid.make_box(1, 1, 1).shell([], thickness=-0.1) - self.assertAlmostEqual(shell_box.volume(), 1 - 0.8**3, 5) + self.assertAlmostEqual(shell_box.volume, 1 - 0.8**3, 5) with self.assertRaises(ValueError): Solid.make_box(1, 1, 1).shell([], thickness=0.1, kind=Kind.TANGENT) @@ -914,7 +906,7 @@ class TestMixin3D(unittest.TestCase): None, [f], additive=False ) self.assertTrue(d.is_valid()) - self.assertAlmostEqual(d.volume(), 1 - 0.5**2, 5) + self.assertAlmostEqual(d.volume, 1 - 0.5**2, 5) # face with depth f = Face.make_rect(0.5, 0.5) @@ -922,7 +914,7 @@ class TestMixin3D(unittest.TestCase): None, [f], depth=0.5, thru_all=False, additive=False ) self.assertTrue(d.is_valid()) - self.assertAlmostEqual(d.volume(), 1 - 0.5**3, 5) + self.assertAlmostEqual(d.volume, 1 - 0.5**3, 5) # face until f = Face.make_rect(0.5, 0.5) @@ -931,7 +923,7 @@ class TestMixin3D(unittest.TestCase): None, [f], up_to_face=limit, thru_all=False, additive=False ) self.assertTrue(d.is_valid()) - self.assertAlmostEqual(d.volume(), 1 - 0.5**3, 5) + self.assertAlmostEqual(d.volume, 1 - 0.5**3, 5) # wire w = Face.make_rect(0.5, 0.5).outer_wire() @@ -939,7 +931,7 @@ class TestMixin3D(unittest.TestCase): None, [w], additive=False ) self.assertTrue(d.is_valid()) - self.assertAlmostEqual(d.volume(), 1 - 0.5**2, 5) + self.assertAlmostEqual(d.volume, 1 - 0.5**2, 5) class TestShape(unittest.TestCase): @@ -981,17 +973,17 @@ class TestShape(unittest.TestCase): self.assertEqual(Vertex().shape_type(), "Vertex") def test_scale(self): - self.assertAlmostEqual(Solid.make_box(1, 1, 1).scale(2).volume(), 2**3, 5) + self.assertAlmostEqual(Solid.make_box(1, 1, 1).scale(2).volume, 2**3, 5) def test_fuse(self): box1 = Solid.make_box(1, 1, 1) box2 = Solid.make_box(1, 1, 1, pnt=(1, 0, 0)) combined = box1.fuse(box2, glue=True) self.assertTrue(combined.is_valid()) - self.assertAlmostEqual(combined.volume(), 2, 5) + self.assertAlmostEqual(combined.volume, 2, 5) fuzzy = box1.fuse(box2, tol=1e-6) self.assertTrue(fuzzy.is_valid()) - self.assertAlmostEqual(fuzzy.volume(), 2, 5) + self.assertAlmostEqual(fuzzy.volume, 2, 5) def test_faces_intersected_by_line(self): box = Solid.make_box(1, 1, 1, pnt=(0, 0, 1)) @@ -1081,7 +1073,7 @@ class TestShape(unittest.TestCase): predicted_location = Location(offset) * Rotation(*rotation) located_shape = Solid.make_box(1, 1, 1).locate(predicted_location) intersect = shape.intersect(located_shape) - self.assertAlmostEqual(intersect.volume(), 1, 5) + self.assertAlmostEqual(intersect.volume, 1, 5) class TestShapeList(unittest.TestCase): @@ -1092,7 +1084,7 @@ class TestShapeList(unittest.TestCase): Solid.make_cylinder(1, 1).faces().filter_by(GeomType.PLANE, reverse=True) ) self.assertEqual(len(non_planar_faces), 1) - self.assertAlmostEqual(non_planar_faces[0].area(), 2 * math.pi, 5) + self.assertAlmostEqual(non_planar_faces[0].area, 2 * math.pi, 5) class TestCompound(unittest.TestCase): @@ -1114,10 +1106,10 @@ class TestCompound(unittest.TestCase): box2 = Solid.make_box(1, 1, 1, pnt=(1, 0, 0)) combined = Compound.make_compound([box1]).fuse(box2, glue=True) self.assertTrue(combined.is_valid()) - self.assertAlmostEqual(combined.volume(), 2, 5) + self.assertAlmostEqual(combined.volume, 2, 5) fuzzy = Compound.make_compound([box1]).fuse(box2, tol=1e-6) self.assertTrue(fuzzy.is_valid()) - self.assertAlmostEqual(fuzzy.volume(), 2, 5) + self.assertAlmostEqual(fuzzy.volume, 2, 5) # Doesn't work # def test_remove(self): @@ -1130,16 +1122,16 @@ class TestCompound(unittest.TestCase): class TestEdge(unittest.TestCase): def test_close(self): self.assertAlmostEqual( - Edge.make_circle(1, angle2=180).close().length(), math.pi + 2, 5 + Edge.make_circle(1, angle2=180).close().length, math.pi + 2, 5 ) - self.assertAlmostEqual(Edge.make_circle(1).close().length(), 2 * math.pi, 5) + self.assertAlmostEqual(Edge.make_circle(1).close().length, 2 * math.pi, 5) def test_arc_center(self): self.assertTupleAlmostEquals( - Edge.make_ellipse(2, 1).arc_center().to_tuple(), (0, 0, 0), 5 + Edge.make_ellipse(2, 1).arc_center.to_tuple(), (0, 0, 0), 5 ) with self.assertRaises(ValueError): - Edge.make_line((0, 0, 0), (0, 0, 1)).arc_center() + Edge.make_line((0, 0, 0), (0, 0, 1)).arc_center def test_spline_with_parameters(self): spline = Edge.make_spline( @@ -1176,7 +1168,7 @@ class TestFace(unittest.TestCase): top_edge = Edge.make_circle(radius=1, pnt=(0, 0, 1), angle2=90) curved = Face.make_surface_from_curves(bottom_edge, top_edge) self.assertTrue(curved.is_valid()) - self.assertAlmostEqual(curved.area(), math.pi / 2, 5) + self.assertAlmostEqual(curved.area, math.pi / 2, 5) self.assertTupleAlmostEquals( curved.normal_at().to_tuple(), (math.sqrt(2) / 2, math.sqrt(2) / 2, 0), 5 ) @@ -1185,17 +1177,17 @@ class TestFace(unittest.TestCase): top_wire = Wire.make_circle(1, center=(0, 0, 1), normal=(0, 0, 1)) curved = Face.make_surface_from_curves(bottom_wire, top_wire) self.assertTrue(curved.is_valid()) - self.assertAlmostEqual(curved.area(), 2 * math.pi, 5) + self.assertAlmostEqual(curved.area, 2 * math.pi, 5) def test_center(self): test_face = Face.make_from_wires( Wire.make_polygon([(0, 0), (1, 0), (1, 1), (0, 0)]) ) self.assertTupleAlmostEquals( - test_face.center(center_of=CenterOf.MASS).to_tuple(), (2 / 3, 1 / 3, 0), 1 + test_face.center_of_mass.to_tuple(), (2 / 3, 1 / 3, 0), 1 ) self.assertTupleAlmostEquals( - test_face.center(center_of=CenterOf.BOUNDING_BOX).to_tuple(), + test_face.bounding_box().center.to_tuple(), (0.5, 0.5, 0), 5, ) @@ -1329,8 +1321,8 @@ class TestSolid(unittest.TestCase): base = Face.make_rect(1, 1) pyramid = Solid.extrude_linear(base, normal=(0, 0, 1), taper=1) self.assertLess( - pyramid.faces().sort_by(Axis.Z)[-1].area(), - pyramid.faces().sort_by(Axis.Z)[0].area(), + pyramid.faces().sort_by(Axis.Z)[-1].area, + pyramid.faces().sort_by(Axis.Z)[0].area, ) def test_extrude_linear_with_rotation(self): @@ -1339,19 +1331,19 @@ class TestSolid(unittest.TestCase): twist = Solid.extrude_linear_with_rotation( base, center=(0, 0, 0), normal=(0, 0, 1), angle=45 ) - self.assertAlmostEqual(twist.volume(), 1, 5) + self.assertAlmostEqual(twist.volume, 1, 5) top = twist.faces().sort_by(Axis.Z)[-1].rotate(Axis.Z, 45) bottom = twist.faces().sort_by(Axis.Z)[0] - self.assertAlmostEqual(top.translate((0, 0, -1)).intersect(bottom).area(), 1, 5) + self.assertAlmostEqual(top.translate((0, 0, -1)).intersect(bottom).area, 1, 5) # Wire base = Wire.make_rect(1, 1) twist = Solid.extrude_linear_with_rotation( base, center=(0, 0, 0), normal=(0, 0, 1), angle=45 ) - self.assertAlmostEqual(twist.volume(), 1, 5) + self.assertAlmostEqual(twist.volume, 1, 5) top = twist.faces().sort_by(Axis.Z)[-1].rotate(Axis.Z, 45) bottom = twist.faces().sort_by(Axis.Z)[0] - self.assertAlmostEqual(top.translate((0, 0, -1)).intersect(bottom).area(), 1, 5) + self.assertAlmostEqual(top.translate((0, 0, -1)).intersect(bottom).area, 1, 5) class ProjectionTests(unittest.TestCase): @@ -1443,7 +1435,7 @@ class VertexTests(unittest.TestCase): v = Vertex(1, 1, 1) self.assertEqual(1, v.X) - self.assertEqual(Vector, type(v.center())) + self.assertEqual(Vector, type(v.center)) with self.assertRaises(ValueError): Vertex(Vector()) @@ -1494,11 +1486,11 @@ class TestWire(unittest.TestCase): def test_ellipse_arc(self): full_ellipse = Wire.make_ellipse(2, 1) half_ellipse = Wire.make_ellipse(2, 1, angle1=0, angle2=180, closed=True) - self.assertAlmostEqual(full_ellipse.area() / 2, half_ellipse.area(), 5) + self.assertAlmostEqual(full_ellipse.area / 2, half_ellipse.area, 5) def test_conical_helix(self): helix = Wire.make_helix(1, 4, 1, normal=(-1, 0, 0), angle=10, lefthand=True) - self.assertAlmostEqual(helix.length(), 34.102023034708374, 5) + self.assertAlmostEqual(helix.length, 34.102023034708374, 5) def test_stitch(self): half_ellipse1 = Wire.make_ellipse(2, 1, angle1=0, angle2=180, closed=False) @@ -1510,14 +1502,14 @@ class TestWire(unittest.TestCase): square = Wire.make_rect(1, 1) squaroid = square.fillet_2d(0.1, square.vertices()) self.assertAlmostEqual( - squaroid.length(), 4 * (1 - 2 * 0.1) + 2 * math.pi * 0.1, 5 + squaroid.length, 4 * (1 - 2 * 0.1) + 2 * math.pi * 0.1, 5 ) def test_chamfer_2d(self): square = Wire.make_rect(1, 1) squaroid = square.chamfer_2d(0.1, square.vertices()) self.assertAlmostEqual( - squaroid.length(), 4 * (1 - 2 * 0.1 + 0.1 * math.sqrt(2)), 5 + squaroid.length, 4 * (1 - 2 * 0.1 + 0.1 * math.sqrt(2)), 5 ) @@ -1527,8 +1519,8 @@ class TestFunctions(unittest.TestCase): rectangle_edges = Face.make_rect(2, 1, pnt=(5, 0)).edges() wires = edges_to_wires(square_edges + rectangle_edges) self.assertEqual(len(wires), 2) - self.assertAlmostEqual(wires[0].length(), 4, 5) - self.assertAlmostEqual(wires[1].length(), 6, 5) + self.assertAlmostEqual(wires[0].length, 4, 5) + self.assertAlmostEqual(wires[1].length, 6, 5) if __name__ == "__main__":