def copyToZ(self, z, layerNo): "makes a copy of this slice, transformed to the specified z height" theCopy = Slice() theCopy.zLevel = z theCopy.fillAngle = self.fillAngle theCopy.layerNo = layerNo theCopy.thickness = self.thickness #make transformation p1 = gp.gp_Pnt(0, 0, 0) p2 = gp.gp_Pnt(0, 0, z) xform = gp.gp_Trsf() xform.SetTranslation(p1, p2) bt = BRepBuilderAPI.BRepBuilderAPI_Transform(xform) #copy all of the faces for f in self.faces: bt.Perform(f.face, True) newFace = Face(OCCUtil.cast(bt.Shape())) #copy shells for shell in f.shellWires: #print shell bt.Perform(shell, True) newFace.shellWires.append(OCCUtil.cast(bt.Shape())) #copy fillWires for fill in f.fillWires: bt.Perform(fill, True) newFace.shellWires.append(OCCUtil.cast(bt.Shape())) theCopy.addFace(newFace) return theCopy
def copyToZ(self, z, layerNo): "makes a copy of this slice, transformed to the specified z height" theCopy = Slice() theCopy.zLevel = z theCopy.fillAngle = self.fillAngle theCopy.layerNo = layerNo theCopy.thickness = self.thickness # make transformation p1 = gp.gp_Pnt(0, 0, 0) p2 = gp.gp_Pnt(0, 0, z) xform = gp.gp_Trsf() xform.SetTranslation(p1, p2) bt = BRepBuilderAPI.BRepBuilderAPI_Transform(xform) # copy all of the faces for f in self.faces: bt.Perform(f.face, True) newFace = Face(OCCUtil.cast(bt.Shape())) # copy shells for shell in f.shellWires: # print shell bt.Perform(shell, True) newFace.shellWires.append(OCCUtil.cast(bt.Shape())) # copy fillWires for fill in f.fillWires: bt.Perform(fill, True) newFace.shellWires.append(OCCUtil.cast(bt.Shape())) theCopy.addFace(newFace) return theCopy
def makeHexArray(self, bottomLeftCenter, countX, countY): """ makes an array of hexagons bottomLeftCenter is the center of the top left hex, as a three-element tuple countX is the number of hexes in the x direction countY is the number of hexes in the y direction returns a list of wires representing a hexagon fill pattern """ pattern = self.makePeriodic(bottomLeftCenter) wireBuilder = BRepBuilderAPI.BRepBuilderAPI_MakeWire(pattern) #make horizontal array tsf = gp.gp_Trsf() pDist = 2.0 * self.cartesianSpacing()[0] tsf.SetTranslation(gp.gp_Pnt(0, 0, 0), gp.gp_Pnt(pDist, 0, 0)) tx = BRepBuilderAPI.BRepBuilderAPI_Transform(tsf) currentShape = pattern for i in range(1, int((countX / 2) + 1)): tx.Perform(currentShape, False) currentShape = tx.Shape() #display.DisplayShape(currentShape); wireBuilder.Add(OCCUtil.cast(currentShape)) #create an array by alternately offsetting one cell right and #moving down topHalf = wireBuilder.Wire() #topHalf= approximatedWire(topHalf); wires = [] wires.append(topHalf) dY = self.cartesianSpacing()[1] / 2.0 dX = self.cartesianSpacing()[0] ####TODO// performance note. This method takes about 31ms to compute 1000x1000 hex. # pretty good, except that nearly 50% of the time is spent in makeTransform!!! # a much better method would be to use the same transform object somehow for i in range(1, int(countY * 2)): if i % 2 == 0: t = makeTransform(0, dY * i, 0) else: t = makeTransform(dX, dY * i, 0) t.Perform(topHalf, False) w = OCCUtil.cast(t.Shape()) #approximate the wire #wires.append ( approximatedWire(w)); wires.append(w) #display.DisplayShape(wires); return wires
def makeOffsets(wire,d=True): numOffsets = 0; if d: display.DisplayColoredShape(startWire,'YELLOW'); STEP = 0.5; for offset in Util.frange6(0.5,4.0,STEP): #print "offsetting by %0.3f" % offset o = OCCUtil.offsetWire(startWire,offset*(-1.0)); numOffsets+=1; if d: display.DisplayColoredShape(o, 'RED'); o2 = OCCUtil.offsetWire(startWire,offset*(-1.0) + (STEP/2.0) ); numOffsets+=1; #create a naive centerline by setting in( which could conflict with others ) #if d: display.DisplayColoredShape(o2,'GREEN'); #now offset back out to create centerline. if the result is a compound, then we must offset each member wire if o.ShapeType() == TopAbs.TopAbs_COMPOUND: t = Topo(o); for w in t.wires(): w2 = OCCUtil.offsetWire(w,STEP*(0.5)); numOffsets+=1; if d: display.DisplayColoredShape(w2, 'BLUE'); else: #wire o2 = OCCUtil.offsetWire(OCCUtil.cast(o),STEP*(0.5)); numOffsets+=1; if d: display.DisplayColoredShape(o2, 'WHITE'); return numOffsets;
def testOffsetReferences(): #f = TestObjects.makeHeartFace(); #f must be a face with one outer and one inner wire f = TestObjects.makeSquareWithRoundHole(); wires = OCCUtil.wireListFromFace(f); outer = wires[0]; inner = wires[1]; display.DisplayColoredShape(outer,'GREEN'); display.DisplayColoredShape(inner,'WHITE'); #add wires to offset. bo = BRepOffsetAPI.BRepOffsetAPI_MakeOffset(); bo.AddWire(outer); bo.AddWire(inner); bo.Perform(-0.2,0.0); #do an offset shape = bo.Shape(); for w in Topo(shape).wires(): display.DisplayColoredShape(OCCUtil.cast(shape),'YELLOW'); for e in Topo(outer).edges(): print "Outer Edge %d has %d generated shapes" % ( e.__hash__(), len(OCCUtil.listFromTopToolsListOfShape(bo.Generated(e) )) ); for e in Topo(inner).edges(): print "Inner Edge %d has %d generated shapes" % ( e.__hash__(), len(OCCUtil.listFromTopToolsListOfShape(bo.Generated(e) )) ); display.FitAll();
def testOffsetReferences(): #f = TestObjects.makeHeartFace(); #f must be a face with one outer and one inner wire f = TestObjects.makeSquareWithRoundHole() wires = OCCUtil.wireListFromFace(f) outer = wires[0] inner = wires[1] display.DisplayColoredShape(outer, 'GREEN') display.DisplayColoredShape(inner, 'WHITE') #add wires to offset. bo = BRepOffsetAPI.BRepOffsetAPI_MakeOffset() bo.AddWire(outer) bo.AddWire(inner) bo.Perform(-0.2, 0.0) #do an offset shape = bo.Shape() for w in Topo(shape).wires(): display.DisplayColoredShape(OCCUtil.cast(shape), 'YELLOW') for e in Topo(outer).edges(): print "Outer Edge %d has %d generated shapes" % ( e.__hash__(), len(OCCUtil.listFromTopToolsListOfShape(bo.Generated(e)))) for e in Topo(inner).edges(): print "Inner Edge %d has %d generated shapes" % ( e.__hash__(), len(OCCUtil.listFromTopToolsListOfShape(bo.Generated(e)))) display.FitAll()
def makeOffsets(wire, d=True): numOffsets = 0 if d: display.DisplayColoredShape(startWire, 'YELLOW') STEP = 0.5 for offset in Util.frange6(0.5, 4.0, STEP): #print "offsetting by %0.3f" % offset o = OCCUtil.offsetWire(startWire, offset * (-1.0)) numOffsets += 1 if d: display.DisplayColoredShape(o, 'RED') o2 = OCCUtil.offsetWire(startWire, offset * (-1.0) + (STEP / 2.0)) numOffsets += 1 #create a naive centerline by setting in( which could conflict with others ) #if d: display.DisplayColoredShape(o2,'GREEN'); #now offset back out to create centerline. if the result is a compound, then we must offset each member wire if o.ShapeType() == TopAbs.TopAbs_COMPOUND: t = Topo(o) for w in t.wires(): w2 = OCCUtil.offsetWire(w, STEP * (0.5)) numOffsets += 1 if d: display.DisplayColoredShape(w2, 'BLUE') else: #wire o2 = OCCUtil.offsetWire(OCCUtil.cast(o), STEP * (0.5)) numOffsets += 1 if d: display.DisplayColoredShape(o2, 'WHITE') return numOffsets
def addBoundaryWire(self,wire): #for finding an edge node wr = Wrappers.Wire(wire); eS = wr.edgesAsSequence(); for i in range(1,eS.Length()+1): e = OCCUtil.cast(eS.Value(i)); self.addSingleBoundaryEdge(e);
def build(self): topoWire = Topo(self.wire) #compute closest point on the wire brp = BRepExtrema.BRepExtrema_DistShapeShape() brp.LoadS1(OCCUtil.make_vertex(self.startPoint)) brp.LoadS2(self.wire) result = brp.Perform() p1 = brp.PointOnShape2(1) wb = OCCUtil.WireBuilder() closestParam = None if brp.SupportTypeShape2(1) == BRepExtrema.BRepExtrema_IsOnEdge: #closest point is a point along an edge interSectingEdge = OCCUtil.cast(brp.SupportOnShape2(1)) closestParam = brp.ParOnEdgeS2(1) else: #closest point is a point on a vertex, here we'll shorten one edge #in this case closest point is a vertex, so we dont have a param on an edge vertex = OCCUtil.cast(brp.SupportOnShape2(1)) edges = [] for e in topoWire.edges_from_vertex(vertex): edges.append(e) interSectingEdge = edges[0] #compute parameter along one curve #break the edge into two new edges. account for a split distance between them. ej = EdgeJoin(interSectingEdge, self.startPoint, self.trackWidth, closestParam) #add lead-in edges for e in ej.connectingEdges: wb.add(e) #now add all of the other edges in the wire except the original one that we split for e in topoWire.edges(): if not e.IsSame(interSectingEdge): wb.add(e) for e in ej.otherEdges: wb.add(e) return wb.wire()
def build(self): topoWire = Topo(self.wire); #compute closest point on the wire brp = BRepExtrema.BRepExtrema_DistShapeShape(); brp.LoadS1(OCCUtil.make_vertex(self.startPoint)); brp.LoadS2(self.wire); result = brp.Perform(); p1 = brp.PointOnShape2(1); wb = OCCUtil.WireBuilder(); closestParam = None; if brp.SupportTypeShape2(1) == BRepExtrema.BRepExtrema_IsOnEdge: #closest point is a point along an edge interSectingEdge = OCCUtil.cast(brp.SupportOnShape2(1)); closestParam = brp.ParOnEdgeS2(1); else: #closest point is a point on a vertex, here we'll shorten one edge #in this case closest point is a vertex, so we dont have a param on an edge vertex = OCCUtil.cast(brp.SupportOnShape2(1)); edges = []; for e in topoWire.edges_from_vertex(vertex): edges.append(e); interSectingEdge = edges[0]; #compute parameter along one curve #break the edge into two new edges. account for a split distance between them. ej = EdgeJoin(interSectingEdge,self.startPoint,self.trackWidth ,closestParam); #add lead-in edges for e in ej.connectingEdges: wb.add(e); #now add all of the other edges in the wire except the original one that we split for e in topoWire.edges(): if not e.IsSame(interSectingEdge): wb.add(e); for e in ej.otherEdges: wb.add(e); return wb.wire();
def getWires(self): q = time.clock(); en = self.graphBuilder.walkEdges(); #print "Walked Edges-- %d total paths, %0.3f sec" % (len(en), ( time.clock() - q ) ); wires = []; for path in en: wb = OCCUtil.WireBuilder(); for edge in Util.pairwise(path): #each pair is a set of nodes that form an edge in the graph. We need to ge the OCC edges from each for occEdge in self.graphBuilder.getEdges(edge[0],edge[1]): wb.add( OCCUtil.cast(occEdge) ); wires.append(wb.wire() ); return wires;
def getWires(self): q = time.clock() en = self.graphBuilder.walkEdges() #print "Walked Edges-- %d total paths, %0.3f sec" % (len(en), ( time.clock() - q ) ); wires = [] for path in en: wb = OCCUtil.WireBuilder() for edge in Util.pairwise(path): #each pair is a set of nodes that form an edge in the graph. We need to ge the OCC edges from each for occEdge in self.graphBuilder.getEdges(edge[0], edge[1]): wb.add(OCCUtil.cast(occEdge)) wires.append(wb.wire()) return wires
def distToPoint( wire, vertex): brp = BRepExtrema.BRepExtrema_DistShapeShape(); brp.LoadS1(vertex); brp.LoadS2(wire); result = brp.Perform(); if result: if brp.NbSolution() > 1: print "weird, more than one solution" point = brp.PointOnShape2(1); #otherwise, figure out what kind of location we have. if brp.SupportTypeShape2(1) == BRepExtrema.BRepExtrema_IsOnEdge: #closest point is a point along an edge edge = OCCUtil.cast(brp.SupportOnShape2(1)); parameter = brp.ParOnEdgeS2(1); #print "Closest point is on an edge" else: #closest point is a point on a vertex vertex = OCCUtil.cast(brp.SupportOnShape2(1)); #print "closest point is on vertex" return point;
def makeExtrusionWire( shellWire, startPoint, trackWidth): topoWire = Topo(shellWire); #compute closest point on the wire brp = BRepExtrema.BRepExtrema_DistShapeShape(); brp.LoadS1(OCCUtil.make_vertex(startPoint)); brp.LoadS2(shellWire); result = brp.Perform(); p1 = brp.PointOnShape2(1); wb = WireBuilder(); #make an edge from start point to located point. #wb.add ( OCCUtil.edgeFromTwoPoints(startPoint, p1 ) ); dist = p1.Distance(p2) if brp.SupportTypeShape2(1) == BRepExtrema.BRepExtrema_IsOnEdge: #closest point is a point along an edge interSectingEdge = OCCUtil.cast(brp.SupportOnShape2(1)); p = brp.ParOnEdgeS2(1); #compute parameter along one curve #break the edge into two new edges. account for a split distance between them. (e1,e2)= OCCUtil.splitEdge(interSectingEdge,p); wb.add(e1); #add second one shortened, on the end near the vertex wb.add ( OCCUtil.shortenEdge(e2,p1,trackWidth)); #hack, must find parameter closest to this end #now add all of the other edges in the wire except the original one that we split for e in topoWire.edges(): if not e.IsSame(interSectingEdge): wb.add(e); else: #closest point is a point on a vertex, here we'll shorten one edge # vertex = OCCUtil.cast(brp.SupportOnShape2(1)); edges = []; for e in topoWire.edges_from_vertex(vertex): edges.append(e); #shorten one, leave other intact #try to handle case where vertex is at end of a wire ( ie a non-closed wire ) e1 = edges[0]; wb.add( edges[0]); e2 = None; if len(edges) > 1: e2 = edges[1]; e3 = OCCUtil.shortenEdge(e2,p1,trackWidth); #hack-- find edges closest to this end #display.DisplayColoredShape(e3,'BLUE') wb.add ( e3); for e in topoWire.edges(): if e.IsSame(e1): continue; if e2 and e.IsSame(e2): continue; wb.add ( e ); return wb.wire();
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 ( [ OCCUtil.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( OCCUtil.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 = OCCUtil.cast(topexp.Current() ); edges.append(edge); #print "adding middle edge" topexp.Next(); #add the last edge (bp,ep) = brepTool.Range(nextIntersection.edge); edges.append( OCCUtil.trimmedEdge(nextIntersection.edge,bp,nextIntersection.param)); #print "adding last piece of edge" edgeList.append(edges); return edgeList;
def hatch(self): """take the a slice and compute hatches computing the intersections of wires is very expensive, so it is important to do this as efficently as possible. Inputs: a set of boundary wires that define a face, a set of filling wires that cover a bounding box around the face. Outputs: trim covering wires/edges by the boundaries, trim boundaries by intersections with wires optimizations so far: * use active wire table to detect when to stop computing intersections with wires. each boundary must be activated before computation stops, and a boundary is finished after intersections have been found, and then stop occurring. More optimization can be used by Bnd_BoundSortBox-- which would compare all of the bounding boxes at once in c++, but with more glue code. """ q = time.clock(); hatchWires = self._makeHatchLines(); numCompares = 0; bbuilder = BRep.BRep_Builder(); comp = TopoDS.TopoDS_Compound(); bbuilder.MakeCompound(comp); #print "Time to Make hatch Lines: %0.3f" % ( time.clock() - q ) for b in self.boundaryWires: bbuilder.Add(comp,b); self.graphBuilder.addBoundaryWire(b); #print "There are %d boundary wires, %d hatch wires" % ( len(self.boundaryWires),len(hatchWires) ) #intersect each line with each boundary brp = BRepExtrema.BRepExtrema_DistShapeShape(); brp.LoadS1(comp); for hatchLine in hatchWires: interSections = []; #list of intersections for just this single hatch line closePoints = []; #extrema that are not intersectionsf or this single hatch line brp.LoadS2(hatchLine ); numCompares+= 1; result = brp.Perform(); """ tricky thing: for a given hatch line ( whether a line or a string of hexes ), we want to check for both intersections and close points that would result in overdrawing. if the line has zero intersections, then it is not in play, and should not be considered. if the line has at least one intersection, then it is in play, and extrema that are not intersections should also be included for later processing. """ if result and brp.Value() < 0.050: #if < tolerance we have an intersection. if < filament width we have a close sitation #print "intersection found, distance = %0.6f" % brp.Value() #TODO need to handle the somewhat unusual cases that the intersection is #on a vertex for k in range(1,brp.NbSolution()+1): if brp.Value() < 0.001: #there is at least one intersection on this wire. there may also be extrema #print "spot on match" #try: #make the node #quite complex depending on where exactly the intersection is. if brp.SupportTypeShape1(k) == BRepExtrema.BRepExtrema_IsOnEdge: #well this sux-- have to check to ensure that the edge is not a local #minimum or maximum also. if OCCUtil.isEdgeLocalMinimum(OCCUtil.cast(brp.SupportOnShape1(k)),brp.ParOnEdgeS1(k),brp.PointOnShape1(k)): print "Warning: edge appears to be a local min/max. Is it a tangent?" continue; else: #self.boundaryIntersectionsByEdge = {} #boundary intersections, hashed by edges self.graphBuilder.addPointOnBoundaryEdge(OCCUtil.cast(brp.SupportOnShape1(k)),brp.ParOnEdgeS1(k),brp.PointOnShape1(k)); if brp.SupportTypeShape2(k) == BRepExtrema.BRepExtrema_IsOnEdge: if brp.SupportTypeShape1(k) == BRepExtrema.BRepExtrema_IsVertex: #the intersection is on a vertex of the boundary. vertex = OCCUtil.cast(brp.SupportOnShape1(k)); #otherwise, vertex was not a local minimum, or was on an edge poe = eg.PointOnAnEdge(OCCUtil.cast(brp.SupportOnShape2(k)),brp.ParOnEdgeS2(k),brp.PointOnShape2(k)); interSections.append(poe); elif brp.SupportTypeShape2(k) == BRepExtrema.BRepExtrema_IsVertex: #how on earth to handle this one? #this actually means that a vertex can also have an infill node attached to it! #for right now let's just ignore it. print "WARNING: intersection on vertex of hatch line!" pass; else: raise ValueError("I dont know how to handle this kind of intersection"); else: #brp.Value is between 0.001 and 0.05 #print "intersection is close"; #we know this is a place where the boundary is close to a fill contour. #our goal is to eventually remove it from the list. Support1 is the boundary. #print "found extremum close but not intersecting, distance = %0.3f" % ( brp.Value() ) if brp.SupportTypeShape1(k) == BRepExtrema.BRepExtrema_IsOnEdge: poeBound = eg.PointOnAnEdge(brp.SupportOnShape1(k), brp.ParOnEdgeS1(k),brp.PointOnShape1(k)); closePoints.append((poeBound,'EDGE',brp.SupportOnShape2(k))); elif brp.SupportTypeShape2(k) == BRepExtrema.BRepExtrema_IsVertex: #here a vertex is closest to a fill line. poeBound = eg.PointOnAnEdge(brp.SupportOnShape1(k), 0,brp.PointOnShape1(k)); closePoints.append((poeBound,'VERTEX',brp.SupportOnShape2(k))); if len(interSections) % 2 == 1: print "Detected Odd Number of intersection points. This is ignored for now."; continue; if len(interSections) == 0: #print "Hatch has no intersections-- discarding"; continue; #at this point we have all the intersections for this hatch line. #we also know we have at least one intersection. if len(closePoints) > 0: #there were extrema ( points where this hatch is close to a boundary but doesnt intersect. #we do this here instead of inline because we have to avoid hatch lines that are close, but do not actually #intersect a wire. ( ie, they are 'just outside' of the boundary ) for cp in closePoints: self.graphBuilder.addPointsTooClose(cp[0], cp[1]); #display.DisplayShape(cp[0].edge ); #display.DisplayShape(cp[2] ); #add the edges 'inside' the shape to the graph #print "Splitting wire by %d intersection points" % len(interSections ) edgesInside = []; edgesInside = eg.splitWire(hatchLine,interSections); #returned value is a list of lists. each entry is a chain of edges for e in edgesInside: self.graphBuilder.addFillEdges(e); #test to see if we can break out of the loop. #we can stop if we've hit each boundary at least once #if len(interSections) == 0 and (len(boundariesFound) == len(self.boundaryWires)): # continueHatching = False; print "%d Total Intersections computed." % ( numCompares ) self.graphBuilder.buildGraph();
def hatch(self): """take the a slice and compute hatches computing the intersections of wires is very expensive, so it is important to do this as efficently as possible. Inputs: a set of boundary wires that define a face, a set of filling wires that cover a bounding box around the face. Outputs: trim covering wires/edges by the boundaries, trim boundaries by intersections with wires optimizations so far: * use active wire table to detect when to stop computing intersections with wires. each boundary must be activated before computation stops, and a boundary is finished after intersections have been found, and then stop occurring. More optimization can be used by Bnd_BoundSortBox-- which would compare all of the bounding boxes at once in c++, but with more glue code. """ q = time.clock() hatchWires = self._makeHatchLines() numCompares = 0 bbuilder = BRep.BRep_Builder() comp = TopoDS.TopoDS_Compound() bbuilder.MakeCompound(comp) #print "Time to Make hatch Lines: %0.3f" % ( time.clock() - q ) for b in self.boundaryWires: bbuilder.Add(comp, b) self.graphBuilder.addBoundaryWire(b) #print "There are %d boundary wires, %d hatch wires" % ( len(self.boundaryWires),len(hatchWires) ) #intersect each line with each boundary brp = BRepExtrema.BRepExtrema_DistShapeShape() brp.LoadS1(comp) for hatchLine in hatchWires: interSections = [] #list of intersections for just this single hatch line closePoints = [] #extrema that are not intersectionsf or this single hatch line brp.LoadS2(hatchLine) numCompares += 1 result = brp.Perform() """ tricky thing: for a given hatch line ( whether a line or a string of hexes ), we want to check for both intersections and close points that would result in overdrawing. if the line has zero intersections, then it is not in play, and should not be considered. if the line has at least one intersection, then it is in play, and extrema that are not intersections should also be included for later processing. """ if result and brp.Value( ) < 0.050: #if < tolerance we have an intersection. if < filament width we have a close sitation #print "intersection found, distance = %0.6f" % brp.Value() #TODO need to handle the somewhat unusual cases that the intersection is #on a vertex for k in range(1, brp.NbSolution() + 1): if brp.Value( ) < 0.001: #there is at least one intersection on this wire. there may also be extrema #print "spot on match" #try: #make the node #quite complex depending on where exactly the intersection is. if brp.SupportTypeShape1( k) == BRepExtrema.BRepExtrema_IsOnEdge: #well this sux-- have to check to ensure that the edge is not a local #minimum or maximum also. if OCCUtil.isEdgeLocalMinimum( OCCUtil.cast(brp.SupportOnShape1(k)), brp.ParOnEdgeS1(k), brp.PointOnShape1(k)): print "Warning: edge appears to be a local min/max. Is it a tangent?" continue else: #self.boundaryIntersectionsByEdge = {} #boundary intersections, hashed by edges self.graphBuilder.addPointOnBoundaryEdge( OCCUtil.cast(brp.SupportOnShape1(k)), brp.ParOnEdgeS1(k), brp.PointOnShape1(k)) if brp.SupportTypeShape2( k) == BRepExtrema.BRepExtrema_IsOnEdge: if brp.SupportTypeShape1( k) == BRepExtrema.BRepExtrema_IsVertex: #the intersection is on a vertex of the boundary. vertex = OCCUtil.cast(brp.SupportOnShape1(k)) #otherwise, vertex was not a local minimum, or was on an edge poe = eg.PointOnAnEdge( OCCUtil.cast(brp.SupportOnShape2(k)), brp.ParOnEdgeS2(k), brp.PointOnShape2(k)) interSections.append(poe) elif brp.SupportTypeShape2( k) == BRepExtrema.BRepExtrema_IsVertex: #how on earth to handle this one? #this actually means that a vertex can also have an infill node attached to it! #for right now let's just ignore it. print "WARNING: intersection on vertex of hatch line!" pass else: raise ValueError( "I dont know how to handle this kind of intersection" ) else: #brp.Value is between 0.001 and 0.05 #print "intersection is close"; #we know this is a place where the boundary is close to a fill contour. #our goal is to eventually remove it from the list. Support1 is the boundary. #print "found extremum close but not intersecting, distance = %0.3f" % ( brp.Value() ) if brp.SupportTypeShape1( k) == BRepExtrema.BRepExtrema_IsOnEdge: poeBound = eg.PointOnAnEdge( brp.SupportOnShape1(k), brp.ParOnEdgeS1(k), brp.PointOnShape1(k)) closePoints.append( (poeBound, 'EDGE', brp.SupportOnShape2(k))) elif brp.SupportTypeShape2( k) == BRepExtrema.BRepExtrema_IsVertex: #here a vertex is closest to a fill line. poeBound = eg.PointOnAnEdge( brp.SupportOnShape1(k), 0, brp.PointOnShape1(k)) closePoints.append( (poeBound, 'VERTEX', brp.SupportOnShape2(k))) if len(interSections) % 2 == 1: print "Detected Odd Number of intersection points. This is ignored for now." continue if len(interSections) == 0: #print "Hatch has no intersections-- discarding"; continue #at this point we have all the intersections for this hatch line. #we also know we have at least one intersection. if len(closePoints) > 0: #there were extrema ( points where this hatch is close to a boundary but doesnt intersect. #we do this here instead of inline because we have to avoid hatch lines that are close, but do not actually #intersect a wire. ( ie, they are 'just outside' of the boundary ) for cp in closePoints: self.graphBuilder.addPointsTooClose(cp[0], cp[1]) #display.DisplayShape(cp[0].edge ); #display.DisplayShape(cp[2] ); #add the edges 'inside' the shape to the graph #print "Splitting wire by %d intersection points" % len(interSections ) edgesInside = [] edgesInside = eg.splitWire(hatchLine, interSections) #returned value is a list of lists. each entry is a chain of edges for e in edgesInside: self.graphBuilder.addFillEdges(e) #test to see if we can break out of the loop. #we can stop if we've hit each boundary at least once #if len(interSections) == 0 and (len(boundariesFound) == len(self.boundaryWires)): # continueHatching = False; print "%d Total Intersections computed." % (numCompares) self.graphBuilder.buildGraph()