"""
Copyright (c) 2021-2022, CodeLV.
Distributed under the terms of the GPL v3 License.
The full license is in the file LICENSE, distributed with this software.
"""
from typing import Any, Optional
from atom.api import Dict, Typed, set_default
from OCCT.BRep import BRep_Builder, BRep_Tool
from OCCT.BRepAdaptor import BRepAdaptor_CompCurve
from OCCT.BRepBuilderAPI import (
BRepBuilderAPI_MakeEdge,
BRepBuilderAPI_MakeFace,
BRepBuilderAPI_MakeWire,
)
from OCCT.BRepMAT2d import (
BRepMAT2d_BisectingLocus,
BRepMAT2d_Explorer,
BRepMAT2d_LinkTopoBilo,
)
from OCCT.BRepOffsetAPI import BRepOffsetAPI_MiddlePath
from OCCT.GeomAbs import GeomAbs_Arc, GeomAbs_Intersection, GeomAbs_Tangent
from OCCT.MAT import MAT_Arc, MAT_Left
from OCCT.TopoDS import (
TopoDS_Compound,
TopoDS_Edge,
TopoDS_Face,
TopoDS_Shape,
TopoDS_Wire,
)
from declaracad.occ.draw import ProxyMiddlePath
from .occ_shape import Shape
from .occ_wire import OccWire
from .topology import Topology
[docs]
class OccMiddlePath(OccWire, ProxyMiddlePath):
reference = set_default( # type: ignore
"https://dev.opencascade.org/doc/refman/html/"
"class_b_rep_offset_a_p_i___middle_path.html"
)
# ------------------------------------------------------------------------
# 2D Parameters
# ------------------------------------------------------------------------
bilo = Typed(BRepMAT2d_BisectingLocus)
link = Typed(BRepMAT2d_LinkTopoBilo)
explorer = Typed(BRepMAT2d_Explorer)
graph = Dict(TopoDS_Edge, MAT_Arc)
face = Typed(TopoDS_Face)
join_types = {
"arc": GeomAbs_Arc,
"tangent": GeomAbs_Tangent,
"intersection": GeomAbs_Intersection,
}
def update_shape(self, change: Optional[dict[str, Any]] = None):
d = self.declaration
n = len(d.shapes)
if n in (1, 3):
args = d.shapes
elif n == 2:
child = self.get_first_child()
args = [child.shape] + d.shapes
else:
args = [c.shape for c in self.children()]
for i, s in enumerate(args):
if isinstance(s, Shape):
args[i] = s.proxy.shape
first_shape = Topology.cast_shape(args[0])
if isinstance(first_shape, (TopoDS_Wire, TopoDS_Face)):
self.middle_path_2d(first_shape)
else:
self.middle_path_3d(args)
def middle_path_3d(self, args: list):
for i, s in enumerate(args[:]):
if isinstance(s, TopoDS_Edge):
args[i] = BRepBuilderAPI_MakeWire(s).Wire()
builder = BRepOffsetAPI_MiddlePath(*args)
shape = Topology.cast_shape(builder.Shape())
self.curve = BRepAdaptor_CompCurve(shape)
self.shape = shape
def middle_path_2d(self, shape: TopoDS_Shape):
d = self.declaration
if isinstance(shape, TopoDS_Wire):
face = BRepBuilderAPI_MakeFace(shape).Face()
else:
face = shape
self.face = face
explorer = self.explorer = BRepMAT2d_Explorer(face)
bilo = self.bilo = BRepMAT2d_BisectingLocus()
is_open = False
join_type = self.join_types[d.join_type]
line_index = 1
side = MAT_Left
bilo.Compute(explorer, line_index, side, join_type, is_open)
if not bilo.IsDone():
raise RuntimeError(f"Could not build middle path {d}")
link = self.link = BRepMAT2d_LinkTopoBilo()
link.Perform(explorer, bilo)
graph = bilo.Graph()
surf = BRep_Tool.Surface_(face)
touching = d.mode in ("normal", "no-trim")
tol = d.tolerance
for j in range(1, graph.NumberOfArcs() + 1):
arc = graph.Arc(j)
if not touching:
if arc.FirstNode().Distance() < tol:
continue
if arc.SecondNode().Distance() < tol:
continue
bisector, rev = bilo.GeomBis(arc, False)
curve = bisector.Value()
# Use the basis curve or the type information is lost
t1, t2 = curve.FirstParameter(), curve.LastParameter()
n1, n2 = arc.FirstNode(), arc.SecondNode()
if n1.Infinite() or n2.Infinite():
edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge()
else:
edge = BRepBuilderAPI_MakeEdge(curve, surf, t1, t2).Edge()
self.graph[edge] = arc
builder = BRep_Builder()
shape = TopoDS_Compound()
builder.MakeCompound(shape)
for e in self.graph.keys():
builder.Add(shape, e)
# Create 3d curves
# BRepLib.BuildCurves3d_(shape)
self.shape = shape
def set_shapes(self, shapes: list[Shape]):
self.update_shape()
def set_mode(self, mode: str):
self.update_shape()
def set_join_type(self, join_type: str):
self.update_shape()