def TestDivideEdge(): #lines are parameterized between 0 and line length edge = edgeFromTwoPoints(gp.gp_Pnt(0, 0, 0), gp.gp_Pnt(2, 2, 0)) (handleCurve, p1, p2) = brepTool.Curve(edge) #p1=0, #p2=2.828 print p1, p2 totalLen = (p2 - p1) display.DisplayColoredShape(edge, 'BLUE') #divide the edge into two edges, split at 0.25 units from param=1.414, with a gap of 0.1 between them edges = divideEdgeAtParam(edge, 1.414, 0.25, 0.1) #divide the edge into two edges assert (len(edges) == 2) (e1, e2) = (edges[0], edges[1]) (hc, q1, q2) = brepTool.Curve(e1) print q1, q2 (hc, q1, q2) = brepTool.Curve(e2) print q1, q2 print Wrappers.Edge(e1).distanceBetweenEnds() assert (abs(Wrappers.Edge(e1).distanceBetweenEnds() - (1.414 + 0.25)) < 0.000001) assert (abs( Wrappers.Edge(e2).distanceBetweenEnds() - (totalLen - 1.414 - 0.25 - 0.1)) < 0.0000001) display.DisplayColoredShape(edges, 'RED') edges = divideEdgeAtParam(edge, 1.414, 2.5, 0.1) #should return one edge of length 0.1 less than total assert (len(edges) == 1) assert ( abs(Wrappers.Edge(edges[0]).distanceBetweenEnds() - (totalLen - 0.1)) < 0.0000001) display.DisplayColoredShape(edges, 'GREEN')
def splitPerfTest(): "make a long wire of lots of edges" """ performance of the wire split routine is surprisingly bad! """ WIDTH=0.1 edges = []; #trick here. after building a wire, the edges change identity. #evidently, BRepBuilder_MakeWire makes copies of the underliying edges. h = hexagonlib.Hexagon(2.0,0 ); wirelist = h.makeHexForBoundingBox((0,0,0), (100,100,0)); w = wirelist[0]; ee = Wrappers.Wire(w).edgesAsList(); #compute two intersections e1 = Wrappers.Edge(ee[5]); e2 = Wrappers.Edge(ee[55]); e1p = (e1.lastParameter - e1.firstParameter )/ 2; e2p = (e2.lastParameter - e2.firstParameter )/ 2; p1 = PointOnAnEdge(e1.edge,e1p ,e1.pointAtParameter(e1p)); p2 = PointOnAnEdge(e2.edge,e2p ,e2.pointAtParameter(e2p)); t = Util.Timer(); ee = []; for i in range(1,1000): ee = splitWire(w,[p2,p1]); assert len(ee) == 1; print "Elapsed for 1000splits:",t.finishedString();
def testSplitWire1(): """ Test split wire function. there are two main cases: wires with intersection on different edges, and a wire with a single edge split in many places """ #case 1: a single edge with lots of intersections along its length e = Wrappers.edgeFromTwoPoints( gp.gp_Pnt(0,0,0),gp.gp_Pnt(5,0,0)); w = Wrappers.wireFromEdges([e]); #out of order on purpose p1 = PointOnAnEdge(e,1.0,gp.gp_Pnt(1.0,0,0)); p3 = PointOnAnEdge(e,3.0,gp.gp_Pnt(3.0,0,0)); p2 = PointOnAnEdge(e,2.0,gp.gp_Pnt(2.0,0,0)); p4 = PointOnAnEdge(e,4.0,gp.gp_Pnt(4.0,0,0)); ee = splitWire(w,[p1,p3,p2,p4] ); assert len(ee) == 2; length = 0; for e in ee: ew = Wrappers.Edge(e[0]); length += ew.distanceBetweenEnds(); TestDisplay.display.showShape(e); assert length == 2.0;
def testSplitWire2(): "intersections on different edges. one edge completely inside" e1 = Wrappers.edgeFromTwoPoints(gp.gp_Pnt(0,0,0),gp.gp_Pnt(2,0,0)); e2 = Wrappers.edgeFromTwoPoints(gp.gp_Pnt(2,0,0),gp.gp_Pnt(5,0,0)); e3 = Wrappers.edgeFromTwoPoints(gp.gp_Pnt(5,0,0),gp.gp_Pnt(6,0,0)); #trick here. after building a wire, the edges change identity. #evidently, BRepBuilder_MakeWire makes copies of the underliying edges. w = Wrappers.wireFromEdges([e1,e2,e3]); ee = Wrappers.Wire(w).edgesAsList(); #print "Original Edges: %d %d %d " % ( ee[0].__hash__(),ee[1].__hash__(),ee[2].__hash__()); p1 = PointOnAnEdge(ee[0],1.0,gp.gp_Pnt(1.0,0,0)); p2 = PointOnAnEdge(ee[2],0.5,gp.gp_Pnt(5.0,0,0)); ee = splitWire(w,[p2,p1]); assert len(ee) == 1; length = 0; for e in ee[0]: ew = Wrappers.Edge(e); length += ew.distanceBetweenEnds(); TestDisplay.display.showShape(e); #print "length=%0.3f" % length; assert length == 4.5;
def divideEdge(self,edge,param): """ split the edge at the provided parameter, creating two new edge nodes. update internal structures accordingly. """ original = self.findEdge(edge,param); ew = Wrappers.Edge(edge); if original == None: raise ValueError,"Could not find edge having parameter %0.3f" % (param); #param must be between the bounds on the original edge assert param >= original.p1 and param <= original.p2; #compute nodes on either end. n1 = tP(original.ew.firstPoint); n2 = tP(original.ew.lastPoint); #add new node and edges n3 = tP(ew.pointAtParameter(param)); newNode1 = EdgeSegment(ew,original.p1,param,original.type); newNode2 = EdgeSegment(ew,param,original.p2, original.type ); self.addEdgeSegment(newNode1); self.addEdgeSegment(newNode2); #delete the original self.removeEdge(original); return [newNode1,newNode2];
def addEdge(self,edge,type): "adds an edgeto the structure, using the endpoints of the edge as the nodes" "this is equivalent to adding an edgesegment that spans the full edge" ew = Wrappers.Edge(edge); newEdge = EdgeSegment(ew,ew.firstParameter,ew.lastParameter,type); self.addEdgeSegment(newEdge);
def addWire(self, wire, type): "add all the edges of a wire. They will be connected together." "type is the node type for each edge" #for finding an edge node wr = Wrappers.Wire(wire) self.edgeSeq = wr.edgesAsSequence() firstNode = None lastNode = None last = None for i in range(1, self.edgeSeq.Length() + 1): edge = Wrappers.cast(self.edgeSeq.Value(i)) te = Wrappers.Edge(edge) newnode = EdgeNode(edge, te.firstParameter, te.lastParameter, type) self.addNode(newnode) if last: newnode.addPrev(newnode) last.addNext(newnode) last = newnode if i == 1: firstNode = newnode if i == self.edgeSeq.Length(): lastNode = newnode #link last and first edge if the wire is closed if wire.Closed(): lastNode.addNext(firstNode) firstNode.addPrev(lastNode)
def normalEdgesAlongEdge(edge, length , interval): "compute an edge having length at the specified parameter on the supplied curve:" edgeList = []; ew = Wrappers.Edge(edge); zDir = gp.gp().DZ(); zVec = gp.gp_Vec(zDir); curve = ew.curve; pStart = ew.firstParameter; pEnd = ew.lastParameter; for p in Wrappers.frange6(pStart,pEnd,interval): tangent = gp.gp_Vec(); tanpoint = gp.gp_Pnt(); curve.D1(p,tanpoint,tangent ); axis = gp.gp_Ax1(tanpoint, gp.gp_Dir(tangent.Crossed(zVec) ) ); line = Geom.Geom_Line(axis ); e = BRepBuilderAPI.BRepBuilderAPI_MakeEdge(line.GetHandle(),0, length).Edge(); if e: edgeList.append(e); return edgeList;
def __init__(self, edge, p1, p2, type): "edge is a ref to an edge, with the beginning and ending parameters" "for the underlying curve" self.edge = edge self.ew = Wrappers.Edge(edge) self.p1 = p1 self.p2 = p2 self.type = type
def tuplesFromWire(wire, deflection): "return a list of tuples from a wire" list = [] ww = Wrappers.Wire(wire) for e in ww.edges2(): #for each edge, set vertices, and compute points on the edge ew = Wrappers.Edge(e) for pnt in ew.discretePoints(deflection): list.append(tP(pnt)) return list
def makeEdgeIndicator(edge): "makes an indicator showing which way the edge goes" ew = Wrappers.Edge(edge) fp = ew.firstParameter lp = ew.lastParameter if ew.reversed: p = fp + ((lp - fp) * 1 / 5) else: p = fp + ((lp - fp) * 4 / 5) midPnt = ew.curve.Value(p) return Wrappers.make_vertex(midPnt)
def splitPerfTest(): "make a long wire of lots of edges" """ performance of the wire split routine is surprisingly bad! """ WIDTH=0.1 edges = []; #trick here. after building a wire, the edges change identity. #evidently, BRepBuilder_MakeWire makes copies of the underliying edges. h = hexagonlib.Hexagon(2.0,0 ); wirelist = h.makeHexForBoundingBox((0,0,0), (100,100,0)); w = wirelist[0]; ee = Wrappers.Wire(w).edgesAsList(); TestDisplay.display.showShape(w); #compute two intersections e1 = Wrappers.Edge(ee[5]); e2 = Wrappers.Edge(ee[55]); e1p = (e1.lastParameter - e1.firstParameter )/ 2; e2p = (e2.lastParameter - e2.firstParameter )/ 2; p1 = PointOnAnEdge(e1.edge,e1p ,e1.pointAtParameter(e1p)); p2 = PointOnAnEdge(e2.edge,e2p ,e2.pointAtParameter(e2p)); TestDisplay.display.showShape( Wrappers.make_vertex(p1.point)); TestDisplay.display.showShape( Wrappers.make_vertex(p2.point)); #cProfile.runctx('for i in range(1,20): ee=splitWire(w,[p2,p1])', globals(), locals(), filename="slicer.prof") #p = pstats.Stats('slicer.prof') #p.sort_stats('cum') #p.print_stats(.98); t = Wrappers.Timer(); ee = []; for i in range(1,1000): ee = splitWire(w,[p2,p1]); assert len(ee) == 1; print "Elapsed for 1000splits:",t.finishedString();
def splitPerfTest(): "make a long wire of lots of edges" """ performance of the wire split routine is surprisingly bad! """ WIDTH=0.1 edges = []; for i in range(1,50): e = Wrappers.edgeFromTwoPoints(gp.gp_Pnt(i*WIDTH,0,0),gp.gp_Pnt((i+1)*WIDTH,0,0)) TestDisplay.display.showShape(e); edges.append(e); #trick here. after building a wire, the edges change identity. #evidently, BRepBuilder_MakeWire makes copies of the underliying edges. w = Wrappers.wireFromEdges(edges); ee = Wrappers.Wire(w).edgesAsList(); #compute two intersections e1 = Wrappers.Edge(ee[5]); e2 = Wrappers.Edge(ee[30]); e1p = (e1.lastParameter - e1.firstParameter )/ 2; e2p = (e2.lastParameter - e2.firstParameter )/ 2; p1 = PointOnAnEdge(e1.edge,e1p ,e1.pointAtParameter(e1p)); p2 = PointOnAnEdge(e2.edge,e2p ,e2.pointAtParameter(e2p)); #cProfile.runctx('for i in range(1,100): ee=splitWire(w,[p2,p1])', globals(), locals(), filename="slicer.prof") #p = pstats.Stats('slicer.prof') #p.sort_stats('time') #p.print_stats(.98); t = Wrappers.Timer(); for i in range(1,100): ee = splitWire(w,[p2,p1]); print "Elapsed for 100 splits:",t.finishedString();
def __init__(self, edge, p1, p2, type): "edge is a ref to an edge, with the beginning and ending parameters" "for the underlying curve" self.edge = edge self.ew = Wrappers.Edge(edge) self.p1 = p1 self.p2 = p2 self.type = type #next is edges reachable from the end of the edge self.next = {} #prev is the edges reachable from the beginning of the edge self.prev = {}
def __init__(self, edge, type): "edge is the OCC native edge object" "type is an edge type, either FILL or BOUND" self.type = "BOUND" self.edge = edge self.id = hashE(self.edge) self.edgeWrapper = Wrappers.Edge(edge) self.nextFill = None self.prevFill = None self.nextBoundary = None self.prevBoundary = None
def makeHexEdges(xMin, yMin, xMax, yMax, zLevel): #this can be faster by avoiding 3d wires in the first place, for for now it is ok hex = hexagonlib.Hexagon(0.35, 0.01) wires = hex.makeHexForBoundingBox((xMin, yMin, zLevel), (xMax, yMax, zLevel)) tt = [] for w in wires: ww = Wrappers.Wire(w) for e in ww.edges2(): ew = Wrappers.Edge(e) tt.append((tP(ew.firstPoint), tP(ew.lastPoint))) print "Made %d hex edges" % len(tt) return tt
def normalEdgeAtParameter(edge, param, length ): "compute an edge having length at the specified parameter on the supplied curve:" ew = Wrappers.Edge(edge); zDir = gp.gp().DZ(); zVec = gp.gp_Vec(zDir); tangent = gp.gp_Vec(); tanpoint = gp.gp_Pnt(); curve = ew.curve; curve.D1(param,tanpoint,tangent ); axis = gp.gp_Ax1(tanpoint, gp.gp_Dir(tangent.Crossed(zVec) ) ); line = Geom.Geom_Line(axis ); return BRepBuilderAPI.BRepBuilderAPI_MakeEdge(line.GetHandle(),0, length).Edge();
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 shortenEdge(edge, point, dist, shortestEdge=0.01, display=None): (handleCurve, p1, p2) = brepTool.Curve(edge) curve = GeomAdaptor.GeomAdaptor_Curve(handleCurve) pt1 = curve.Value(p1) pt2 = curve.Value(p2) if display: display.DisplayShape(make_vertex(pt1)) display.DisplayShape(make_vertex(pt2)) if pt1.Distance(point) < pt2.Distance(point): #pt1 is closer to point pstart = p1 pend = p2 else: #pt2 is closer to point pstart = p2 pend = p1 #BRepAdaptor_CompCurve if pstart > pend: dist = (-1.0) * dist #OCC NOte: # the right solution is to use this: # gcpnts = GCPnts.GCPnts_AbscissaPoint(curve,pstart,dist); # p = gcpnts.Parameter(); # BUT IT HAS A BUG when the requested distance is close to the end of the curve. # fortunately, CPnts doesnt seem to have this problem e = Wrappers.Edge(edge).length() if dist >= e: print "Warning: attempt to trim shorter than edge: shortening to smallest edge size" dist = e - shortestEdge #TODO: move constant 0.001 to new place cpnts = CPnts.CPnts_AbscissaPoint(curve, dist, pstart, 0.001) pp2 = cpnts.Parameter() (pt, vec) = D1AtPointOnCurve(curve, pp2) return (trimmedEdge(edge, pp2, pend), pt, vec)
def followEdge(self, e, finish=False): """ return a sequence of points for an edge as a generator NOTE: this algorithm leaves a potential linear move not returned, so you have to check pendingLinearMove at the end and return it if not null """ ew = Wrappers.Edge(e) log.debug("Follow Edge: " + str(ew)) #if no current point, move to the first edge. if not self.currentPoint: log.debug("No Current Point, Move to start.") "no current point defined yet." self.currentPoint = ew.firstPoint yield LinearMove(None, ew.firstPoint, False) else: "there is a current point. But if the start of the edge is not close, we have to move there" if self.isClose(ew.firstPoint): log.debug("No moved Required to get to edge start.") else: log.debug( "Must Move to first point, running any previous move.") t = self._fetchPendingMove() p = None if t: p = t.toPoint yield t log.debug("Moving to First Point of Edge") self.currentPoint = ew.firstPoint yield LinearMove(p, ew.firstPoint, False) if ew.isLine(): "the last move was a line, and this one is too." "if this move is parallel to the last one, then we'll dump that one" "and replace it with this one. otherwise, we'll execute it first" thisMoveDir = gp.gp_Vec(ew.firstPoint, ew.lastPoint) if self.pendingLinearMove: if not self.pendingLinearMove.dir.IsParallel( thisMoveDir, self.tolerance): "this move is parallel to the last one, so replace with this one" log.info("Move is redundant, replacing with this one.") yield self.pendingLinearMove log.debug("Saving Move as Pending.") self.pendingLinearMove = LinearMove(ew.firstPoint, ew.lastPoint, True) self.currentPoint = ew.lastPoint else: t = self._fetchPendingMove() if t: log.debug("Flushing a pending linear move...") yield t if ew.isCircle() and self.useArcs: log.debug("Curve is a Circle") circle = ew.curve.Circle() center = circle.Location() axisDir = circle.Axis().Direction() #assume we are essentially in 2d space, so we're looking only at wehter the #axis of the circle is +z or -z zDir = gp.gp().DZ() if ew.reversed: zDir = zDir.Reversed() ccw = zDir.IsEqual(axisDir, self.tolerance) self.currentPoint = ew.lastPoint includedAngle = abs(ew.firstParameter - ew.lastParameter) a = ArcMove(ew.firstPoint, ew.lastPoint, center, ccw, includedAngle) #circles are parameterized between zero and 2*pi. yield a #yield ArcMove(ew.firstPoint, ew.lastPoint, center, ccw ); else: log.debug("Curve is not a line or a circle") "a curve, or a circle we'll approximate" #the generated points might include the beginning of the curve, #so test for that, but only for the first point firstP = True lastPoint = None for p in ew.discretePoints(self.approximatedCurveDeflection): #check the first generated point for a duplicate if firstP and self.isClose(p): firstP = False continue yield LinearMove(lastPoint, p, True) lastPoint = p self.currentPoint = lastPoint #flush any last remaining move if finish: t = self._fetchPendingMove() if t: yield t
def tuplesFromEdge(edge, deflection): ew = Wrappers.Edge(edge) list = [] for p in ew.discretePoints(deflection): list.append(tP(p)) return list
"return a tuple for a point" return (point.X(), point.Y(), point.Z()) if __name__ == '__main__': print "Basic Wrappers and Utilities Module" w = TestDisplay.makeCircleWire() w = TestDisplay.makeSquareWire() #w = TestDisplay.makeReversedWire(); wr = Wrappers.Wire(w) g = networkx.Graph() for e in wr.edges(): ew = Wrappers.Edge(e) g.add_edge(tP(ew.firstPoint), tP(ew.lastPoint), {'ew': ew}) TestDisplay.display.showShape(e) #print g.nodes(); #print g.edges(); print g.get_edge_data((5.0, 0.0, 0.0), (5.0, 5.0, 0.0)) #eg = EdgeGraph(); #eg.addWire(w,'BOUND'); #the big test-- split one of the edges #e = eg.firstNode().edge; #newNode = eg.divideEdge(e,2.5); #e2 = newNode.edge;
def compute(self): tw = Topo(self.request.wire) eL = list(tw.edges_from_vertex(self.vertex)) if len(eL) > 2: raise Exception( "Cannot trim wire at vertex with more than two edges") if len(eL) == 0: raise Exception("Vertex has no edges, cannot trim") allVertices = list(tw.vertices()) #only one edge accessible from this vertex if len(eL) == 1: edgeWrapper = Wrappers.Edge(eL[0]) pointObj = edgeWrapper.getPointAtVertex(self.vertex) self.solution = JointSolution(self.request, pointObj) self.solution.trimDistance = self.request.trackWidth #for a single edge, simply trim the path width return self.solution #else len(eL) == 2. this is the most common case. (edge1, edge2) = eL[:2] edgeWrapper1 = Wrappers.Edge(eL[0]) edgeWrapper2 = Wrappers.Edge(eL[1]) #compute solutions using both edges pointOnEdge1 = edgeWrapper1.getPointAtVertex(self.vertex) pointOnEdge2 = edgeWrapper2.getPointAtVertex(self.vertex) solution1 = JointSolution(self.request, pointOnEdge1) solution2 = JointSolution(self.request, pointOnEdge2) #choose the solution that is best. ideally, we want wide angles, #remember, these are direction vectors, so small angles means 'same direction' which is good, #while pi ( 180 ) angles are bad, becaues the paths switch back onto themselves. if solution1.isBetterThan(solution2): self.solution = solution1 else: self.solution = solution2 #compute the trim distance, which is based on the angles between the edges #edges with vectors pi apart overlap, and 0 degrees are aligned #TODO: this assumes all angles are between zero and 2pi angleAtVertex = pointOnEdge1.vector.Angle(pointOnEdge2.vector) angleDiff = abs(math.pi - angleAtVertex) trimWidth = self.request.trackWidth if angleDiff < 0.1: #print "Trimmed Wire: two edges are very close to each other!" #TODO: here, if one of the edges is a curve we can re-evaluate along the curve #to find a better location. If the cuves are lines, the two should be removed. #for now, though, we'll handle this in the shortening routine, which will #essentially never allow replacing an entire edge trimDistance = trimWidth * 5.0 elif angleDiff < (math.pi / 2): #print "Trimmed Wire based on sin rule" trimDistance = trimWidth / 2 * (1 + (1 / math.sin(angleAtVertex))) else: #print "No Trim was necessary" trimDistance = trimWidth / 2 solution1.trimDistance = trimDistance solution2.trimDistance = trimDistance if self.solution is None: raise Exception( "No solution selected, this should not ever occur.") return self.solution