Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for closed path fillet to Wire.fillet() #1573

Merged
merged 9 commits into from
Jun 13, 2024
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ init:
install:
- mamba env create -f environment.yml
- conda activate cadquery
- conda list

build: false

Expand Down
22 changes: 16 additions & 6 deletions cadquery/occ_impl/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
overload,
TypeVar,
cast as tcast,
Literal,
Protocol,
)
from typing_extensions import Literal, Protocol

from io import BytesIO

Expand Down Expand Up @@ -2505,13 +2506,18 @@ def fillet(

edges = list(self)
all_vertices = self.Vertices()
n_edges = len(edges)
n_vertices = len(all_vertices)

newEdges = []
currentEdge = edges[0]

verticesSet = set(vertices) if vertices else set()

for i in range(len(edges) - 1):
nextEdge = edges[i + 1]
for i in range(n_edges):
if i == n_edges - 1 and not self.IsClosed():
break
nextEdge = edges[(i + 1) % n_edges]

# Create a plane that is spanned by currentEdge and nextEdge
currentDir = currentEdge.tangentAt(1)
Expand All @@ -2522,7 +2528,8 @@ def fillet(
# 1. The edges are parallel
# 2. The vertex is not in the vertices white list
if normalDir.Length == 0 or (
all_vertices[i + 1] not in verticesSet and bool(verticesSet)
all_vertices[(i + 1) % n_vertices] not in verticesSet
and bool(verticesSet)
):
newEdges.append(currentEdge)
currentEdge = nextEdge
Expand Down Expand Up @@ -2551,8 +2558,11 @@ def fillet(

currentEdge = nextEdge

# Add the last edge
newEdges.append(currentEdge)
# Add the last edge unless we are closed, since then
# currentEdge is the first edge, which was already added
# (and clipped)
if not self.IsClosed():
newEdges.append(currentEdge)

return Wire.assembleEdges(newEdges)

Expand Down
2 changes: 1 addition & 1 deletion cadquery/occ_impl/sketch_solver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Tuple, Union, Any, Callable, List, Optional, Iterable, Dict, Sequence
from typing_extensions import Literal
from typing import Literal
from nptyping import NDArray as Array
from nptyping import Float
from itertools import accumulate, chain
Expand Down
2 changes: 1 addition & 1 deletion cadquery/sketch.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
Sequence,
TypeVar,
cast as tcast,
Literal,
)
from typing_extensions import Literal
from math import tan, sin, cos, pi, radians, remainder
from itertools import product, chain
from multimethod import multimethod
Expand Down
11 changes: 11 additions & 0 deletions tests/test_cad_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,17 @@ def testWireFillet(self):
with self.assertRaises(ValueError):
wfillet = wire.fillet(radius=1.0)

# Test a closed fillet
points = [[0, 0, 0], [5, 4, 0], [8, 3, 1], [10, 0, 0]]

wire = Wire.makePolygon(points, close=True)
wfillet = wire.fillet(radius=0.5)
assert len(wfillet.Edges()) == 2 * len(points)

# Fillet a single vertex
wfillet = wire.fillet(radius=0.5, vertices=wire.Vertices()[0:1])
assert len(wfillet.Edges()) == len(points) + 1


@pytest.mark.parametrize(
"points, close, expected_edges",
Expand Down