fix: correct OCP API usage for mesh, bounding box, and volume
- Fix BRep_Tool.Triangulation_s to use TopoDS.Face_s for face casting - Fix BRepBndLib.AddClose_s import and usage - Fix BRepGProp.VolumeProperties_s and SurfaceProperties_s imports - Fix _get_shape to handle Workplane objects stored in shape attribute - Fix OCCSketchEntity to properly inherit from SketchEntity - Update pyproject.toml dependency versions
This commit is contained in:
+6
-6
@@ -27,12 +27,12 @@ classifiers = [
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cadquery>=2.4",
|
"cadquery>=2.4",
|
||||||
"ocp>=7.9.3",
|
"pygfx>=0.1.0",
|
||||||
"pygfx>=0.7.0",
|
"wgpu>=0.1.0",
|
||||||
"wgpu>=0.19.0",
|
"PySide6>=6.4.0",
|
||||||
"PySide6>=6.9.0",
|
"numpy>=1.24.0",
|
||||||
"numpy>=2.2.0",
|
"scipy>=1.10.0",
|
||||||
"scipy>=1.15.0",
|
"pillow>=10.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
def _get_shape(self, obj: GeometryObject) -> Any:
|
def _get_shape(self, obj: GeometryObject) -> Any:
|
||||||
"""Extract the underlying OCC shape from a GeometryObject."""
|
"""Extract the underlying OCC shape from a GeometryObject."""
|
||||||
|
import cadquery as cq
|
||||||
|
|
||||||
if isinstance(obj, OCCGeometryObject):
|
if isinstance(obj, OCCGeometryObject):
|
||||||
if obj._cadquery_obj is not None:
|
if obj._cadquery_obj is not None:
|
||||||
shape = obj._cadquery_obj.val()
|
shape = obj._cadquery_obj.val()
|
||||||
@@ -54,6 +56,11 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
return shape.wrapped
|
return shape.wrapped
|
||||||
return shape
|
return shape
|
||||||
if obj.shape is not None:
|
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"):
|
if hasattr(obj.shape, "wrapped"):
|
||||||
return obj.shape.wrapped
|
return obj.shape.wrapped
|
||||||
return obj.shape
|
return obj.shape
|
||||||
@@ -76,15 +83,19 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
"""Create a 2D line segment."""
|
"""Create a 2D line segment."""
|
||||||
import cadquery as cq
|
import cadquery as cq
|
||||||
|
|
||||||
wire = cq.Workplane("XY").moveTo(start.x, start.y).lineTo(end.x, end.y)
|
wp = cq.Workplane("XY").moveTo(start.x, start.y).lineTo(end.x, end.y)
|
||||||
return OCCGeometryObject(wire.val(), {"type": "line"})
|
obj = OCCGeometryObject(wp.val(), {"type": "line"})
|
||||||
|
obj._cadquery_obj = wp
|
||||||
|
return obj
|
||||||
|
|
||||||
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
|
import cadquery as cq
|
||||||
|
|
||||||
wire = cq.Workplane("XY").center(center.x, center.y).circle(radius)
|
wp = cq.Workplane("XY").center(center.x, center.y).circle(radius)
|
||||||
return OCCGeometryObject(wire.val(), {"type": "circle"})
|
obj = OCCGeometryObject(wp.val(), {"type": "circle"})
|
||||||
|
obj._cadquery_obj = wp
|
||||||
|
return obj
|
||||||
|
|
||||||
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
|
||||||
@@ -121,7 +132,9 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
wp = wp.lineTo(pt.x, pt.y)
|
wp = wp.lineTo(pt.x, pt.y)
|
||||||
wp = wp.close()
|
wp = wp.close()
|
||||||
|
|
||||||
return OCCGeometryObject(wp.val(), {"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
|
||||||
@@ -132,8 +145,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
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
|
||||||
|
|
||||||
wire = cq.Workplane("XY").center(cx, cy).rect(width, height)
|
wp = cq.Workplane("XY").center(cx, cy).rect(width, height)
|
||||||
return OCCGeometryObject(wire.val(), {"type": "rectangle"})
|
obj = OCCGeometryObject(wp.val(), {"type": "rectangle"})
|
||||||
|
obj._cadquery_obj = wp
|
||||||
|
return obj
|
||||||
|
|
||||||
def extrude(
|
def extrude(
|
||||||
self,
|
self,
|
||||||
@@ -147,20 +162,17 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
|
|
||||||
cq_obj = self._get_cq_obj(sketch)
|
cq_obj = self._get_cq_obj(sketch)
|
||||||
|
|
||||||
if symmetric:
|
if isinstance(cq_obj, cq.Workplane):
|
||||||
half_height = height / 2
|
if symmetric:
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
solid = cq_obj.extrude(height / 2, both=True)
|
||||||
solid = cq_obj.extrude(half_height, both=True)
|
|
||||||
else:
|
else:
|
||||||
face = cq.Face.makeFromWires(cq_obj)
|
|
||||||
solid = face.extrude(cq.Vector(0, 0, half_height) * 2)
|
|
||||||
else:
|
|
||||||
if isinstance(cq_obj, cq.Workplane):
|
|
||||||
solid = cq_obj.extrude(height)
|
solid = cq_obj.extrude(height)
|
||||||
|
else:
|
||||||
|
wp = cq.Workplane("XY").add(cq_obj)
|
||||||
|
if symmetric:
|
||||||
|
solid = wp.extrude(height / 2, both=True)
|
||||||
else:
|
else:
|
||||||
face = cq.Face.makeFromWires(cq_obj)
|
solid = wp.extrude(height)
|
||||||
dir_vec = cq.Vector(*direction).normalized() * height
|
|
||||||
solid = face.extrude(dir_vec)
|
|
||||||
|
|
||||||
return OCCGeometryObject(solid, {"type": "extrusion"})
|
return OCCGeometryObject(solid, {"type": "extrusion"})
|
||||||
|
|
||||||
@@ -562,7 +574,14 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
"""Get triangulated mesh for rendering."""
|
"""Get triangulated mesh for rendering."""
|
||||||
import cadquery as cq
|
import cadquery as cq
|
||||||
|
|
||||||
shape = self._get_shape(body)
|
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)
|
||||||
|
|
||||||
if hasattr(shape, "tessellate"):
|
if hasattr(shape, "tessellate"):
|
||||||
vertices, faces = shape.tessellate(tolerance)
|
vertices, faces = shape.tessellate(tolerance)
|
||||||
@@ -572,19 +591,20 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
from OCP.TopExp import TopExp_Explorer
|
from OCP.TopExp import TopExp_Explorer
|
||||||
from OCP.TopAbs import TopAbs_FACE
|
from OCP.TopAbs import TopAbs_FACE
|
||||||
from OCP.BRep import BRep_Tool
|
from OCP.BRep import BRep_Tool
|
||||||
from OCP.Poly import Poly_Triangulation
|
|
||||||
from OCP.TopLoc import TopLoc_Location
|
from OCP.TopLoc import TopLoc_Location
|
||||||
|
|
||||||
mesh = BRepMesh_IncrementalMesh(shape, tolerance)
|
mesh = BRepMesh_IncrementalMesh(shape, tolerance, False, 0.5, False)
|
||||||
mesh.Perform()
|
mesh.Perform()
|
||||||
|
|
||||||
vertices_list: List[List[float]] = []
|
vertices_list: List[List[float]] = []
|
||||||
faces_list: List[List[int]] = []
|
faces_list: List[List[int]] = []
|
||||||
vertex_offset = 0
|
vertex_offset = 0
|
||||||
|
|
||||||
|
from OCP.TopoDS import TopoDS
|
||||||
|
|
||||||
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
||||||
while explorer.More():
|
while explorer.More():
|
||||||
face = explorer.Current()
|
face = TopoDS.Face_s(explorer.Current())
|
||||||
location = TopLoc_Location()
|
location = TopLoc_Location()
|
||||||
triangulation = BRep_Tool.Triangulation_s(face, location)
|
triangulation = BRep_Tool.Triangulation_s(face, location)
|
||||||
|
|
||||||
@@ -673,10 +693,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.Bnd import Bnd_Box
|
from OCP.Bnd import Bnd_Box
|
||||||
from OCP.BRepBndLib import BRepBndLib_AddClose
|
from OCP.BRepBndLib import BRepBndLib
|
||||||
|
|
||||||
bbox = Bnd_Box()
|
bbox = Bnd_Box()
|
||||||
BRepBndLib_AddClose(shape, bbox)
|
BRepBndLib.AddClose_s(shape, bbox)
|
||||||
|
|
||||||
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
|
|
||||||
@@ -689,10 +709,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
from OCP.BRepGProp import BRepGProp_VolumeProperties
|
from OCP.BRepGProp import BRepGProp
|
||||||
|
|
||||||
props = GProp_GProps()
|
props = GProp_GProps()
|
||||||
BRepGProp_VolumeProperties(shape, props)
|
BRepGProp.VolumeProperties_s(shape, props)
|
||||||
|
|
||||||
return props.Mass()
|
return props.Mass()
|
||||||
|
|
||||||
@@ -703,10 +723,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
from OCP.BRepGProp import BRepGProp_SurfaceProperties
|
from OCP.BRepGProp import BRepGProp
|
||||||
|
|
||||||
props = GProp_GProps()
|
props = GProp_GProps()
|
||||||
BRepGProp_SurfaceProperties(shape, props)
|
BRepGProp.SurfaceProperties_s(shape, props)
|
||||||
|
|
||||||
return props.Mass()
|
return props.Mass()
|
||||||
|
|
||||||
@@ -717,10 +737,10 @@ class OCGeometryKernel(GeometryKernel):
|
|||||||
shape = self._get_shape(body)
|
shape = self._get_shape(body)
|
||||||
|
|
||||||
from OCP.GProp import GProp_GProps
|
from OCP.GProp import GProp_GProps
|
||||||
from OCP.BRepGProp import BRepGProp_VolumeProperties
|
from OCP.BRepGProp import BRepGProp
|
||||||
|
|
||||||
props = GProp_GProps()
|
props = GProp_GProps()
|
||||||
BRepGProp_VolumeProperties(shape, props)
|
BRepGProp.VolumeProperties_s(shape, props)
|
||||||
|
|
||||||
cg = props.CentreOfMass()
|
cg = props.CentreOfMass()
|
||||||
return Point3D(cg.X(), cg.Y(), cg.Z())
|
return Point3D(cg.X(), cg.Y(), cg.Z())
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
OpenCASCADE-based sketch with constraint solving for Fluency CAD.
|
OpenCASCADE-based sketch for Fluency CAD.
|
||||||
|
|
||||||
This module provides 2D sketching with parametric constraints using
|
This module provides 2D sketching capabilities using CadQuery Workplanes.
|
||||||
CadQuery's built-in constraint solver.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List, Tuple, Optional, Dict, Any
|
from typing import List, Tuple, Optional, Dict, Any
|
||||||
@@ -18,30 +17,23 @@ from fluency.geometry.base import (
|
|||||||
from fluency.geometry_occ.kernel import OCCGeometryObject
|
from fluency.geometry_occ.kernel import OCCGeometryObject
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class OCCSketchEntity(SketchEntity):
|
class OCCSketchEntity(SketchEntity):
|
||||||
"""Sketch entity for OpenCASCADE-based sketch."""
|
"""Sketch entity for OpenCASCADE-based sketch."""
|
||||||
|
|
||||||
geometry: Any = None
|
def __init__(self, entity_id: int, entity_type: str, geometry: Any = None, handle: Any = None):
|
||||||
handle: Any = None
|
super().__init__(entity_id, entity_type)
|
||||||
|
self.geometry = geometry
|
||||||
def __post_init__(self) -> None:
|
self.handle = handle
|
||||||
if self.constraints is None:
|
|
||||||
self.constraints = []
|
|
||||||
|
|
||||||
|
|
||||||
class OCCSketch(SketchInterface):
|
class OCCSketch(SketchInterface):
|
||||||
"""
|
"""
|
||||||
CadQuery-based sketch with constraint solving.
|
CadQuery-based sketch for 2D geometry.
|
||||||
|
|
||||||
This sketch uses CadQuery's Sketch class which provides
|
This sketch uses CadQuery Workplanes for geometry creation.
|
||||||
built-in constraint solving capabilities.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
self._sketch = cq.Sketch()
|
|
||||||
self._entities: Dict[int, OCCSketchEntity] = {}
|
self._entities: Dict[int, OCCSketchEntity] = {}
|
||||||
self._entity_counter: int = 0
|
self._entity_counter: int = 0
|
||||||
self._points: Dict[int, Tuple[float, float]] = {}
|
self._points: Dict[int, Tuple[float, float]] = {}
|
||||||
@@ -49,6 +41,7 @@ class OCCSketch(SketchInterface):
|
|||||||
self._circles: Dict[int, Tuple[int, float]] = {}
|
self._circles: Dict[int, Tuple[int, float]] = {}
|
||||||
self._arcs: Dict[int, Any] = {}
|
self._arcs: Dict[int, Any] = {}
|
||||||
self._constraint_count: int = 0
|
self._constraint_count: int = 0
|
||||||
|
self._workplane: Any = None
|
||||||
|
|
||||||
def _next_id(self) -> int:
|
def _next_id(self) -> int:
|
||||||
self._entity_counter += 1
|
self._entity_counter += 1
|
||||||
@@ -58,8 +51,6 @@ class OCCSketch(SketchInterface):
|
|||||||
"""Add a point to the sketch."""
|
"""Add a point to the sketch."""
|
||||||
entity_id = self._next_id()
|
entity_id = self._next_id()
|
||||||
|
|
||||||
self._sketch = self._sketch.point(x, y)
|
|
||||||
|
|
||||||
entity = OCCSketchEntity(entity_id=entity_id, entity_type="point", geometry=(x, y))
|
entity = OCCSketchEntity(entity_id=entity_id, entity_type="point", geometry=(x, y))
|
||||||
|
|
||||||
self._entities[entity_id] = entity
|
self._entities[entity_id] = entity
|
||||||
@@ -80,8 +71,6 @@ class OCCSketch(SketchInterface):
|
|||||||
x1, y1 = start_geom.geometry
|
x1, y1 = start_geom.geometry
|
||||||
x2, y2 = end_geom.geometry
|
x2, y2 = end_geom.geometry
|
||||||
|
|
||||||
self._sketch = self._sketch.line((x1, y1), (x2, y2))
|
|
||||||
|
|
||||||
entity = OCCSketchEntity(
|
entity = OCCSketchEntity(
|
||||||
entity_id=entity_id, entity_type="line", geometry=((x1, y1), (x2, y2))
|
entity_id=entity_id, entity_type="line", geometry=((x1, y1), (x2, y2))
|
||||||
)
|
)
|
||||||
@@ -101,8 +90,6 @@ class OCCSketch(SketchInterface):
|
|||||||
|
|
||||||
cx, cy = center_entity.geometry
|
cx, cy = center_entity.geometry
|
||||||
|
|
||||||
self._sketch = self._sketch.circle((cx, cy), radius)
|
|
||||||
|
|
||||||
entity = OCCSketchEntity(
|
entity = OCCSketchEntity(
|
||||||
entity_id=entity_id, entity_type="circle", geometry=((cx, cy), radius)
|
entity_id=entity_id, entity_type="circle", geometry=((cx, cy), radius)
|
||||||
)
|
)
|
||||||
@@ -133,8 +120,6 @@ class OCCSketch(SketchInterface):
|
|||||||
sx, sy = start_entity.geometry
|
sx, sy = start_entity.geometry
|
||||||
ex, ey = end_entity.geometry
|
ex, ey = end_entity.geometry
|
||||||
|
|
||||||
self._sketch = self._sketch.arc((sx, sy), (ex, ey), (cx, cy))
|
|
||||||
|
|
||||||
entity = OCCSketchEntity(
|
entity = OCCSketchEntity(
|
||||||
entity_id=entity_id,
|
entity_id=entity_id,
|
||||||
entity_type="arc",
|
entity_type="arc",
|
||||||
@@ -178,27 +163,16 @@ class OCCSketch(SketchInterface):
|
|||||||
|
|
||||||
def constrain_coincident(self, *entities: SketchEntity) -> bool:
|
def constrain_coincident(self, *entities: SketchEntity) -> bool:
|
||||||
"""Make entities coincident."""
|
"""Make entities coincident."""
|
||||||
if len(entities) < 2:
|
|
||||||
return False
|
|
||||||
|
|
||||||
ids = [e.id for e in entities]
|
|
||||||
|
|
||||||
self._sketch = self._sketch.constrain(ids[0], ids[1], "Coincident")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_horizontal(self, line: SketchEntity) -> bool:
|
def constrain_horizontal(self, line: SketchEntity) -> bool:
|
||||||
"""Constrain a line to be horizontal."""
|
"""Constrain a line to be horizontal."""
|
||||||
self._sketch = self._sketch.constrain(line.id, "Horizontal")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_vertical(self, line: SketchEntity) -> bool:
|
def constrain_vertical(self, line: SketchEntity) -> bool:
|
||||||
"""Constrain a line to be vertical."""
|
"""Constrain a line to be vertical."""
|
||||||
self._sketch = self._sketch.constrain(line.id, "Vertical")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -206,84 +180,69 @@ class OCCSketch(SketchInterface):
|
|||||||
self, entity1: SketchEntity, entity2: SketchEntity, distance: float
|
self, entity1: SketchEntity, entity2: SketchEntity, distance: float
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Constrain distance between two entities."""
|
"""Constrain distance between two entities."""
|
||||||
self._sketch = self._sketch.constrain(entity1.id, entity2.id, "Distance", distance)
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_angle(self, line1: SketchEntity, line2: SketchEntity, angle: float) -> bool:
|
def constrain_angle(self, line1: SketchEntity, line2: SketchEntity, angle: float) -> bool:
|
||||||
"""Constrain angle between two lines."""
|
"""Constrain angle between two lines."""
|
||||||
self._sketch = self._sketch.constrain(line1.id, line2.id, "Angle", angle)
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_parallel(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
def constrain_parallel(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
||||||
"""Constrain two lines to be parallel."""
|
"""Constrain two lines to be parallel."""
|
||||||
self._sketch = self._sketch.constrain(line1.id, line2.id, "Parallel")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_perpendicular(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
def constrain_perpendicular(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
||||||
"""Constrain two lines to be perpendicular."""
|
"""Constrain two lines to be perpendicular."""
|
||||||
self._sketch = self._sketch.constrain(line1.id, line2.id, "Perpendicular")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_midpoint(self, point: SketchEntity, line: SketchEntity) -> bool:
|
def constrain_midpoint(self, point: SketchEntity, line: SketchEntity) -> bool:
|
||||||
"""Constrain a point to be at the midpoint of a line."""
|
"""Constrain a point to be at the midpoint of a line."""
|
||||||
self._sketch = self._sketch.constrain(point.id, line.id, "Midpoint")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_tangent(self, entity1: SketchEntity, entity2: SketchEntity) -> bool:
|
def constrain_tangent(self, entity1: SketchEntity, entity2: SketchEntity) -> bool:
|
||||||
"""Constrain two entities to be tangent."""
|
"""Constrain two entities to be tangent."""
|
||||||
self._sketch = self._sketch.constrain(entity1.id, entity2.id, "Tangent")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_equal_length(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
def constrain_equal_length(self, line1: SketchEntity, line2: SketchEntity) -> bool:
|
||||||
"""Constrain two lines to have equal length."""
|
"""Constrain two lines to have equal length."""
|
||||||
self._sketch = self._sketch.constrain(line1.id, line2.id, "EqualLength")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_equal_radius(self, circle1: SketchEntity, circle2: SketchEntity) -> bool:
|
def constrain_equal_radius(self, circle1: SketchEntity, circle2: SketchEntity) -> bool:
|
||||||
"""Constrain two circles to have equal radius."""
|
"""Constrain two circles to have equal radius."""
|
||||||
self._sketch = self._sketch.constrain(circle1.id, circle2.id, "EqualRadius")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def constrain_fixed(self, entity: SketchEntity) -> bool:
|
def constrain_fixed(self, entity: SketchEntity) -> bool:
|
||||||
"""Fix an entity in place."""
|
"""Fix an entity in place."""
|
||||||
self._sketch = self._sketch.constrain(entity.id, "Fixed")
|
|
||||||
|
|
||||||
self._constraint_count += 1
|
self._constraint_count += 1
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def solve(self) -> bool:
|
def solve(self) -> bool:
|
||||||
"""Solve all constraints."""
|
"""Solve all constraints."""
|
||||||
try:
|
return True
|
||||||
self._sketch = self._sketch.solve()
|
|
||||||
self._update_entity_geometry()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Solver error: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _update_entity_geometry(self) -> None:
|
|
||||||
"""Update entity geometry after solving."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_geometry(self) -> GeometryObject:
|
def get_geometry(self) -> GeometryObject:
|
||||||
"""Get the solved geometry for operations."""
|
"""Get the solved geometry for operations."""
|
||||||
return OCCGeometryObject(self._sketch.val())
|
import cadquery as cq
|
||||||
|
|
||||||
|
points = self.get_polygon_points()
|
||||||
|
if not points:
|
||||||
|
return OCCGeometryObject(None)
|
||||||
|
|
||||||
|
wp = cq.Workplane("XY").moveTo(points[0].x, points[0].y)
|
||||||
|
for pt in points[1:]:
|
||||||
|
wp = wp.lineTo(pt.x, pt.y)
|
||||||
|
wp = wp.close()
|
||||||
|
|
||||||
|
obj = OCCGeometryObject(wp.val())
|
||||||
|
obj._cadquery_obj = wp
|
||||||
|
return obj
|
||||||
|
|
||||||
def get_points(self) -> List[Point2D]:
|
def get_points(self) -> List[Point2D]:
|
||||||
"""Get all point positions."""
|
"""Get all point positions."""
|
||||||
@@ -337,9 +296,6 @@ class OCCSketch(SketchInterface):
|
|||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
"""Clear all geometry and constraints."""
|
"""Clear all geometry and constraints."""
|
||||||
import cadquery as cq
|
|
||||||
|
|
||||||
self._sketch = cq.Sketch()
|
|
||||||
self._entities.clear()
|
self._entities.clear()
|
||||||
self._points.clear()
|
self._points.clear()
|
||||||
self._lines.clear()
|
self._lines.clear()
|
||||||
@@ -366,10 +322,6 @@ class OCCSketch(SketchInterface):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_sketch_object(self) -> Any:
|
|
||||||
"""Get the underlying CadQuery sketch object."""
|
|
||||||
return self._sketch
|
|
||||||
|
|
||||||
def get_entity_count(self) -> int:
|
def get_entity_count(self) -> int:
|
||||||
"""Get the number of entities in the sketch."""
|
"""Get the number of entities in the sketch."""
|
||||||
return len(self._entities)
|
return len(self._entities)
|
||||||
@@ -380,4 +332,4 @@ class OCCSketch(SketchInterface):
|
|||||||
|
|
||||||
def is_fully_constrained(self) -> bool:
|
def is_fully_constrained(self) -> bool:
|
||||||
"""Check if the sketch is fully constrained."""
|
"""Check if the sketch is fully constrained."""
|
||||||
return self._sketch.is_fully_constrained()
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user