|
265 | 265 |
|
266 | 266 | from OCP.BRepAlgo import BRepAlgo
|
267 | 267 |
|
| 268 | +from OCP.ChFi2d import ChFi2d_FilletAPI # For Wire.Fillet() |
| 269 | + |
268 | 270 | from math import pi, sqrt, inf, radians, cos
|
269 | 271 |
|
270 | 272 | import warnings
|
@@ -2379,6 +2381,90 @@ def chamfer2D(self, d: float, vertices: Iterable[Vertex]) -> "Wire":
|
2379 | 2381 |
|
2380 | 2382 | return f.chamfer2D(d, vertices).outerWire()
|
2381 | 2383 |
|
| 2384 | + def fillet( |
| 2385 | + self, radius: float, vertices: Optional[Iterable[Vertex]] = None |
| 2386 | + ) -> "Wire": |
| 2387 | + """ |
| 2388 | + Apply 2D or 3D fillet to a wire |
| 2389 | + :param wire: The input wire to fillet. Currently only open wires are supported |
| 2390 | + :param radius: the radius of the fillet, must be > zero |
| 2391 | + :param vertices: Optional list of vertices to fillet. By default all vertices are fillet. |
| 2392 | + :return: A wire with filleted corners |
| 2393 | + """ |
| 2394 | + |
| 2395 | + edges = list(self) |
| 2396 | + all_vertices = self.Vertices() |
| 2397 | + newEdges = [] |
| 2398 | + currentEdge = edges[0] |
| 2399 | + |
| 2400 | + verticesSet = set(vertices) if vertices else set() |
| 2401 | + |
| 2402 | + for i in range(len(edges) - 1): |
| 2403 | + nextEdge = edges[i + 1] |
| 2404 | + |
| 2405 | + # Create a plane that is spanned by currentEdge and nextEdge |
| 2406 | + currentDir = currentEdge.tangentAt(1) |
| 2407 | + nextDir = nextEdge.tangentAt(0) |
| 2408 | + normalDir = currentDir.cross(nextDir) |
| 2409 | + |
| 2410 | + # Check conditions for skipping fillet: |
| 2411 | + # 1. The edges are parallel |
| 2412 | + # 2. The vertex is not in the vertices white list |
| 2413 | + if normalDir.Length == 0 or ( |
| 2414 | + all_vertices[i + 1] not in verticesSet and bool(verticesSet) |
| 2415 | + ): |
| 2416 | + newEdges.append(currentEdge) |
| 2417 | + currentEdge = nextEdge |
| 2418 | + continue |
| 2419 | + |
| 2420 | + # Prepare for using ChFi2d_FilletAPI |
| 2421 | + pointInPlane = currentEdge.Center().toPnt() |
| 2422 | + cornerPlane = gp_Pln(pointInPlane, normalDir.toDir()) |
| 2423 | + |
| 2424 | + filletMaker = ChFi2d_FilletAPI( |
| 2425 | + currentEdge.wrapped, nextEdge.wrapped, cornerPlane |
| 2426 | + ) |
| 2427 | + |
| 2428 | + ok = filletMaker.Perform(radius) |
| 2429 | + if not ok: |
| 2430 | + raise ValueError(f"Failed fillet at vertex {i+1}!") |
| 2431 | + |
| 2432 | + # Get the result of the fillet operation |
| 2433 | + thePoint = next(iter(nextEdge)).Center().toPnt() |
| 2434 | + res_arc = filletMaker.Result( |
| 2435 | + thePoint, currentEdge.wrapped, nextEdge.wrapped |
| 2436 | + ) |
| 2437 | + |
| 2438 | + newEdges.append(currentEdge) |
| 2439 | + newEdges.append(Edge(res_arc)) |
| 2440 | + |
| 2441 | + currentEdge = nextEdge |
| 2442 | + |
| 2443 | + # Add the last edge |
| 2444 | + newEdges.append(currentEdge) |
| 2445 | + |
| 2446 | + return Wire.assembleEdges(newEdges) |
| 2447 | + |
| 2448 | + def Vertices(self) -> List[Vertex]: |
| 2449 | + """ |
| 2450 | + Ordered list of vertices of the wire. |
| 2451 | + """ |
| 2452 | + |
| 2453 | + rv = [] |
| 2454 | + |
| 2455 | + exp = BRepTools_WireExplorer(self.wrapped) |
| 2456 | + rv.append(Vertex(exp.CurrentVertex())) |
| 2457 | + |
| 2458 | + while exp.More(): |
| 2459 | + exp.Next() |
| 2460 | + rv.append(Vertex(exp.CurrentVertex())) |
| 2461 | + |
| 2462 | + # handle closed wires correclty |
| 2463 | + if self.IsClosed(): |
| 2464 | + rv = rv[:-1] |
| 2465 | + |
| 2466 | + return rv |
| 2467 | + |
2382 | 2468 | def __iter__(self) -> Iterator[Edge]:
|
2383 | 2469 | """
|
2384 | 2470 | Iterate over edges in an ordered way.
|
|
0 commit comments