def __call__(self, skelcontext, name): skelobj = skelcontext.getObject() (seg_set, direction_set)=skelobj.getInterfaceSegments( skelcontext, self.interface) if self.direction==director.Director('Non-sequenceable'): skelcontext.createNonsequenceableEdgeBoundary(name, seg_set, direction_set) else: (startnode, seg_list) = _segset2seglist(seg_set, self.direction, skelobj) # At this point, we have a correctly-sequenced list of segments. # Actually create the boundary. The context will create it in # the underlying object. skelcontext.createEdgeBoundary(name, seg_list, startnode)
def _segset2seglist(seg_set, direction, skel): if len(seg_set) == 0: raise ooferror.ErrUserError("Attempt to sequence null segment set.") (seg_list, node_list, winding_number) = skeletonsegment.segSequence(seg_set) # At this point, seg_list is an ordered list of adjacent # segments, and "node_list" is the corresponding set of nodes. # The path is a loop if node_list[0]==node_list[-1], otherwise # it's a simple path. # We may want to reverse this list, depending on the # setting of "direction". firstnode = node_list[0] lastnode = node_list[-1] startnode = firstnode # The winding number is used to handle the cases where the line # crosses a periodic boundary. if (firstnode != lastnode and firstnode not in lastnode.getPartners()) \ or winding_number != [0,0]: # In case the first node and last node are partners, we set them # equal so that we can compare positions properly. if lastnode in firstnode.getPartners(): lastnode = firstnode if direction == director.Director('Left to right'): if (firstnode.position().x > lastnode.position().x + winding_number[0] * skel.MS.size()[0]): seg_list.reverse() startnode = lastnode elif direction == director.Director('Right to left'): if (firstnode.position().x < lastnode.position().x + winding_number[0] * skel.MS.size()[0]): seg_list.reverse() startnode = lastnode elif direction == director.Director('Top to bottom'): if (firstnode.position().y < lastnode.position().y + winding_number[1] * skel.MS.size()[1]): seg_list.reverse() startnode = lastnode elif direction == director.Director('Bottom to top'): if (firstnode.position().y > lastnode.position().y + winding_number[1] * skel.MS.size()[1]): seg_list.reverse() startnode = lastnode else: # User specified clockwise or counterclockwise for a # non-loop segment set. This is an error. raise ooferror.ErrUserError( "Clockwise or counterclockwise is for closed loops.") else: # firstnode==lastnode, loop case. # Use the total area swept out by vectors from the origin to the # nodes along the path as we traverse the path in order to # determine if the existing sequence traces a clockwise or # counterclockwise path. If two consecutive nodes in the # node_list are not the endpoints of a segment, we are crossing a # periodic boundary. In this case, use the positions not to find # the area swept out, but to increment the position_adjustment # needed to unwrap the periodic boundary conditions. startnode = None area = 0.0 p0 = node_list[0].position() position_adjustment = primitives.Point(0, 0) for i in range(1, len(node_list)): p1 = node_list[i].position() + position_adjustment if skel.findSegment(node_list[i], node_list[i - 1]) is not None: area += p0.x * p1.y - p1.x * p0.y p0 = p1 else: position_adjustment += p0 - p1 # setting p0 = p1 here will be redundant as we # must now adjust positions by p0 - p1 if direction == director.Director('Clockwise'): if area > 0.0: seg_list.reverse() elif direction == director.Director('Counterclockwise'): if area < 0.0: seg_list.reverse() else: # User specified an endpoint orientation on a loop. raise ooferror.ErrUserError( "Closed loops need clockwise or counterclockwise direction.") return (startnode, seg_list)
seg_set = skelcontext.segments_from_seg_aggregate(self.group) if config.dimension() == 2: (startnode, seg_list) = _segset2seglist(seg_set, self.direction, skelobj) # At this point, we have a correctly-sequenced list of segments. # Actually create the boundary. The context will create it in # the underlying object. skelcontext.createEdgeBoundary(name, seg_list, startnode) else: # 3D segmentsequence = _segset2seglist3D(seg_set, self.direction) skelcontext.createEdgeBoundary3D(name, segmentsequence) if config.dimension() == 2: director0 = director.Director('Left to right') else: director0 = director.Director('-X to +X') registeredclass.Registration( "Edge boundary from segments", BoundaryConstructor, EdgeFromSegments, ordering=_edgeBdyConstructor + _edgeBdySource, params=[ skeletongroupparams.SegmentAggregateParameter( 'group', tip="Construct the boundary from these segments"), director.DirectorParameter('direction', director0, tip="Direction of the boundary.") ],
# At this point, we have a correctly-sequenced list of segments. # Actually create the boundary. The context will create it in # the underlying object. skelcontext.createEdgeBoundary(name, seg_list, startnode) registeredclass.Registration( "Edge boundary from segments", BoundaryConstructor, EdgeFromSegments, ordering=100, params = [skeletongroupparams.SegmentAggregateParameter('group', tip="Construct the boundary from these segments"), director.DirectorParameter('direction', director.Director('Clockwise'), tip="Direction of the boundary.")], tip="Construct an edge boundary from a set of segments.", discussion=xmlmenudump.loadFile('DISCUSSIONS/engine/reg/edge_from_segments.xml')) # ## ### #### ##### ###### ####### ######## ####### ##### #### ### ## # # Finds the perimeter of an elementgroup. Requires that the element # group have a topologically simple (non-self-intersecting, # non-disjoint) boundary. # Utility function for extracting a segment list from elements. # Also used by the DirectorWidget.