def followShape(self, shape, finish=False): "follows this shape" if shape.ShapeType() == TopAbs.TopAbs_WIRE: for m in self.followWire(topoDS.Wire(shape)): yield m elif shape.ShapeType() == TopAbs.TopAbs_EDGE: for m in self.followEdge(topoDS.Edge(shape)): yield m elif shape.ShapeType() == TopAbs.TopAbs_COMPOUND: bb = TopExp.TopExp_Explorer() bb.Init(shape, TopAbs.TopAbs_WIRE) while bb.More(): w = topoDS.Wire(bb.Current()) for m in self.followWire(wire): yield m bb.Next() bb.ReInit() else: "unknown shape" pass #flush any last remaining move if finish: t = self._fetchPendingMove() if t: yield t
def preview(self, input, direction): if self.step == 0: from OCC import TopExp, TopAbs, BRep exp = TopExp.TopExp_Explorer(input, TopAbs.TopAbs_VERTEX) v1 = TopoDS.topods_Vertex(exp.Current()) v1_ = BRep.BRep_Tool.Pnt(TopoDS.TopoDS_Vertex(v1)) # TODO: 0.3: finish: automatically determine orthogonal direction # from # input self.previous_data = [input, direction] try: wire = TopoDS.TopoDS_Wire(input) print(dir(wire)) except: pass return () elif self.step == 1: object, dir_ = self.previous_data[:] dirvec = [0, 0, 0] dirvec[dir_] = input[dir_] if dirvec == [0, 0, 0]: raise InvalidInputException self.remove = [self.previous_data[0]] self._final = [BRepPrimAPI.BRepPrimAPI_MakePrism( object, gp.gp_Vec(*dirvec)).Shape()] return self._final
def offsetWireList(wireList, offsetAmount): if len(wireList) == 0: print "Warning: zero wires in the shape-- skipping" return [] bo = BRepOffsetAPI.BRepOffsetAPI_MakeOffset() for w in wireList: bo.AddWire(w) bo.Perform(offsetAmount, 0.0) #if this crashes, try using a small non zero number for the last argument if not bo.IsDone(): print "Warning: offset not computed!" return None else: #make sure to return a list of wires also, since we got one in returnWires = [] shape = bo.Shape() if shape.ShapeType() == TopAbs.TopAbs_WIRE: returnWires.append(cast(shape)) elif shape.ShapeType() == TopAbs.TopAbs_COMPOUND: bb = TopExp.TopExp_Explorer() bb.Init(shape, TopAbs.TopAbs_WIRE) while bb.More(): w = topoDS.wire(bb.Current()) returnWires.append(cast(w)) bb.Next() bb.ReInit() return returnWires
def makeWiresFromOffsetShape(shape): "get all the wires from the offset shape" resultWires = TopTools.TopTools_HSequenceOfShape() if shape.ShapeType() == TopAbs.TopAbs_WIRE: #log.info( "offset result is a wire" ); wire = topoDS.Wire(shape) #resultWires.append(wire); resultWires.Append(wire) elif shape.ShapeType() == TopAbs.TopAbs_COMPOUND: #log.info( "offset result is a compound"); bb = TopExp.TopExp_Explorer() bb.Init(shape, TopAbs.TopAbs_WIRE) while bb.More(): w = topoDS.Wire(bb.Current()) #resultWires.append(w); resultWires.Append(w) # #debugShape(w); bb.Next() bb.ReInit() return resultWires
def loopWire(w): topexp = TopExp.TopExp_Explorer() topexp.Init(w, TopAbs.TopAbs_EDGE) edges = [] while topexp.More(): currentEdge = Wrappers.cast(topexp.Current()) edges.append(currentEdge) topexp.Next() return edges
def edges(self): "a generator for edges" bb = TopExp.TopExp_Explorer() bb.Init(self.wire, TopAbs.TopAbs_EDGE) while bb.More(): e = topoDS.edge(bb.Current()) yield e bb.Next() bb.ReInit()
def loopWire2(w): edges = TopTools.TopTools_HSequenceOfShape() topexp = TopExp.TopExp_Explorer() topexp.Init(w, TopAbs.TopAbs_EDGE) while topexp.More(): #currentEdge = Wrappers.cast(); edges.Append(topexp.Current()) topexp.Next() return edges
def _makeSlice(self, shapeToSlice, zLevel): s = Slice() #change if layers are variable thickness s.sliceHeight = self.sliceHeight s.zLevel = zLevel #make a cutting plane p = gp.gp_Pnt(0, 0, zLevel) origin = gp.gp_Pnt(0, 0, zLevel - 1) csys = gp.gp_Ax3(p, gp.gp().DZ()) cuttingPlane = gp.gp_Pln(csys) bff = BRepBuilderAPI.BRepBuilderAPI_MakeFace(cuttingPlane) face = bff.Face() #odd, a halfspace is faster than a box? hs = BRepPrimAPI.BRepPrimAPI_MakeHalfSpace(face, origin) hs.Build() halfspace = hs.Solid() #make the cut bc = BRepAlgoAPI.BRepAlgoAPI_Cut(shapeToSlice, halfspace) cutShape = bc.Shape() #search the shape for faces at the specified zlevel texp = TopExp.TopExp_Explorer() texp.Init(cutShape, TopAbs.TopAbs_FACE) foundFace = False while (texp.More()): face = ts.Face(texp.Current()) if self._isAtZLevel(zLevel, face): foundFace = True logging.debug("Face is at zlevel" + str(zLevel)) s.addFace(face, self.saveSliceFaces) texp.Next() #free memory face.Nullify() bc.Destroy() texp.Clear() texp.Destroy() if not foundFace: logging.warn("No faces found after slicing at zLevel " + str(zLevel) + " !. Skipping This layer completely") return None else: return s
def subshapes(shape, shapetype): """Return a list of subshapes of the specified type""" # TODO: Return a generator instead of a list convertor = _convertors[shapetype] shapelist = [] exp = TopExp.TopExp_Explorer(shape, shapetype) while exp.More(): v = exp.Current() t = type(v) i = id(v) # v2 = convertor(exp.Current()) k = get_key(_convertors, t) shapelist.append(v) exp.Next() return shapelist
def boundarypixmapFromFace(face): """ creates a pixel map containing only the boundaries of the object. the shape is approximated with straight lines, and vertices are marked with different values to help re-construct the lines later on. Some c++ optimizaion woudl really speed this up. """ PIXEL = 0.02 DEFLECTION = PIXEL / 4.0 #get bounding box (xMin, yMin, zMin, xMax, yMax, zMax) = boundingBox([face]) #make pixmap pixmap = pixmaptest.pixmap((xMin, yMin), (xMax, yMax), PIXEL) #approximate each wire with a set of segments bb = TopExp.TopExp_Explorer() bb.Init(face, TopAbs.TopAbs_WIRE) while bb.More(): #print "plotting wire" w = Wrappers.Wire(Wrappers.cast(bb.Current())) #divide the edge into discrete segments lastPnt = None for e in w.edges2(): #for each edge, set vertices, and compute points on the edge ew = Wrappers.Edge(e) lastPnt = None for pnt in ew.discretePoints(DEFLECTION): pixmap.set(tP(pnt), 2) #plot the line if lastPnt != None: pixmap.drawLine(tP(lastPnt), tP(pnt)) lastPnt = pnt bb.Next() return pixmap
def addFace(self, face, saveFaceCopy=True): if saveFaceCopy: copier = BRepBuilderAPI.BRepBuilderAPI_Copy(face) self.faces.append(copier.Shape()) copier.Delete() ow = brt.OuterWire(face) logging.debug("Adding OuterWire...") self.addWire(ow) logging.debug("Adding Other Wires...") #now get the other wires te = TopExp.TopExp_Explorer() te.Init(face, TopAbs.TopAbs_WIRE) while te.More(): w = ts.Wire(te.Current()) if not w.IsSame(ow): self.addWire(w) te.Next() te.Clear() te.Destroy()
def checkMinimumDistanceForOffset(offset, resolution): "PERFORMANCE INTENSIVE!!!!" "check an offset shape to make sure that it does not overlap too closely" "this consists of making sure that none of the wires are too close to each other" "and that no individual wires have edges too close together" log.info("Checking this offset for minimum distances") te = TopExp.TopExp_Explorer() resultWires = TopTools.TopTools_HSequenceOfShape() te.Init(offset, TopAbs.TopAbs_WIRE) allPoints = [] while te.More(): w = ts.Wire(te.Current()) wr = Wire(w) resultWires.Append(w) allPoints.extend(pointsFromWire(w, resolution * 3)) #for p in wr.discretePoints(resolution/2): # debugShape(make_vertex(p)); # allPoints.append(p); te.Next() te.ReInit() log.info("There are %d wires, and %d points" % (resultWires.Length(), len(allPoints))) #cool trick here: list all permutations of these points "this is where we could probably really improve this algorithm" for (p1, p2) in list(itertools.combinations(allPoints, 2)): d = p1.Distance(p2) if d < resolution: log.warn("Distance %0.5f is less than expected value" % d) return False #else: #log.info("Computed distance = %0.5f" % d ); return True
def isLocalMinimum(wire, vertex): """ The vertex is assumed to exist on the wire. The method determines if the vertex is situated such that the location is a local minimum or maxiumum on the boundary. The method is needed for teh scanline algorithm: in the case that a filling line intersects a boundary at a vertex, the vertex counts as boundary if it does, and does not count otherwise. This method is slow, hopefully it is very rarely used. TODO: right now, this assumes that scanlines are always oriented parallel with the x axis ( horizontal ). this algorithm needs a direction vector in order to be generalized for the situation where the fill lines can be oriented in any direction """ #print "Determining if the specified point is a local minimum or not..." topexp = TopExp.TopExp_Explorer() topexp.Init(wire, TopAbs.TopAbs_EDGE) te = TopExp.TopExp() #find two edges that contain the vertex edges = [] while topexp.More(): e = cast(topexp.Current()) if te.LastVertex(e).__hash__() == vertex.__hash__(): #print "found a last vertex" edges.append(e) if te.FirstVertex(e).__hash__() == vertex.__hash__(): edges.append(e) #print "found a first vertex" topexp.Next() assert len(edges) == 2 #move a little away from the vertex in each direction ALITTLEBIT = d1 = d2 = 0.01 e1 = edges[0] e2 = edges[1] p1 = brepTool.Parameter(vertex, e1) p2 = brepTool.Parameter(vertex, e2) (bp1, ep1) = brepTool.Range(e1) (bp2, ep2) = brepTool.Range(e2) if p1 == ep1: d1 = d1 * (-1) if p2 == ep2: d2 = d2 * (-1) pnt1 = pointAtParameter(e1, p1 + d1) pnt2 = pointAtParameter(e2, p2 + d2) #TestDisplay.display.showShape(vertex); #TestDisplay.display.showShape(wire); #TestDisplay.display.showShape(make_vertex(pnt1)); #TestDisplay.display.showShape(make_vertex(pnt2)); #TestDisplay.display.run(); #finally! compare y values. this is the part that needs to change later #to account for rotated filling lines y = brepTool.Pnt(vertex).Y() dy1 = pnt1.Y() - y dy2 = pnt2.Y() - y if dy1 * dy2 > 0: #print "local min/max detected." return True else: #print "vertex is not a local min/max" return False
def splitWire(wire,ipoints): """ ipoints is a list of intersection points. returns a list of wires inside the intersection point this method must also work for a 'wire' consisting of a single edge. more than one intersection point can be on each edge, but all of the ipoints are expected to be on edges in the provided wire. BASELINE PERFORMANCE: 11 ms per call for splitwiretest returns a list of lists. each element in the top list is a chain of connected edges. each element in that list is an edge ( or part of an edge ) so, for example, suppose you compute a wire that has 100 edges, and there are 4 intersection points. in this case, there will be two elements returned, and each element would contain a list of edges between the two segments. ---E1---+---E2---+-X-E3---+---E4--X--+---E5--- will return [ [E1,E2], [ E3,E4 ] ] """ topexp = TopExp.TopExp_Explorer(); topexp.Init(wire,TopAbs.TopAbs_EDGE); #sort intersection points by ascending X location ix = sorted(ipoints,key = lambda p: p.point.X() ); edgeList = []; assert (len(ipoints) % 2) == 0; for i in range(0,len(ipoints),2): #process intersection points in pairs #TODO: this could be done more cleanly with a pairwise iterator currentIntersection = ix[i]; nextIntersection = ix[i+1]; #if they are on the same edge, simply add a trimmed edge. #in this case, if currentIntersection.hash == nextIntersection.hash: edgeList.append ( [ Wrappers.trimmedEdge(currentIntersection.edge, currentIntersection.param, nextIntersection.param ) ] ); else: #intersections are not on the same edge. #add the fraction of the first edge (bp,ep) = brepTool.Range(currentIntersection.edge); edges = []; #print "adding piece of start edge." edges.append( Wrappers.trimmedEdge(currentIntersection.edge,currentIntersection.param, ep)); #pick up whole edges between the first intersection and the next one #loop till current edge is same as current intersection while topexp.Current().__hash__() != currentIntersection.hash: topexp.Next(); #advance to next edge topexp.Next(); #add edges till current edge is same as next intersection #most of the performance suckage is happening here, with gc associated with these #edge objects. If that gets fixed, we'll get a huge speed boost. about 33% of total time is saved. while topexp.Current().__hash__() != nextIntersection.hash: edge = Wrappers.cast(topexp.Current() ); edges.append(edge); #print "adding middle edge" topexp.Next(); #add the last edge (bp,ep) = brepTool.Range(nextIntersection.edge); edges.append( Wrappers.trimmedEdge(nextIntersection.edge,bp,nextIntersection.param)); #print "adding last piece of edge" edgeList.append(edges); return edgeList;
from OCC import TopExp, BRepPrimAPI, TopAbs, TopoDS box = BRepPrimAPI.BRepPrimAPI_MakeBox(10., 20., 30.) ex = TopExp.TopExp_Explorer(box.Shape(), TopAbs.TopAbs_EDGE) results = [] while ex.More(): shape = TopoDS.TopoDS().Edge(ex.Current()) print "is null?", bool(shape.IsNull()) results.append(shape) ex.Next() ex.ReInit() for edge in results: print "null now?", bool(edge.IsNull())
def splitWire(wire, ipoints): """ ipoints is a list of intersection points. returns a list of wires inside the intersection point BASELINE PERFORMANCE: 11 ms per call for splitwiretest """ #load original wire #we make an important assumption that the wire is organized from #left to right or from right to left, and starts outside the boundaries. #this allows the scanline algorithm to define which segments are 'inside' #wr = Wrappers.Wire(wire); #assume edges are in ascending x order also #very interesting OCC weird thing: topexp is much faster than wireexplorer topexp = TopExp.TopExp_Explorer(); topexp.Init(wire,TopAbs.TopAbs_EDGE); #sort intersection points by ascending X location ix = sorted(ipoints,key = lambda p: p.point.X() ); inside = False; edges = []; #a list of edges for the current wire. iEdge = 0; iIntersection=0; #TODO: handle odd number of intersections #the last parameter on the current edge. #it is either the first parameter on the current edge, #or the last intersection point on the edge. currentEdge = Wrappers.cast(topexp.Current()); currentEdgeBounds = brepTool.Range(currentEdge); startParam = currentEdgeBounds[0]; #print "handling %d intersections" % len(ix) while iIntersection < len(ix) and ( topexp.More() ) : currentIntersection = ix[iIntersection]; if hashE(currentEdge) == currentIntersection.hash: #current edge matches intersection point if inside: #transition to outside: add this part edge currentEdgeBounds = brepTool.Range(currentEdge); newEdge = Wrappers.trimmedEdge(currentEdge,startParam,currentIntersection.param); #TestDisplay.display.showShape(newEdge); edges.append(newEdge); #move to next point, store last intersection iIntersection += 1; startParam = currentIntersection.param; inside = not inside; else: #edges do not match if inside: currentEdgeBounds = brepTool.Range(currentEdge); if startParam == currentEdgeBounds[0]: edges.append(currentEdge); else: newEdge = Wrappers.trimmedEdge(currentEdge,startParam, currentEdgeBounds[1] ); edges.append(newEdge); #move to next edge topexp.Next(); currentEdge = Wrappers.cast(topexp.Current()); startParam = currentEdgeBounds[0]; #print "returning %d edges" % len(edges) return edges;
##Copyright 2008 Jelle Feringa ([email protected])
# -*- coding: iso-8859-1 -*-
## X install guide ## X remove unneed dumpTopology and shapeDescription ## add 2d per-slice view on select of slice ## X add ability to easily select slice thickness ## add separate display for original object and slices ## X sew faces from crappy stl files into single faces somehow ## X remove reference to profile import ##### #utility class instances #available to all methods ##### brt = BRepTools.BRepTools() btool = BRep.BRep_Tool() ts = TopoDS.TopoDS() topexp = TopExp.TopExp() texp = TopExp.TopExp_Explorer() """ Utility class to provide timing information """ class Timer: def __init__(self): self.startTime = time.time() self.startAscTime = time.asctime() def start(self): return self.startTime def elapsed(self):