|
15 | 15 | Protocol,
|
16 | 16 | )
|
17 | 17 |
|
| 18 | +from typing_extensions import Self |
| 19 | + |
18 | 20 | from io import BytesIO
|
19 | 21 |
|
20 | 22 | from vtkmodules.vtkCommonDataModel import vtkPolyData
|
|
192 | 194 |
|
193 | 195 | from OCP.ShapeUpgrade import ShapeUpgrade_UnifySameDomain
|
194 | 196 |
|
195 |
| -from OCP.BRepTools import BRepTools, BRepTools_WireExplorer |
| 197 | +from OCP.BRepTools import ( |
| 198 | + BRepTools, |
| 199 | + BRepTools_WireExplorer, |
| 200 | + BRepTools_ReShape, |
| 201 | +) |
196 | 202 |
|
197 | 203 | from OCP.LocOpe import LocOpe_DPrism
|
198 | 204 |
|
@@ -1397,14 +1403,19 @@ def distance(self, other: "Shape") -> float:
|
1397 | 1403 | Minimal distance between two shapes
|
1398 | 1404 | """
|
1399 | 1405 |
|
1400 |
| - return BRepExtrema_DistShapeShape(self.wrapped, other.wrapped).Value() |
| 1406 | + dist_calc = BRepExtrema_DistShapeShape(self.wrapped, other.wrapped) |
| 1407 | + dist_calc.SetMultiThread(True) |
| 1408 | + |
| 1409 | + return dist_calc.Value() |
1401 | 1410 |
|
1402 | 1411 | def distances(self, *others: "Shape") -> Iterator[float]:
|
1403 | 1412 | """
|
1404 | 1413 | Minimal distances to between self and other shapes
|
1405 | 1414 | """
|
1406 | 1415 |
|
1407 | 1416 | dist_calc = BRepExtrema_DistShapeShape()
|
| 1417 | + dist_calc.SetMultiThread(True) |
| 1418 | + |
1408 | 1419 | dist_calc.LoadS1(self.wrapped)
|
1409 | 1420 |
|
1410 | 1421 | for s in others:
|
@@ -1689,6 +1700,40 @@ def __setstate__(self, data: Tuple[BytesIO, bool]):
|
1689 | 1700 | self.wrapped = wrapped
|
1690 | 1701 | self.forConstruction = data[1]
|
1691 | 1702 |
|
| 1703 | + def replace(self, old: "Shape", *new: "Shape") -> Self: |
| 1704 | + """ |
| 1705 | + Replace old subshape with new subshapes. |
| 1706 | + """ |
| 1707 | + |
| 1708 | + tools: List[Shape] = [] |
| 1709 | + |
| 1710 | + for el in new: |
| 1711 | + if isinstance(el, Compound): |
| 1712 | + tools.extend(el) |
| 1713 | + else: |
| 1714 | + tools.append(el) |
| 1715 | + |
| 1716 | + bldr = BRepTools_ReShape() |
| 1717 | + bldr.Replace(old.wrapped, compound(tools).wrapped) |
| 1718 | + |
| 1719 | + rv = bldr.Apply(self.wrapped) |
| 1720 | + |
| 1721 | + return self.__class__(rv) |
| 1722 | + |
| 1723 | + def remove(self, *subshape: "Shape") -> Self: |
| 1724 | + """ |
| 1725 | + Remove subshapes. |
| 1726 | + """ |
| 1727 | + |
| 1728 | + bldr = BRepTools_ReShape() |
| 1729 | + |
| 1730 | + for el in subshape: |
| 1731 | + bldr.Remove(el.wrapped) |
| 1732 | + |
| 1733 | + rv = bldr.Apply(self.wrapped) |
| 1734 | + |
| 1735 | + return self.__class__(rv) |
| 1736 | + |
1692 | 1737 |
|
1693 | 1738 | class ShapeProtocol(Protocol):
|
1694 | 1739 | @property
|
@@ -3484,6 +3529,32 @@ def isolines(
|
3484 | 3529 |
|
3485 | 3530 | return [self.isoline(p, direction) for p in params]
|
3486 | 3531 |
|
| 3532 | + def extend( |
| 3533 | + self, |
| 3534 | + d: float, |
| 3535 | + umin: bool = True, |
| 3536 | + umax: bool = True, |
| 3537 | + vmin: bool = True, |
| 3538 | + vmax: bool = True, |
| 3539 | + ) -> "Face": |
| 3540 | + """ |
| 3541 | + Extend a face. Does not work well in periodic directions. |
| 3542 | + |
| 3543 | + :param d: length of the extension. |
| 3544 | + :param umin: extend along the umin isoline. |
| 3545 | + :param umax: extend along the umax isoline. |
| 3546 | + :param vmin: extend along the vmin isoline. |
| 3547 | + :param vmax: extend along the vmax isoline. |
| 3548 | + """ |
| 3549 | + |
| 3550 | + # convert to NURBS if needed |
| 3551 | + tmp = self.toNURBS() if self.geomType() != "BSPLINE" else self |
| 3552 | + |
| 3553 | + rv = TopoDS_Face() |
| 3554 | + BRepLib.ExtendFace_s(tmp.wrapped, d, umin, umax, vmin, vmax, rv) |
| 3555 | + |
| 3556 | + return self.__class__(rv) |
| 3557 | + |
3487 | 3558 |
|
3488 | 3559 | class Shell(Shape):
|
3489 | 3560 | """
|
@@ -4357,6 +4428,25 @@ def innerShells(self) -> List[Shell]:
|
4357 | 4428 |
|
4358 | 4429 | return [s for s in self.Shells() if not s.isSame(outer)]
|
4359 | 4430 |
|
| 4431 | + def addCavity(self, *shells: Union[Shell, "Solid"]) -> Self: |
| 4432 | + """ |
| 4433 | + Add one or more cavities. |
| 4434 | + """ |
| 4435 | + |
| 4436 | + builder = BRepBuilderAPI_MakeSolid(self.wrapped) |
| 4437 | + |
| 4438 | + # if a solid is provided only outer shell is added |
| 4439 | + for sh in shells: |
| 4440 | + builder.Add( |
| 4441 | + sh.wrapped if isinstance(sh, Shell) else sh.outerShell().wrapped |
| 4442 | + ) |
| 4443 | + |
| 4444 | + # fix orientations |
| 4445 | + sf = ShapeFix_Solid(builder.Solid()) |
| 4446 | + sf.Perform() |
| 4447 | + |
| 4448 | + return self.__class__(sf.Solid()) |
| 4449 | + |
4360 | 4450 |
|
4361 | 4451 | class CompSolid(Shape, Mixin3D):
|
4362 | 4452 | """
|
@@ -4385,13 +4475,15 @@ def _makeCompound(listOfShapes: Iterable[TopoDS_Shape]) -> TopoDS_Compound:
|
4385 | 4475 |
|
4386 | 4476 | return comp
|
4387 | 4477 |
|
4388 |
| - def remove(self, shape: Shape): |
| 4478 | + def remove(self, *shape: Shape): |
4389 | 4479 | """
|
4390 |
| - Remove the specified shape. |
| 4480 | + Remove the specified shapes. |
4391 | 4481 | """
|
4392 | 4482 |
|
4393 | 4483 | comp_builder = TopoDS_Builder()
|
4394 |
| - comp_builder.Remove(self.wrapped, shape.wrapped) |
| 4484 | + |
| 4485 | + for s in shape: |
| 4486 | + comp_builder.Remove(self.wrapped, s.wrapped) |
4395 | 4487 |
|
4396 | 4488 | @classmethod
|
4397 | 4489 | def makeCompound(cls, listOfShapes: Iterable[Shape]) -> "Compound":
|
@@ -5672,11 +5764,17 @@ def imprint(
|
5672 | 5764 | # collect shapes present in the history dict
|
5673 | 5765 | for k, v in history.items():
|
5674 | 5766 | if isinstance(k, str):
|
5675 |
| - history[k] = _compound_or_shape(list(images.Find(v.wrapped))) |
| 5767 | + try: |
| 5768 | + history[k] = _compound_or_shape(list(images.Find(v.wrapped))) |
| 5769 | + except Standard_NoSuchObject: |
| 5770 | + pass |
5676 | 5771 |
|
5677 | 5772 | # store all top-level shape relations
|
5678 | 5773 | for s in shapes:
|
5679 |
| - history[s] = _compound_or_shape(list(images.Find(s.wrapped))) |
| 5774 | + try: |
| 5775 | + history[s] = _compound_or_shape(list(images.Find(s.wrapped))) |
| 5776 | + except Standard_NoSuchObject: |
| 5777 | + pass |
5680 | 5778 |
|
5681 | 5779 | return _compound_or_shape(builder.Shape())
|
5682 | 5780 |
|
@@ -5928,6 +6026,7 @@ def sweep(
|
5928 | 6026 | def _make_builder():
|
5929 | 6027 |
|
5930 | 6028 | rv = BRepOffsetAPI_MakePipeShell(spine.wrapped)
|
| 6029 | + |
5931 | 6030 | if aux:
|
5932 | 6031 | rv.SetMode(_get_one_wire(aux).wrapped, True)
|
5933 | 6032 | else:
|
@@ -6142,6 +6241,15 @@ def closest(s1: Shape, s2: Shape) -> Tuple[Vector, Vector]:
|
6142 | 6241 | """
|
6143 | 6242 | Closest points between two shapes.
|
6144 | 6243 | """
|
6145 |
| - ext = BRepExtrema_DistShapeShape(s1.wrapped, s2.wrapped) |
| 6244 | + # configure |
| 6245 | + ext = BRepExtrema_DistShapeShape() |
| 6246 | + ext.SetMultiThread(True) |
| 6247 | + |
| 6248 | + # load shapes |
| 6249 | + ext.LoadS1(s1.wrapped) |
| 6250 | + ext.LoadS2(s2.wrapped) |
| 6251 | + |
| 6252 | + # perform |
| 6253 | + assert ext.Perform() |
6146 | 6254 |
|
6147 | 6255 | return Vector(ext.PointOnShape1(1)), Vector(ext.PointOnShape2(1))
|
0 commit comments