def adapt_edge_to_curve(edg): ''' returns a curve adaptor from an edge @param edg: TopoDS_Edge ''' return BRepAdaptor_Curve(edg)
class Edge(TopoDS_Edge, BaseObject): def __init__(self, edge): assert isinstance( edge, TopoDS_Edge), 'need a TopoDS_Edge, got a %s' % edge.__class__ assert not edge.IsNull() super(Edge, self).__init__() BaseObject.__init__(self, 'edge') # we need to copy the base shape using the following three # lines assert self.IsNull() self.TShape(edge.TShape()) self.Location(edge.Location()) self.Orientation(edge.Orientation()) assert not self.IsNull() # tracking state self._local_properties_init = False self._curvature_init = False self._geometry_lookup_init = False self._curve_handle = None self._curve = None self._adaptor = None self._adaptor_handle = None # instantiating cooperative classes # cooperative classes are distinct through CamelCaps from # normal method -> pep8 self.DiffGeom = DiffGeomCurve(self) self.Intersect = IntersectCurve(self) self.Construct = ConstructFromCurve(self) # GeomLProp object self._curvature = None def is_closed(self): return self.adaptor.IsClosed() def is_periodic(self): return self.adaptor.IsPeriodic() def is_rational(self): return self.adaptor.IsRational() def continuity(self): return self.adaptor.Continuity def degree(self): if 'line' in self.type: return 1 elif 'curve' in self.type: return self.adaptor.Degree() else: # hyperbola, parabola, circle return 2 def nb_knots(self): return self.adaptor.NbKnots() def nb_poles(self): return self.adaptor.NbPoles() @property def curve(self): if self._curve is not None and not self.is_dirty: pass else: self._curve_handle = BRep_Tool().Curve(self)[0] self._curve = self._curve_handle.GetObject() return self._curve @property def curve_handle(self): if self._curve_handle is not None and not self.is_dirty: return self._curve_handle else: return None @property def adaptor(self): if self._adaptor is not None and not self.is_dirty: pass else: self._adaptor = BRepAdaptor_Curve(self) self._adaptor_handle = BRepAdaptor_HCurve(self._adaptor) return self._adaptor @property def adaptor_handle(self): if self._adaptor_handle is not None and not self.is_dirty: pass else: self.adaptor return self._adaptor_handle @property def geom_curve_handle(self): """ :return: Handle_Geom_Curve adapted from `self` """ if self._adaptor_handle is not None and not self.is_dirty: return self._adaptor.Curve().Curve() else: return None @property def type(self): return geom_lut[self.adaptor.Curve().GetType()] def pcurve(self, face): """ computes the 2d parametric spline that lies on the surface of the face :return: Geom2d_Curve, u, v """ crv, u, v = BRep_Tool().CurveOnSurface(self, face) return crv.GetObject(), u, v def _local_properties(self): self._lprops_curve_tool = GeomLProp_CurveTool() self._local_properties_init = True def domain(self): '''returns the u,v domain of the curve''' return self.adaptor.FirstParameter(), self.adaptor.LastParameter() #=========================================================================== # Curve.GlobalProperties #=========================================================================== def length(self, lbound=None, ubound=None, tolerance=1e-5): '''returns the curve length if either lbound | ubound | both are given, than the length of the curve will be measured over that interval ''' _min, _max = self.domain() if _min < self.adaptor.FirstParameter(): raise ValueError( 'the lbound argument is lower than the first parameter of the curve: %s ' % (self.adaptor.FirstParameter())) if _max > self.adaptor.LastParameter(): raise ValueError( 'the ubound argument is greater than the last parameter of the curve: %s ' % (self.adaptor.LastParameter())) lbound = _min if lbound is None else lbound ubound = _max if ubound is None else ubound return GCPnts_AbscissaPoint().Length(self.adaptor, lbound, ubound, tolerance) #=========================================================================== # Curve.modify #=========================================================================== def trim(self, lbound, ubound): ''' trim the curve @param lbound: @param ubound: ''' a, b = sorted([lbound, ubound]) tr = Geom_TrimmedCurve(self.adaptor.Curve().Curve(), a, b).GetHandle() return Edge(make_edge(tr)) def extend_by_point(self, pnt, degree=3, beginning=True): '''extends the curve to point does not extend if the degree of self.curve > 3 @param pnt: @param degree: @param beginning: ''' if self.degree > 3: raise ValueError('to extend you self.curve should be <= 3, is %s' % (self.degree)) return geomlib.ExtendCurveToPoint(self.curve, pnt, degree, beginning) #=========================================================================== # Curve. #=========================================================================== def closest(self, other): return minimum_distance(self, other) def project_vertex(self, pnt_or_vertex): ''' returns the closest orthogonal project on `pnt` on edge ''' if isinstance(pnt_or_vertex, TopoDS_Vertex): pnt_or_vertex = vertex2pnt(pnt_or_vertex) poc = GeomAPI_ProjectPointOnCurve(pnt_or_vertex, self.curve_handle) return poc.LowerDistanceParameter(), poc.NearestPoint() def distance_on_curve(self, distance, close_parameter, estimate_parameter): '''returns the parameter if there is a parameter on the curve with a distance length from u raises OutOfBoundary if no such parameter exists ''' gcpa = GCPnts_AbscissaPoint(self.adaptor, distance, close_parameter, estimate_parameter, 1e-5) with assert_isdone(gcpa, 'couldnt compute distance on curve'): return gcpa.Parameter() def mid_point(self): """ :return: the parameter at the mid point of the curve, and its corresponding gp_Pnt """ _min, _max = self.domain() _mid = (_min + _max) / 2. return _mid, self.adaptor.Value(_mid) def divide_by_number_of_points(self, n_pts, lbound=None, ubound=None): '''returns a nested list of parameters and points on the edge at the requested interval [(param, gp_Pnt),...] ''' _lbound, _ubound = self.domain() if lbound: _lbound = lbound elif ubound: _ubound = ubound # minimally two points or a Standard_ConstructionError is raised if n_pts <= 1: n_pts = 2 try: npts = GCPnts_UniformAbscissa(self.adaptor, n_pts, _lbound, _ubound) except: print("Warning : GCPnts_UniformAbscissa failed") if npts.IsDone(): tmp = [] for i in xrange(1, npts.NbPoints() + 1): param = npts.Parameter(i) pnt = self.adaptor.Value(param) tmp.append((param, pnt)) return tmp else: return None def __eq__(self, other): if hasattr(other, 'topo'): return self.IsEqual(other) else: return self.IsEqual(other) def __ne__(self, other): return not self.__eq__(other) def first_vertex(self): return topexp.FirstVertex(self) def last_vertex(self): return topexp.LastVertex(self) def common_vertex(self, edge): vert = TopoDS_Vertex() if topexp.CommonVertex(self, edge, vert): return vert else: return False def as_vec(self): if self.is_line(): first, last = map( vertex2pnt, [self.first_vertex(), self.last_vertex()]) return gp_Vec(first, last) else: raise ValueError( "edge is not a line, hence no meaningful vector can be returned" ) #=========================================================================== # Curve. #=========================================================================== def parameter_to_point(self, u): '''returns the coordinate at parameter u ''' return self.adaptor.Value(u) def fix_continuity(self, continuity): """ splits an edge to achieve a level of continuity :param continuity: GeomAbs_C* """ return fix_continuity(self, continuity) def continuity_from_faces(self, f1, f2): return BRep_Tool_Continuity(self, f1, f2) #=========================================================================== # Curve. #=========================================================================== def is_line(self): '''checks if the curve is planar ''' if self.nb_knots() == 2 and self.nb_poles() == 2: return True else: return False def is_seam(self, face): """ :return: True if the edge has two pcurves on one surface ( in the case of a sphere for example... ) """ sae = ShapeAnalysis_Edge() return sae.IsSeam(self, face) def is_edge_on_face(self, face): '''checks whether curve lies on a surface or a face ''' return ShapeAnalysis_Edge().HasPCurve(self, face) #=========================================================================== # Curve.graphic #=========================================================================== def show(self): ''' poles, knots, should render all slightly different. here's how... http://www.opencascade.org/org/forum/thread_1125/ ''' super(Edge, self).show()