- removed cadquery deoendency
This commit is contained in:
Generated
+16
-7
@@ -4,13 +4,13 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- Tons of addtions">
|
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- Basic operations">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/fluency/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/__init__.py" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry_occ/kernel.py" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/fluency/geometry_occ/sketch.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry_occ/sketch.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/fluency/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/main.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/tests/test_geometry.py" beforeDir="false" afterPath="$PROJECT_DIR$/tests/test_geometry.py" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -280,7 +280,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1782679912834</updated>
|
<updated>1782679912834</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="22" />
|
<task id="LOCAL-00022" summary="- Basic operations">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1782768610475</created>
|
||||||
|
<option name="number" value="00022" />
|
||||||
|
<option name="presentableId" value="LOCAL-00022" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1782768610475</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="23" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -319,6 +327,7 @@
|
|||||||
<MESSAGE value="- added screenshot" />
|
<MESSAGE value="- added screenshot" />
|
||||||
<MESSAGE value="- added sdf folder ( doesnt work via pip or git=)" />
|
<MESSAGE value="- added sdf folder ( doesnt work via pip or git=)" />
|
||||||
<MESSAGE value="- Tons of addtions" />
|
<MESSAGE value="- Tons of addtions" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="- Tons of addtions" />
|
<MESSAGE value="- Basic operations" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="- Basic operations" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -6,7 +6,7 @@ A parametric CAD application built on OpenCASCADE Technology (OCCT) with a moder
|
|||||||
|
|
||||||
- **OpenCASCADE Geometry Kernel**: Industry-standard BRep geometry with exact precision
|
- **OpenCASCADE Geometry Kernel**: Industry-standard BRep geometry with exact precision
|
||||||
- **STEP/IGES Import/Export**: Full support for industry-standard CAD file formats
|
- **STEP/IGES Import/Export**: Full support for industry-standard CAD file formats
|
||||||
- **Parametric Sketching**: 2D sketching with constraint solving using CadQuery
|
- **Parametric Sketching**: 2D sketching with constraint solving using SolveSpace
|
||||||
- **Boolean Operations**: Union, difference, and intersection
|
- **Boolean Operations**: Union, difference, and intersection
|
||||||
- **Fillet & Chamfer**: Apply edge treatments to solid bodies
|
- **Fillet & Chamfer**: Apply edge treatments to solid bodies
|
||||||
- **Modern Renderer**: WebGPU-based rendering with pygfx (smaller footprint than VTK)
|
- **Modern Renderer**: WebGPU-based rendering with pygfx (smaller footprint than VTK)
|
||||||
@@ -47,8 +47,7 @@ pip install -e ".[dev]"
|
|||||||
|
|
||||||
| Package | Purpose |
|
| Package | Purpose |
|
||||||
|---------|---------|
|
|---------|---------|
|
||||||
| cadquery | High-level OpenCASCADE Python bindings |
|
| cadquery-ocp | OpenCASCADE Python bindings (OCP) |
|
||||||
| ocp | Low-level OpenCASCADE Python bindings |
|
|
||||||
| pygfx | WebGPU-based 3D renderer |
|
| pygfx | WebGPU-based 3D renderer |
|
||||||
| wgpu | WebGPU Python bindings |
|
| wgpu | WebGPU Python bindings |
|
||||||
| PySide6 | Qt GUI framework |
|
| PySide6 | Qt GUI framework |
|
||||||
@@ -105,7 +104,7 @@ kernel.export_stl(body, "part.stl")
|
|||||||
| File Size | Large (mesh) | Small (BRep) |
|
| File Size | Large (mesh) | Small (BRep) |
|
||||||
| Fillet/Chamfer | Approximate | Exact |
|
| Fillet/Chamfer | Approximate | Exact |
|
||||||
| Dependency Size | ~200MB (VTK) | ~30MB (pygfx) |
|
| Dependency Size | ~200MB (VTK) | ~30MB (pygfx) |
|
||||||
| Constraint Solver | SolveSpace (separate) | CadQuery (integrated) |
|
| Constraint Solver | SolveSpace (separate) | SolveSpace (integrated) |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cadquery>=2.4",
|
|
||||||
"pygfx>=0.1.0",
|
"pygfx>=0.1.0",
|
||||||
"wgpu>=0.1.0",
|
"wgpu>=0.1.0",
|
||||||
"PySide6>=6.4.0",
|
"PySide6>=6.4.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Fluency CAD - Parametric CAD Application
|
Fluency CAD - Parametric CAD Application
|
||||||
|
|
||||||
A modern parametric CAD application built on OpenCASCADE Technology (OCCT)
|
A modern parametric CAD application built on OpenCASCADE Technology (OCCT)
|
||||||
with a clean Python API using CadQuery.
|
with a clean Python API using OCP (OpenCASCADE Python bindings).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "2.0.0"
|
__version__ = "2.0.0"
|
||||||
|
|||||||
+116
-232
@@ -2,7 +2,7 @@
|
|||||||
OpenCASCADE-based geometry kernel for Fluency CAD.
|
OpenCASCADE-based geometry kernel for Fluency CAD.
|
||||||
|
|
||||||
This module provides a concrete implementation of the geometry kernel
|
This module provides a concrete implementation of the geometry kernel
|
||||||
using CadQuery and OCP (OpenCASCADE Python bindings).
|
using OCP (OpenCASCADE Python bindings).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List, Tuple, Optional, Any, Dict
|
from typing import List, Tuple, Optional, Any, Dict
|
||||||
@@ -21,24 +21,14 @@ class OCCGeometryObject(GeometryObject):
|
|||||||
|
|
||||||
def __init__(self, shape: Any = None, metadata: Optional[Dict] = None):
|
def __init__(self, shape: Any = None, metadata: Optional[Dict] = None):
|
||||||
super().__init__(shape, metadata)
|
super().__init__(shape, metadata)
|
||||||
self._cadquery_obj: Any = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cq_obj(self) -> Any:
|
|
||||||
"""Get the CadQuery object if available."""
|
|
||||||
return self._cadquery_obj
|
|
||||||
|
|
||||||
@cq_obj.setter
|
|
||||||
def cq_obj(self, value: Any) -> None:
|
|
||||||
self._cadquery_obj = value
|
|
||||||
|
|
||||||
|
|
||||||
class OCGeometryKernel(GeometryKernel):
|
class OCGeometryKernel(GeometryKernel):
|
||||||
"""
|
"""
|
||||||
OpenCASCADE-based geometry kernel implementation.
|
OpenCASCADE-based geometry kernel implementation.
|
||||||
|
|
||||||
This kernel uses CadQuery for high-level operations and
|
This kernel uses OCP (OpenCASCADE Python bindings) for all geometry
|
||||||
OCP for direct OpenCASCADE access when needed.
|
operations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@@ -51,114 +41,93 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
Returns *None* if the object carries no shape (e.g. an empty sketch) —
|
Returns *None* if the object carries no shape (e.g. an empty sketch) —
|
||||||
callers should check for None before using the result.
|
callers should check for None before using the result.
|
||||||
"""
|
"""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
if isinstance(obj, OCCGeometryObject):
|
if isinstance(obj, OCCGeometryObject):
|
||||||
if obj._cadquery_obj is not None:
|
if obj.shape is not None and hasattr(obj.shape, "wrapped"):
|
||||||
shape = obj._cadquery_obj.val()
|
|
||||||
if hasattr(shape, "wrapped"):
|
|
||||||
return shape.wrapped
|
|
||||||
return shape
|
|
||||||
if obj.shape is not None:
|
|
||||||
if isinstance(obj.shape, cq.Workplane):
|
|
||||||
shape = obj.shape.val()
|
|
||||||
if hasattr(shape, "wrapped"):
|
|
||||||
return shape.wrapped
|
|
||||||
return shape
|
|
||||||
if hasattr(obj.shape, "wrapped"):
|
|
||||||
return obj.shape.wrapped
|
return obj.shape.wrapped
|
||||||
return obj.shape
|
return obj.shape
|
||||||
# No cadquery obj and no raw shape → genuinely empty.
|
|
||||||
return None
|
|
||||||
# Non-OCCGeometryObject: return its shape if present, else None.
|
# Non-OCCGeometryObject: return its shape if present, else None.
|
||||||
# (Use explicit identity/truth checks — some OCP TopoDS objects have a
|
# (Use explicit identity/truth checks — some OCP TopoDS objects have a
|
||||||
# falsy __bool__, so ``obj.shape if obj.shape`` is unsafe.)
|
# falsy __bool__, so ``obj.shape if obj.shape`` is unsafe.)
|
||||||
shape = getattr(obj, "shape", None)
|
shape = getattr(obj, "shape", None)
|
||||||
return shape if shape is not None else None
|
return shape if shape is not None else None
|
||||||
|
|
||||||
def _get_cq_obj(self, obj: GeometryObject) -> Any:
|
|
||||||
"""Get CadQuery object from GeometryObject."""
|
|
||||||
if isinstance(obj, OCCGeometryObject) and obj._cadquery_obj is not None:
|
|
||||||
return obj._cadquery_obj
|
|
||||||
return obj.shape
|
|
||||||
|
|
||||||
def create_point(self, x: float, y: float) -> GeometryObject:
|
def create_point(self, x: float, y: float) -> GeometryObject:
|
||||||
"""Create a 2D point."""
|
"""Create a 2D point."""
|
||||||
import cadquery as cq
|
from OCP.gp import gp_Pnt
|
||||||
|
return OCCGeometryObject(gp_Pnt(x, y, 0))
|
||||||
point = cq.Vector(x, y, 0)
|
|
||||||
return OCCGeometryObject(point)
|
|
||||||
|
|
||||||
def create_line(self, start: Point2D, end: Point2D) -> GeometryObject:
|
def create_line(self, start: Point2D, end: Point2D) -> GeometryObject:
|
||||||
"""Create a 2D line segment."""
|
"""Create a 2D line segment."""
|
||||||
import cadquery as cq
|
from OCP.gp import gp_Pnt
|
||||||
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
|
||||||
|
|
||||||
wp = cq.Workplane("XY").moveTo(start.x, start.y).lineTo(end.x, end.y)
|
edge = BRepBuilderAPI_MakeEdge(
|
||||||
obj = OCCGeometryObject(wp.val(), {"type": "line"})
|
gp_Pnt(start.x, start.y, 0), gp_Pnt(end.x, end.y, 0)
|
||||||
obj._cadquery_obj = wp
|
).Edge()
|
||||||
return obj
|
return OCCGeometryObject(edge, {"type": "line"})
|
||||||
|
|
||||||
def create_circle(self, center: Point2D, radius: float) -> GeometryObject:
|
def create_circle(self, center: Point2D, radius: float) -> GeometryObject:
|
||||||
"""Create a 2D circle."""
|
"""Create a 2D circle."""
|
||||||
import cadquery as cq
|
from OCP.gp import gp_Pnt, gp_Dir, gp_Ax2, gp_Circ
|
||||||
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
|
||||||
|
|
||||||
wp = cq.Workplane("XY").center(center.x, center.y).circle(radius)
|
circ = gp_Circ(
|
||||||
obj = OCCGeometryObject(wp.val(), {"type": "circle"})
|
gp_Ax2(gp_Pnt(center.x, center.y, 0), gp_Dir(0, 0, 1)), radius
|
||||||
obj._cadquery_obj = wp
|
)
|
||||||
return obj
|
edge = BRepBuilderAPI_MakeEdge(circ).Edge()
|
||||||
|
return OCCGeometryObject(edge, {"type": "circle"})
|
||||||
|
|
||||||
def create_arc(
|
def create_arc(
|
||||||
self, center: Point2D, radius: float, start_angle: float, end_angle: float
|
self, center: Point2D, radius: float, start_angle: float, end_angle: float
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Create a 2D arc."""
|
"""Create a 2D arc."""
|
||||||
import cadquery as cq
|
|
||||||
import math
|
import math
|
||||||
|
from OCP.gp import gp_Pnt, gp_Dir, gp_Ax2, gp_Circ
|
||||||
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
|
||||||
|
|
||||||
start_rad = math.radians(start_angle)
|
start_rad = math.radians(start_angle)
|
||||||
end_rad = math.radians(end_angle)
|
end_rad = math.radians(end_angle)
|
||||||
|
|
||||||
start_x = center.x + radius * math.cos(start_rad)
|
circ = gp_Circ(
|
||||||
start_y = center.y + radius * math.sin(start_rad)
|
gp_Ax2(gp_Pnt(center.x, center.y, 0), gp_Dir(0, 0, 1)), radius
|
||||||
|
|
||||||
wire = (
|
|
||||||
cq.Workplane("XY")
|
|
||||||
.moveTo(start_x, start_y)
|
|
||||||
.radiusArc(
|
|
||||||
(center.x + radius * math.cos(end_rad), center.y + radius * math.sin(end_rad)),
|
|
||||||
radius,
|
|
||||||
)
|
)
|
||||||
)
|
edge = BRepBuilderAPI_MakeEdge(circ, start_rad, end_rad).Edge()
|
||||||
return OCCGeometryObject(wire.val(), {"type": "arc"})
|
return OCCGeometryObject(edge, {"type": "arc"})
|
||||||
|
|
||||||
def create_polygon(self, points: List[Point2D]) -> GeometryObject:
|
def create_polygon(self, points: List[Point2D]) -> GeometryObject:
|
||||||
"""Create a closed polygon from points."""
|
"""Create a closed polygon from points."""
|
||||||
import cadquery as cq
|
from OCP.gp import gp_Pnt
|
||||||
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakePolygon
|
||||||
|
|
||||||
if len(points) < 3:
|
if len(points) < 3:
|
||||||
raise ValueError("Polygon requires at least 3 points")
|
raise ValueError("Polygon requires at least 3 points")
|
||||||
|
|
||||||
wp = cq.Workplane("XY").moveTo(points[0].x, points[0].y)
|
mp = BRepBuilderAPI_MakePolygon()
|
||||||
for pt in points[1:]:
|
for pt in points:
|
||||||
wp = wp.lineTo(pt.x, pt.y)
|
mp.Add(gp_Pnt(pt.x, pt.y, 0))
|
||||||
wp = wp.close()
|
mp.Close()
|
||||||
|
return OCCGeometryObject(mp.Wire(), {"type": "polygon"})
|
||||||
obj = OCCGeometryObject(wp.val(), {"type": "polygon"})
|
|
||||||
obj._cadquery_obj = wp
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def create_rectangle(
|
def create_rectangle(
|
||||||
self, width: float, height: float, center: Optional[Point2D] = None
|
self, width: float, height: float, center: Optional[Point2D] = None
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Create a rectangle."""
|
"""Create a rectangle."""
|
||||||
import cadquery as cq
|
from OCP.gp import gp_Pnt
|
||||||
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakePolygon
|
||||||
|
|
||||||
cx = center.x if center else 0
|
cx = center.x if center else 0
|
||||||
cy = center.y if center else 0
|
cy = center.y if center else 0
|
||||||
|
|
||||||
wp = cq.Workplane("XY").center(cx, cy).rect(width, height)
|
hw = width / 2.0
|
||||||
obj = OCCGeometryObject(wp.val(), {"type": "rectangle"})
|
hh = height / 2.0
|
||||||
obj._cadquery_obj = wp
|
|
||||||
return obj
|
mp = BRepBuilderAPI_MakePolygon()
|
||||||
|
mp.Add(gp_Pnt(cx - hw, cy - hh, 0))
|
||||||
|
mp.Add(gp_Pnt(cx + hw, cy - hh, 0))
|
||||||
|
mp.Add(gp_Pnt(cx + hw, cy + hh, 0))
|
||||||
|
mp.Add(gp_Pnt(cx - hw, cy + hh, 0))
|
||||||
|
mp.Close()
|
||||||
|
return OCCGeometryObject(mp.Wire(), {"type": "rectangle"})
|
||||||
|
|
||||||
def extrude(
|
def extrude(
|
||||||
self,
|
self,
|
||||||
@@ -182,10 +151,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
# Defensive: figure out the actual shape from whatever the caller
|
# Defensive: figure out the actual shape from whatever the caller
|
||||||
# hands us, and surface a clear error if we can't get one.
|
# hands us, and surface a clear error if we can't get one.
|
||||||
# - If it's an OCCGeometryObject wrapper, unwrap via _get_shape.
|
|
||||||
# - If it's already a TopoDS_Shape (raw face/wire/etc.), use it.
|
|
||||||
# - If it's a cadquery Workplane, unwrap that too.
|
|
||||||
# - If it's a cadquery Shape (cq.Shape), unwrap to TopoDS_Shape.
|
|
||||||
if isinstance(sketch, OCCGeometryObject):
|
if isinstance(sketch, OCCGeometryObject):
|
||||||
face = self._get_shape(sketch)
|
face = self._get_shape(sketch)
|
||||||
elif isinstance(sketch, TopoDS_Shape):
|
elif isinstance(sketch, TopoDS_Shape):
|
||||||
@@ -205,8 +170,8 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
"Cannot extrude: sketch geometry is a wrapper, not a shape. "
|
"Cannot extrude: sketch geometry is a wrapper, not a shape. "
|
||||||
"This is a bug — please report it."
|
"This is a bug — please report it."
|
||||||
)
|
)
|
||||||
# ``face`` may be a TopoDS_Face (new path) or a compound/wire from
|
# ``face`` may be a TopoDS_Face (new path) or a compound/wire.
|
||||||
# legacy cadquery objects. If it's not already a face, build one.
|
# If it's not already a face, build one.
|
||||||
face = self._ensure_face(face)
|
face = self._ensure_face(face)
|
||||||
if face is None:
|
if face is None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -303,48 +268,58 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def loft(self, profiles: List[GeometryObject], ruled: bool = False) -> GeometryObject:
|
def loft(self, profiles: List[GeometryObject], ruled: bool = False) -> GeometryObject:
|
||||||
"""Create a loft between multiple profiles."""
|
"""Create a loft between multiple profiles."""
|
||||||
import cadquery as cq
|
from OCP.BRepOffsetAPI import BRepOffsetAPI_ThruSections
|
||||||
|
from OCP.TopExp import TopExp_Explorer
|
||||||
|
from OCP.TopAbs import TopAbs_WIRE
|
||||||
|
from OCP.TopoDS import TopoDS
|
||||||
|
|
||||||
if len(profiles) < 2:
|
if len(profiles) < 2:
|
||||||
raise ValueError("Loft requires at least 2 profiles")
|
raise ValueError("Loft requires at least 2 profiles")
|
||||||
|
|
||||||
wires = []
|
loft_maker = BRepOffsetAPI_ThruSections(True, ruled)
|
||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
cq_obj = self._get_cq_obj(profile)
|
shape = self._get_shape(profile)
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
explorer = TopExp_Explorer(shape, TopAbs_WIRE)
|
||||||
wires.append(cq_obj.val())
|
while explorer.More():
|
||||||
else:
|
wire = TopoDS.Wire_s(explorer.Current())
|
||||||
wires.append(cq_obj)
|
loft_maker.AddWire(wire)
|
||||||
|
explorer.Next()
|
||||||
|
|
||||||
loft = cq.Solid.loft(wires, ruled)
|
loft_maker.Build()
|
||||||
return OCCGeometryObject(loft, {"type": "loft"})
|
solid = loft_maker.Shape()
|
||||||
|
return OCCGeometryObject(solid, {"type": "loft"})
|
||||||
|
|
||||||
def sweep(
|
def sweep(
|
||||||
self, profile: GeometryObject, path: GeometryObject, is_frenet: bool = False
|
self, profile: GeometryObject, path: GeometryObject, is_frenet: bool = False
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Sweep a profile along a path."""
|
"""Sweep a profile along a path."""
|
||||||
import cadquery as cq
|
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakePipeShell
|
||||||
|
from OCP.TopExp import TopExp_Explorer
|
||||||
|
from OCP.TopAbs import TopAbs_WIRE
|
||||||
|
from OCP.TopoDS import TopoDS
|
||||||
|
|
||||||
profile_obj = self._get_cq_obj(profile)
|
profile_shape = self._get_shape(profile)
|
||||||
path_obj = self._get_cq_obj(path)
|
path_shape = self._get_shape(path)
|
||||||
|
|
||||||
if isinstance(profile_obj, cq.Workplane):
|
def _first_wire(shape):
|
||||||
profile_wire = profile_obj.val()
|
exp = TopExp_Explorer(shape, TopAbs_WIRE)
|
||||||
else:
|
if exp.More():
|
||||||
profile_wire = profile_obj
|
return TopoDS.Wire_s(exp.Current())
|
||||||
|
raise ValueError("No wire found in shape for sweep")
|
||||||
|
|
||||||
if isinstance(path_obj, cq.Workplane):
|
profile_wire = _first_wire(profile_shape)
|
||||||
path_wire = path_obj.val()
|
path_wire = _first_wire(path_shape)
|
||||||
else:
|
|
||||||
path_wire = path_obj
|
|
||||||
|
|
||||||
solid = cq.Solid.sweep(profile_wire, path_wire, is_frenet)
|
pipe = BRepOffsetAPI_MakePipeShell(path_wire)
|
||||||
|
pipe.Add(profile_wire, False, False)
|
||||||
|
if is_frenet:
|
||||||
|
pipe.SetMode(True)
|
||||||
|
pipe.Build()
|
||||||
|
solid = pipe.Shape()
|
||||||
return OCCGeometryObject(solid, {"type": "sweep"})
|
return OCCGeometryObject(solid, {"type": "sweep"})
|
||||||
|
|
||||||
def boolean_union(self, *bodies: GeometryObject) -> GeometryObject:
|
def boolean_union(self, *bodies: GeometryObject) -> GeometryObject:
|
||||||
"""Union multiple bodies."""
|
"""Union multiple bodies."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
if len(bodies) < 2:
|
if len(bodies) < 2:
|
||||||
return bodies[0] if bodies else OCCGeometryObject(None)
|
return bodies[0] if bodies else OCCGeometryObject(None)
|
||||||
|
|
||||||
@@ -357,12 +332,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
fuse.Build()
|
fuse.Build()
|
||||||
result = fuse.Shape()
|
result = fuse.Shape()
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(result), {"type": "union"})
|
return OCCGeometryObject(result, {"type": "union"})
|
||||||
|
|
||||||
def boolean_difference(self, base: GeometryObject, tool: GeometryObject) -> GeometryObject:
|
def boolean_difference(self, base: GeometryObject, tool: GeometryObject) -> GeometryObject:
|
||||||
"""Subtract tool from base."""
|
"""Subtract tool from base."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
base_shape = self._get_shape(base)
|
base_shape = self._get_shape(base)
|
||||||
tool_shape = self._get_shape(tool)
|
tool_shape = self._get_shape(tool)
|
||||||
|
|
||||||
@@ -371,12 +344,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
cut = BRepAlgoAPI_Cut(base_shape, tool_shape)
|
cut = BRepAlgoAPI_Cut(base_shape, tool_shape)
|
||||||
cut.Build()
|
cut.Build()
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(cut.Shape()), {"type": "difference"})
|
return OCCGeometryObject(cut.Shape(), {"type": "difference"})
|
||||||
|
|
||||||
def boolean_intersection(self, body1: GeometryObject, body2: GeometryObject) -> GeometryObject:
|
def boolean_intersection(self, body1: GeometryObject, body2: GeometryObject) -> GeometryObject:
|
||||||
"""Intersect two bodies."""
|
"""Intersect two bodies."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape1 = self._get_shape(body1)
|
shape1 = self._get_shape(body1)
|
||||||
shape2 = self._get_shape(body2)
|
shape2 = self._get_shape(body2)
|
||||||
|
|
||||||
@@ -385,27 +356,21 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
common = BRepAlgoAPI_Common(shape1, shape2)
|
common = BRepAlgoAPI_Common(shape1, shape2)
|
||||||
common.Build()
|
common.Build()
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(common.Shape()), {"type": "intersection"})
|
return OCCGeometryObject(common.Shape(), {"type": "intersection"})
|
||||||
|
|
||||||
def fillet(
|
def fillet(
|
||||||
self, body: GeometryObject, radius: float, edges: Optional[List[Any]] = None
|
self, body: GeometryObject, radius: float, edges: Optional[List[Any]] = None
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Apply fillet to edges."""
|
"""Apply fillet to edges."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
if edges:
|
|
||||||
result = cq_obj.edges(edges).fillet(radius)
|
|
||||||
else:
|
|
||||||
result = cq_obj.edges().fillet(radius)
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepFilletAPI import BRepFilletAPI_MakeFillet
|
from OCP.BRepFilletAPI import BRepFilletAPI_MakeFillet
|
||||||
|
|
||||||
fillet = BRepFilletAPI_MakeFillet(shape)
|
fillet = BRepFilletAPI_MakeFillet(shape)
|
||||||
|
|
||||||
|
if edges:
|
||||||
|
for edge in edges:
|
||||||
|
fillet.Add(radius, edge)
|
||||||
|
else:
|
||||||
from OCP.TopExp import TopExp_Explorer
|
from OCP.TopExp import TopExp_Explorer
|
||||||
from OCP.TopAbs import TopAbs_EDGE
|
from OCP.TopAbs import TopAbs_EDGE
|
||||||
|
|
||||||
@@ -414,29 +379,22 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
fillet.Add(radius, explorer.Current())
|
fillet.Add(radius, explorer.Current())
|
||||||
explorer.Next()
|
explorer.Next()
|
||||||
|
|
||||||
result = cq.Shape(fillet.Shape())
|
fillet.Build()
|
||||||
|
return OCCGeometryObject(fillet.Shape(), {"type": "fillet"})
|
||||||
return OCCGeometryObject(result, {"type": "fillet"})
|
|
||||||
|
|
||||||
def chamfer(
|
def chamfer(
|
||||||
self, body: GeometryObject, size: float, edges: Optional[List[Any]] = None
|
self, body: GeometryObject, size: float, edges: Optional[List[Any]] = None
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Apply chamfer to edges."""
|
"""Apply chamfer to edges."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
if edges:
|
|
||||||
result = cq_obj.edges(edges).chamfer(size)
|
|
||||||
else:
|
|
||||||
result = cq_obj.edges().chamfer(size)
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepFilletAPI import BRepFilletAPI_MakeChamfer
|
from OCP.BRepFilletAPI import BRepFilletAPI_MakeChamfer
|
||||||
|
|
||||||
chamfer = BRepFilletAPI_MakeChamfer(shape)
|
chamfer = BRepFilletAPI_MakeChamfer(shape)
|
||||||
|
|
||||||
|
if edges:
|
||||||
|
for edge in edges:
|
||||||
|
chamfer.Add(size, edge)
|
||||||
|
else:
|
||||||
from OCP.TopExp import TopExp_Explorer
|
from OCP.TopExp import TopExp_Explorer
|
||||||
from OCP.TopAbs import TopAbs_EDGE
|
from OCP.TopAbs import TopAbs_EDGE
|
||||||
|
|
||||||
@@ -445,24 +403,13 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
chamfer.Add(size, explorer.Current())
|
chamfer.Add(size, explorer.Current())
|
||||||
explorer.Next()
|
explorer.Next()
|
||||||
|
|
||||||
result = cq.Shape(chamfer.Shape())
|
chamfer.Build()
|
||||||
|
return OCCGeometryObject(chamfer.Shape(), {"type": "chamfer"})
|
||||||
return OCCGeometryObject(result, {"type": "chamfer"})
|
|
||||||
|
|
||||||
def shell(
|
def shell(
|
||||||
self, body: GeometryObject, thickness: float, faces_to_remove: Optional[List[Any]] = None
|
self, body: GeometryObject, thickness: float, faces_to_remove: Optional[List[Any]] = None
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Create a shell (hollow body)."""
|
"""Create a shell (hollow body)."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
if faces_to_remove:
|
|
||||||
result = cq_obj.faces(faces_to_remove).shell(thickness)
|
|
||||||
else:
|
|
||||||
result = cq_obj.shell(thickness)
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid
|
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid
|
||||||
from OCP.TopTools import TopTools_ListOfShape
|
from OCP.TopTools import TopTools_ListOfShape
|
||||||
@@ -475,31 +422,20 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
shell_maker = BRepOffsetAPI_MakeThickSolid()
|
shell_maker = BRepOffsetAPI_MakeThickSolid()
|
||||||
shell_maker.MakeThickSolidByJoin(shape, faces_list, thickness, 0.001)
|
shell_maker.MakeThickSolidByJoin(shape, faces_list, thickness, 0.001)
|
||||||
shell_maker.Build()
|
shell_maker.Build()
|
||||||
result = cq.Shape(shell_maker.Shape())
|
return OCCGeometryObject(shell_maker.Shape(), {"type": "shell"})
|
||||||
|
|
||||||
return OCCGeometryObject(result, {"type": "shell"})
|
|
||||||
|
|
||||||
def offset(self, face: GeometryObject, distance: float) -> GeometryObject:
|
def offset(self, face: GeometryObject, distance: float) -> GeometryObject:
|
||||||
"""Offset a face or surface."""
|
"""Offset a face or surface."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(face)
|
shape = self._get_shape(face)
|
||||||
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeOffset
|
from OCP.BRepOffsetAPI import BRepOffsetAPI_MakeOffset
|
||||||
|
|
||||||
offset_maker = BRepOffsetAPI_MakeOffset(shape, False)
|
offset_maker = BRepOffsetAPI_MakeOffset(shape, False)
|
||||||
offset_maker.Perform(distance)
|
offset_maker.Perform(distance)
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(offset_maker.Shape()), {"type": "offset"})
|
return OCCGeometryObject(offset_maker.Shape(), {"type": "offset"})
|
||||||
|
|
||||||
def translate(self, body: GeometryObject, vector: Tuple[float, float, float]) -> GeometryObject:
|
def translate(self, body: GeometryObject, vector: Tuple[float, float, float]) -> GeometryObject:
|
||||||
"""Translate a body."""
|
"""Translate a body."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
result = cq_obj.translate(vector)
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
||||||
from OCP.gp import gp_Trsf, gp_Vec
|
from OCP.gp import gp_Trsf, gp_Vec
|
||||||
@@ -507,9 +443,7 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
transform = gp_Trsf()
|
transform = gp_Trsf()
|
||||||
transform.SetTranslation(gp_Vec(*vector))
|
transform.SetTranslation(gp_Vec(*vector))
|
||||||
transformer = BRepBuilderAPI_Transform(shape, transform)
|
transformer = BRepBuilderAPI_Transform(shape, transform)
|
||||||
result = cq.Shape(transformer.Shape())
|
return OCCGeometryObject(transformer.Shape(), {"type": "translated"})
|
||||||
|
|
||||||
return OCCGeometryObject(result, {"type": "translated"})
|
|
||||||
|
|
||||||
def rotate(
|
def rotate(
|
||||||
self,
|
self,
|
||||||
@@ -519,30 +453,19 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
origin: Tuple[float, float, float] = (0, 0, 0),
|
origin: Tuple[float, float, float] = (0, 0, 0),
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Rotate a body around an axis."""
|
"""Rotate a body around an axis."""
|
||||||
import cadquery as cq
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
result = cq_obj.rotate(origin, axis, math.degrees(angle))
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
||||||
from OCP.gp import gp_Trsf, gp_Ax1, gp_Pnt, gp_Dir, gp_Vec
|
from OCP.gp import gp_Trsf, gp_Ax1, gp_Pnt, gp_Dir
|
||||||
|
|
||||||
ax1 = gp_Ax1(gp_Pnt(*origin), gp_Dir(*axis))
|
ax1 = gp_Ax1(gp_Pnt(*origin), gp_Dir(*axis))
|
||||||
transform = gp_Trsf()
|
transform = gp_Trsf()
|
||||||
transform.SetRotation(ax1, angle)
|
transform.SetRotation(ax1, angle)
|
||||||
transformer = BRepBuilderAPI_Transform(shape, transform)
|
transformer = BRepBuilderAPI_Transform(shape, transform)
|
||||||
result = cq.Shape(transformer.Shape())
|
return OCCGeometryObject(transformer.Shape(), {"type": "rotated"})
|
||||||
|
|
||||||
return OCCGeometryObject(result, {"type": "rotated"})
|
|
||||||
|
|
||||||
def scale(self, body: GeometryObject, factor: float) -> GeometryObject:
|
def scale(self, body: GeometryObject, factor: float) -> GeometryObject:
|
||||||
"""Scale a body uniformly."""
|
"""Scale a body uniformly."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
||||||
from OCP.gp import gp_Trsf
|
from OCP.gp import gp_Trsf
|
||||||
@@ -551,7 +474,7 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
transform.SetScale(factor)
|
transform.SetScale(factor)
|
||||||
transformer = BRepBuilderAPI_Transform(shape, transform)
|
transformer = BRepBuilderAPI_Transform(shape, transform)
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(transformer.Shape()), {"type": "scaled"})
|
return OCCGeometryObject(transformer.Shape(), {"type": "scaled"})
|
||||||
|
|
||||||
def mirror(
|
def mirror(
|
||||||
self,
|
self,
|
||||||
@@ -560,8 +483,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
plane_origin: Tuple[float, float, float] = (0, 0, 0),
|
plane_origin: Tuple[float, float, float] = (0, 0, 0),
|
||||||
) -> GeometryObject:
|
) -> GeometryObject:
|
||||||
"""Mirror a body across a plane."""
|
"""Mirror a body across a plane."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
from OCP.BRepBuilderAPI import BRepBuilderAPI_Transform
|
||||||
from OCP.gp import gp_Trsf, gp_Ax2, gp_Pnt, gp_Dir
|
from OCP.gp import gp_Trsf, gp_Ax2, gp_Pnt, gp_Dir
|
||||||
@@ -571,19 +492,12 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
transform.SetMirror(ax2)
|
transform.SetMirror(ax2)
|
||||||
transformer = BRepBuilderAPI_Transform(shape, transform)
|
transformer = BRepBuilderAPI_Transform(shape, transform)
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(transformer.Shape()), {"type": "mirrored"})
|
return OCCGeometryObject(transformer.Shape(), {"type": "mirrored"})
|
||||||
|
|
||||||
def export_step(self, body: GeometryObject, filepath: str, schema: str = "AP214") -> bool:
|
def export_step(self, body: GeometryObject, filepath: str, schema: str = "AP214") -> bool:
|
||||||
"""Export to STEP format."""
|
"""Export to STEP format."""
|
||||||
try:
|
try:
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
if hasattr(shape, "exportStep"):
|
|
||||||
shape.exportStep(filepath)
|
|
||||||
return True
|
|
||||||
|
|
||||||
from OCP.STEPControl import STEPControl_Writer, STEPControl_AsIs
|
from OCP.STEPControl import STEPControl_Writer, STEPControl_AsIs
|
||||||
from OCP.Interface import Interface_Static
|
from OCP.Interface import Interface_Static
|
||||||
|
|
||||||
@@ -594,8 +508,7 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
Interface_Static.SetCVal_s("write.step.schema", "AP203")
|
Interface_Static.SetCVal_s("write.step.schema", "AP203")
|
||||||
|
|
||||||
writer.Transfer(shape, STEPControl_AsIs)
|
writer.Transfer(shape, STEPControl_AsIs)
|
||||||
writer.Write(filepath)
|
return writer.Write(filepath)
|
||||||
return True
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"STEP export error: {e}")
|
print(f"STEP export error: {e}")
|
||||||
return False
|
return False
|
||||||
@@ -603,18 +516,14 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
def export_iges(self, body: GeometryObject, filepath: str) -> bool:
|
def export_iges(self, body: GeometryObject, filepath: str) -> bool:
|
||||||
"""Export to IGES format."""
|
"""Export to IGES format."""
|
||||||
try:
|
try:
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.IGESControl import IGESControl_Writer
|
from OCP.IGESControl import IGESControl_Writer
|
||||||
from OCP.Interface import Interface_Static
|
from OCP.Interface import Interface_Static
|
||||||
|
|
||||||
Interface_Static.SetCVal_s("write.iges.schema", "5.3")
|
Interface_Static.SetCVal_s("write.iges.schema", "5.3")
|
||||||
writer = IGESControl_Writer()
|
writer = IGESControl_Writer()
|
||||||
writer.AddShape(shape)
|
writer.AddShape(shape)
|
||||||
writer.Write(filepath)
|
return writer.Write(filepath)
|
||||||
return True
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"IGES export error: {e}")
|
print(f"IGES export error: {e}")
|
||||||
return False
|
return False
|
||||||
@@ -624,14 +533,7 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
) -> bool:
|
) -> bool:
|
||||||
"""Export to STL format."""
|
"""Export to STL format."""
|
||||||
try:
|
try:
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
if hasattr(shape, "exportStl"):
|
|
||||||
shape.exportStl(filepath, tolerance)
|
|
||||||
return True
|
|
||||||
|
|
||||||
from OCP.StlAPI import StlAPI_Writer
|
from OCP.StlAPI import StlAPI_Writer
|
||||||
from OCP.BRepMesh import BRepMesh_IncrementalMesh
|
from OCP.BRepMesh import BRepMesh_IncrementalMesh
|
||||||
|
|
||||||
@@ -640,23 +542,28 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
writer = StlAPI_Writer()
|
writer = StlAPI_Writer()
|
||||||
writer.ASCIIMode = ascii_mode
|
writer.ASCIIMode = ascii_mode
|
||||||
writer.Write(shape, filepath)
|
return writer.Write(shape, filepath)
|
||||||
return True
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"STL export error: {e}")
|
print(f"STL export error: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def import_step(self, filepath: str) -> GeometryObject:
|
def import_step(self, filepath: str) -> GeometryObject:
|
||||||
"""Import from STEP format."""
|
"""Import from STEP format."""
|
||||||
import cadquery as cq
|
from OCP.STEPControl import STEPControl_Reader
|
||||||
|
from OCP.IFSelect import IFSelect_RetDone
|
||||||
|
|
||||||
result = cq.importers.importStep(filepath)
|
reader = STEPControl_Reader()
|
||||||
return OCCGeometryObject(result, {"type": "imported_step"})
|
status = reader.ReadFile(filepath)
|
||||||
|
|
||||||
|
if status != IFSelect_RetDone:
|
||||||
|
raise ValueError(f"Failed to read STEP file: {filepath}")
|
||||||
|
|
||||||
|
reader.TransferRoots()
|
||||||
|
shape = reader.OneShape()
|
||||||
|
return OCCGeometryObject(shape, {"type": "imported_step"})
|
||||||
|
|
||||||
def import_iges(self, filepath: str) -> GeometryObject:
|
def import_iges(self, filepath: str) -> GeometryObject:
|
||||||
"""Import from IGES format."""
|
"""Import from IGES format."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
from OCP.IGESControl import IGESControl_Reader
|
from OCP.IGESControl import IGESControl_Reader
|
||||||
from OCP.IFSelect import IFSelect_RetDone
|
from OCP.IFSelect import IFSelect_RetDone
|
||||||
|
|
||||||
@@ -669,27 +576,14 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
reader.TransferRoots()
|
reader.TransferRoots()
|
||||||
shape = reader.OneShape()
|
shape = reader.OneShape()
|
||||||
|
|
||||||
return OCCGeometryObject(cq.Shape(shape), {"type": "imported_iges"})
|
return OCCGeometryObject(shape, {"type": "imported_iges"})
|
||||||
|
|
||||||
def get_mesh(
|
def get_mesh(
|
||||||
self, body: GeometryObject, tolerance: float = 0.1
|
self, body: GeometryObject, tolerance: float = 0.1
|
||||||
) -> Tuple[np.ndarray, np.ndarray]:
|
) -> Tuple[np.ndarray, np.ndarray]:
|
||||||
"""Get triangulated mesh for rendering."""
|
"""Get triangulated mesh for rendering."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
cq_obj = self._get_cq_obj(body)
|
|
||||||
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
shape = cq_obj.val()
|
|
||||||
if hasattr(shape, "wrapped"):
|
|
||||||
shape = shape.wrapped
|
|
||||||
else:
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
if hasattr(shape, "tessellate"):
|
|
||||||
vertices, faces = shape.tessellate(tolerance)
|
|
||||||
return np.array(vertices), np.array(faces)
|
|
||||||
|
|
||||||
from OCP.BRepMesh import BRepMesh_IncrementalMesh
|
from OCP.BRepMesh import BRepMesh_IncrementalMesh
|
||||||
from OCP.TopExp import TopExp_Explorer
|
from OCP.TopExp import TopExp_Explorer
|
||||||
from OCP.TopAbs import TopAbs_FACE
|
from OCP.TopAbs import TopAbs_FACE
|
||||||
@@ -745,8 +639,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def get_edges(self, body: GeometryObject) -> Tuple[np.ndarray, np.ndarray]:
|
def get_edges(self, body: GeometryObject) -> Tuple[np.ndarray, np.ndarray]:
|
||||||
"""Get edge wireframe for rendering."""
|
"""Get edge wireframe for rendering."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.TopExp import TopExp_Explorer
|
from OCP.TopExp import TopExp_Explorer
|
||||||
@@ -801,8 +693,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def get_bounding_box(self, body: GeometryObject) -> Tuple[Point3D, Point3D]:
|
def get_bounding_box(self, body: GeometryObject) -> Tuple[Point3D, Point3D]:
|
||||||
"""Get the bounding box of a body."""
|
"""Get the bounding box of a body."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.Bnd import Bnd_Box
|
from OCP.Bnd import Bnd_Box
|
||||||
@@ -817,8 +707,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def get_volume(self, body: GeometryObject) -> float:
|
def get_volume(self, body: GeometryObject) -> float:
|
||||||
"""Calculate the volume of a solid body."""
|
"""Calculate the volume of a solid body."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
@@ -831,8 +719,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def get_surface_area(self, body: GeometryObject) -> float:
|
def get_surface_area(self, body: GeometryObject) -> float:
|
||||||
"""Calculate the surface area of a body."""
|
"""Calculate the surface area of a body."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
@@ -845,8 +731,6 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def get_center_of_mass(self, body: GeometryObject) -> Point3D:
|
def get_center_of_mass(self, body: GeometryObject) -> Point3D:
|
||||||
"""Calculate the center of mass of a solid body."""
|
"""Calculate the center of mass of a solid body."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
|
|||||||
Reference in New Issue
Block a user