vox011 = voxelsetboundary.cvar.vox011 vox111 = voxelsetboundary.cvar.vox111 voxels = { vox000: (0, 0, 0), vox100: (1, 0, 0), vox010: (0, 1, 0), vox110: (1, 1, 0), vox001: (0, 0, 1), vox101: (1, 0, 1), vox011: (0, 1, 1), vox111: (1, 1, 1) } # Define some planes to clip the voxel set boundaries. skew = primitives.Point(1.1, 0.9, 1.0) skew = skew / math.sqrt(skew * skew) xyz = primitives.Point(1, 1, 1) xyz = xyz / math.sqrt(xyz * xyz) planes = [ COrientedPlane(primitives.Point(1, 0, 0), 0.0), # 0 empty COrientedPlane(primitives.Point(1, 0, 0), 4.0).reversed(), # 1 empty COrientedPlane(primitives.Point(1, 0, 0), 0.0).reversed(), # 2 all COrientedPlane(primitives.Point(1, 0, 0), 4.0), # 3 all COrientedPlane(primitives.Point(1, 0, 0), 2.0), # 4 through center COrientedPlane(primitives.Point(1, 0, 0), 2.5), # 5 COrientedPlane(primitives.Point(0, 1, 0), 2.5).reversed(), # 6 COrientedPlane(primitives.Point(0, 0, 1), 1.5), # 7 COrientedPlane(skew, 2.5), # 8 COrientedPlane(skew, 2.5).reversed(), # 9
def __init__(self, pixel, size): self.pixel = pixel self.point = primitives.Point(*(float(pixel[i]) * size[i] + 0.5 * size[i] for i in range(config.dimension())))
def moveCB(self, button): debug.mainthreadTest() xyz = [utils.OOFeval(text.get_text()) for text in self.texts] point = primitives.Point(*xyz) skelctxt = self.getSkeletonContext() subthread.execute(self.kbmove_subthread, (skelctxt, point))
def up(self, x, y, button, shift, ctrl): self.endpoint = primitives.Point(x, y) self.toolbox.makeCS(self.startpoint, self.endpoint)
def _read(self, datafile, prog): # readData gets data from the file, but does no processing data = self.readData(datafile, prog) rows = list(getrows(data)) # sorts data # The grid is hexagonal if the first two rows don't start at the same x. if rows[0][0].position[0] != rows[1][0].position[0]: # Throw out every other row. reporter.warn("Converting hexagonal lattice to rectangular" " by discarding alternate rows.") rows = rows[::2] # discard odd numbered rows # Check that all rows are the same length, and flip the # coordinates if requested. nx = len(rows[0]) ny = len(rows) ymax = rows[-1][0].position[1] ymin = rows[0][0].position[1] xmax = rows[0][-1].position[0] xmin = rows[0][0].position[0] count = 0 for row in rows: count += 1 if len(row) != nx: raise ooferror.ErrUserError( "Orientation map data appears to be incomplete.\n" "len(row 0)=%d len(row %d)=%d" % (nx, count, len(row))) for point in row: if self.flip_x: point.position[0] = xmax - point.position[0] else: point.position[0] = point.position[0] - xmin if self.flip_y: point.position[1] = ymax - point.position[1] else: point.position[1] = point.position[1] - ymin # pixel size dx = abs(rows[0][1].position[0] - rows[0][0].position[0]) dy = abs(rows[0][0].position[1] - rows[1][0].position[1]) pxlsize = primitives.Point(dx, dy) width = abs(rows[0][0].position[0] - rows[0][-1].position[0]) height = abs(rows[0][0].position[1] - rows[-1][0].position[1]) # If we assume that the points are in the centers of the # pixels, then the actual physical size is one pixel bigger # than the range of the xy values. size = primitives.Point(width, height) + pxlsize npts = len(rows) * len(rows[0]) od = orientmapdata.OrientMap(primitives.iPoint(nx, ny), size * self.scale_factor) prog.setMessage("%d/%d orientations" % (0, npts)) count = 0 for row in rows: for datum in row: ij = primitives.iPoint( int(round(datum.position[0] / pxlsize[0])), int(round(datum.position[1] / pxlsize[1]))) for groupname in datum.groups: try: self.groupmembers[groupname].append(ij) except KeyError: self.groupmembers[groupname] = [ij] if self.angle_units == 'Degrees': offset = math.radians(self.angle_offset) angleargs = datum.angletuple else: # angle units are Radians offset = self.angle_offset # All Orientation subclasses that take angle args # assume that they're in degrees. They have a # static radians2Degrees method that converts the # angle args from radians to degrees. angleargs = self.angle_type.radians2Degrees( *datum.angletuple) # Create an instance of the Orientation subclass. orient = self.angle_type(*angleargs) if self.angle_offset != 0: orient = orient.rotateXY(self.angle_offset) # Insert this point into the OrientMap object. self.set_angle(od, ij, orient.corient) prog.setMessage("%d/%d orientations" % (count, npts)) prog.setFraction(float(count) / npts) count += 1 if prog.stopped(): return None return od
def get_endpoints(self): # Dimension-independent version copied from OOF3D for testing # here. DIM = 2 cs_obj = self.meshctxt.getCrossSection(self.cross_section) bounds = self.meshctxt.size() errmsg = ("Segment %s, %s is entirely outside the mesh." % (cs_obj.start, cs_obj.end)) # Check that both endpoints aren't out of bounds on the same # side of the bounding box in any dimension. for i in range(DIM): if ((cs_obj.start[i] < 0 and cs_obj.end[i] < 0) or (cs_obj.start[i] > bounds[i] and cs_obj.end[i] > bounds[i])): raise ooferror.ErrUserError(errmsg) # If an endpoint is out of bounds in any dimension, project it # back onto the bounding planes. First, clone the endpoints # so that we aren't modifying the data in the cross section # object. real_start = primitives.Point(*tuple(cs_obj.start)) real_end = primitives.Point(*tuple(cs_obj.end)) for i in range(DIM): direction = real_end - real_start otherdims = [(i + j) % DIM for j in range(1, DIM)] if real_start[i] < 0: # direction[i] can't be zero if real_start[i] < 0 or # else the bounding box check above would have failed. alpha = -real_start[i] / direction[i] for j in otherdims: real_start[j] += alpha * direction[j] real_start[i] = 0 # don't allow roundoff elif real_start[i] > bounds[i]: alpha = (real_start[i] - bounds[i]) / direction[i] for j in otherdims: real_start[j] -= alpha * direction[j] real_start[i] = bounds[i] if real_end[i] < 0: alpha = -real_end[i] / direction[i] for j in otherdims: real_end[j] += alpha * direction[j] real_end[i] = 0 elif real_end[i] > bounds[i]: alpha = (real_end[i] - bounds[i]) / direction[i] for j in otherdims: real_end[j] -= alpha * direction[j] real_end[i] = bounds[i] # Check that the clipped segment isn't infinitesimal. This # can happen if it grazes a corner of the Microstructure. seg = real_end - real_start if seg * seg == 0: raise ooferror.ErrUserError(errmsg) # Check that the modified points are within bounds. It's # possible that they're not if the original points were placed # sufficiently perversely. for i in range(DIM): if not (0 <= real_start[i] <= bounds[i] and 0 <= real_end[i] <= bounds[i]): raise ooferror.ErrUserError(errmsg) return (real_start, real_end)
def realelement_shares(self, skeleton, mesh, index, fe_node, curnodeindex, elemdict, materialfunc): # Be safe with indices. if self.meshindex is None: # Zero is nontrivial index. self.meshindex = index else: if index != self.meshindex: raise ooferror2.ErrPyProgrammingError( "Index mismatch in element construction.") nnewnodes = 0 ncn = len(self.nodes) # Corner nodes. # elemdict is a dictionary of MasterElements, keyed by number # of sides. elementtype = elemdict[self.nnodes()] nodes = [] # real nodes for this element for i in range(len(self.nodes)): # i.e. for each edge... c0 = self.nodes[i] nodes.append(fe_node[c0]) # Corner nodes already exist. c1 = self.nodes[(i + 1) % ncn] cset = skeletonnode.canonical_order(c0, c1) # Look up this edge in the dictionary. If it's there, # then nodes have been created on the edge already, and we # should reuse them. try: xtranodes = mesh.getEdgeNodes(cset) # The nodes were created by the neighboring element. # Since elements traverse their edges counterclockwise # when creating nodes, the preexisting nodes are in # the wrong order for the current element. xtranodes.reverse() except KeyError: newindexinc = 0 newindex = 0 protocount = 0 protodiclength = len(elementtype.protodic[i]) if c0.index < c1.index: newindexinc = 1 newindex = skeleton.maxnnodes + 100 * c0.index else: # Do this to distinguish the protonode on either # side of a corner node that has a smaller index # than either corner nodes of the collinear # segments extending from that corner node. newindexinc = -1 newindex = skeleton.maxnnodes + 100 * c1.index + 50 + protodiclength - 1 # The edge wasn't in the dictionary. It's a new edge. xtranodes = [] # Loop over all protonodes on the current # edge of the new element for newproto in elementtype.protodic[i]: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode_shares( mesh, newproto, coord.Coord(realxy.x, realxy.y), c0, c1, newindex, protocount, protodiclength, skeleton.maxnnodes) newindex += newindexinc protocount += 1 nnewnodes = nnewnodes + 1 xtranodes.append(newnode) mesh.addEdgeNodes(cset, xtranodes) #Should this be 'join'ed instead, for speed? nodes = nodes + xtranodes # Interior nodes at the end. for newproto in elementtype.protodic['interior']: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 nodes.append(newnode) mesh.addInternalNodes(self, newnode) # Having constructed the list of nodes, call the real # element's constructor. realel = elementtype.build(self, materialfunc(self, skeleton), nodes) # Long-lost cousin of Kal-El and Jor-El. mesh.addElement(realel) # Add to mesh. # Tell the element about its exterior edges. for edge in self.exterior_edges: realel.set_exterior(fe_node[edge[0]], fe_node[edge[1]]) return nnewnodes
def screenCoordsTo3DCoords(self, selectionX, selectionY): # We need to use the renderer to convert coordinate systems in # order to find which point in the 3D structure, the 2D mouse # is pointing to. We use the bounds of the image (or skeleton # or whatever) and the clipping plane to find the topmost # visible point. bounds = self.getBounds() windowY = self._RenderWindow.GetSize()[ 1] #self.widget.window.get_size()[1] selectionY = windowY - selectionY - 1 pickPosition = [0.0, 0.0, 0.0] point = None # get camera focal point and position, convert to display # coordinates cameraPos = list(self._Camera.GetPosition()) cameraPos.append(1.0) cameraFP = list(self._Camera.GetFocalPoint()) cameraFP.append(1.0) self._Renderer.SetWorldPoint(cameraFP) self._Renderer.WorldToDisplay() displayCoords = self._Renderer.GetDisplayPoint() selectionZ = displayCoords[2] # convert selection point into world coordinates self._Renderer.SetDisplayPoint(selectionX, selectionY, selectionZ) self._Renderer.DisplayToWorld() worldCoords = self._Renderer.GetWorldPoint() if (worldCoords[3] == 0.0): raise PyProgrammingError("Bad homogenous coordinates") return None for i in xrange(3): pickPosition[i] = worldCoords[i] / worldCoords[3] # compute ray endpoints. The ray is along the line running # from the camera position to the selection point, starting where # this line intersects the front clipping plane, and terminating # where this line intersects the back clipping plane. ray = [0.0, 0.0, 0.0] for i in xrange(3): ray[i] = pickPosition[i] - cameraPos[i] cameraDOP = self._Camera.GetDirectionOfProjection() rayLength = cameraDOP[0] * ray[0] + cameraDOP[1] * ray[1] + cameraDOP[ 2] * ray[2] if rayLength == 0.0: raise PyProgrammingError("Zero ray length") return None clipRange = self._Camera.GetClippingRange() tF = clipRange[0] / rayLength tB = clipRange[1] / rayLength p1World = [0.0, 0.0, 0.0, 0.0] p2World = [0.0, 0.0, 0.0, 0.0] for i in xrange(3): p1World[i] = cameraPos[i] + tF * ray[i] p2World[i] = cameraPos[i] + tB * ray[i] p1World[3] = p2World[3] = 1.0 # Compute the tolerance in world coordinates. Do this by # determining the world coordinates of the diagonal points of the # window, computing the width of the window in world coordinates, and # multiplying by the tolerance. viewport = self._Renderer.GetViewport() winSize = self._Renderer.GetRenderWindow().GetSize() x = winSize[0] + viewport[0] y = winSize[1] + viewport[1] self._Renderer.SetDisplayPoint(x, y, selectionZ) self._Renderer.DisplayToWorld() windowLowerLeft = self._Renderer.GetWorldPoint() x = winSize[0] + viewport[2] y = winSize[1] + viewport[3] self._Renderer.SetDisplayPoint(x, y, selectionZ) self._Renderer.DisplayToWorld() windowUpperRight = self._Renderer.GetWorldPoint() tol = 0.0 for i in xrange(3): tol += (windowUpperRight[i] - windowLowerLeft[i]) * \ (windowUpperRight[i] - windowLowerLeft[i]) tol = math.sqrt( tol) * 0.025 #self.tol # TODO 3D: set sensible tolerance # end of stuff that was basically copied from vtkPicker::Pick # at this point, p1World is the point (in world coordinates) # where the ray intersects the first clipping plane, p2Worls # is where the ray intersects the back clipping plane. tol is # the tolerance in world coordinates. # we want the point indices and/or point id of the # voxel that 1. intersects the ray 2. is in the front # 3. is within the bounds of the skeleton # simple strategy, increment along the ray by the # tolerance until we find a point that is within the # given bounds. # If we don't find something in the given bounds, then we # return the point on the near clipping plane currentPoint = p1World[0:3] lengthTraversed = 0.0 rayInClippingRange = [ p2World[0] - p1World[0], p2World[1] - p1World[1], p2World[2] - p1World[2] ] rayInCRLength = math.sqrt(rayInClippingRange[0]**2 + rayInClippingRange[1]**2 + rayInClippingRange[2]**2) direction = [ rayInClippingRange[0] / rayInCRLength, rayInClippingRange[1] / rayInCRLength, rayInClippingRange[2] / rayInCRLength ] inc = (direction[0] * tol, direction[1] * tol, direction[2] * tol) while (lengthTraversed <= rayInCRLength and point is None): if currentPoint[0] >= bounds[0] and currentPoint[0] <= bounds[1] and \ currentPoint[1] >= bounds[2] and currentPoint[1] <= bounds[3] and \ currentPoint[2] >= bounds[4] and currentPoint[2] <= bounds[5]: point = primitives.Point(currentPoint[0], currentPoint[1], currentPoint[2]) currentPoint = [ currentPoint[0] + inc[0], currentPoint[1] + inc[1], currentPoint[2] + inc[2] ] lengthTraversed += tol if point is None: point = primitives.Point(p1World[0], p1World[1], p1World[2]) return point
def move(self, x, y, shift, ctrl): # mouse move # Continue the collection of points, if it's been started... if self.points: self.points.append(primitives.Point(x,y))
def _read(self, tslfile, prog): data, hexgrid = self.readData(tslfile, prog) npts = len(data) rows = list(getrows(data)) # sorts data if hexgrid is None: # readData didn't set hexgrid. The grid is hexagonal if # the first two rows don't start at the same x. hexgrid = rows[0][0].position[0] != rows[1][0].position[0] if hexgrid: # Throw out every other row. reporter.warn("Converting hexagonal lattice to rectangular" " by discarding alternate rows.") rows = rows[::2] # discard odd numbered rows nx = len(rows[0]) ny = len(rows) count = 0 for row in rows: count += 1 if len(row) != nx: raise ooferror.ErrUserError( "Orientation map data appears to be incomplete.\n" "len(row 0)=%d len(row %d)=%d" % (nx, count, len(row))) # TSL puts the origin at the top left, so it's using a left # handed coordinate system! If flip_y==True, fix that. Also, # make sure there are no negative x or y values. ymax = rows[-1][0].position[1] ymin = rows[0][0].position[1] xmax = rows[0][-1].position[0] xmin = rows[0][0].position[0] for row in rows: for point in row: if self.flip_x: point.position[0] = xmax - point.position[0] else: point.position[0] = point.position[0] - xmin if self.flip_y: point.position[1] = ymax - point.position[1] else: point.position[1] = point.position[1] - ymin # If flipped, the rows are still ordered top to bottom, but # the coordinates increase bottom to top. # pixel size dx = abs(rows[0][1].position[0] - rows[0][0].position[0]) dy = abs(rows[0][0].position[1] - rows[1][0].position[1]) pxlsize = primitives.Point(dx, dy) width = abs(rows[0][0].position[0] - rows[0][-1].position[0]) height = abs(rows[0][0].position[1] - rows[-1][0].position[1]) # If we assume that the points are in the centers of the # pixels, then the actual physical size is one pixel bigger # than the range of the xy values. size = primitives.Point(width, height) + pxlsize od = orientmapdata.OrientMap(primitives.iPoint(nx, ny), size) prog.setMessage("%d/%d orientations" % (0, npts)) count = 0 for row in rows: for datum in row: ij = primitives.iPoint( int(round(datum.position[0] / pxlsize[0])), int(round(datum.position[1] / pxlsize[1]))) try: self.phaselists[datum.phasename].append(ij) except KeyError: self.phaselists[datum.phasename] = [ij] self.set_angle(od, ij, datum.euler()) prog.setMessage("%d/%d orientations" % (count, npts)) prog.setFraction(float(count) / npts) count += 1 if prog.stopped(): return None prog.finish() return od
def recalibrate(self, point): return primitives.Point(point.x, -point.y)
def _disp2point(mesh, elements, coords, field): # Convert displacement field OutputVals to Points return [primitives.Point(f[disp0], f[disp1]) for f in field]
def readfile(self, filename, prog, z=0): tslfile = file(filename, "r") prog.setMessage("Reading " + filename) count = 1 # line counter lines = tslfile.readlines() nlines = len(lines) data = utils.ReservableList(nlines) angletype = None for line in lines: if line[0] == '#': if line.startswith("Column 1-3", 2): if "radians" in line: angletype = "radians" else: angletype = "degrees" debug.fmsg("Angles are in %s." % angletype) else: # line[0] != '#' substrings = line.split() if len(substrings) < 5: raise ooferror.ErrUserError( "Too few numbers in line %d of %s" % (count, filename)) values = map(float, substrings[:5]) if angletype == "radians": angles = values[:3] elif angletype == "degrees": angles = map(math.radians, values[:3]) else: raise ooferror.ErrDataFileError( "Angle type not specified in TSL data file") orientation = corientation.COrientBunge(*angles) if config.dimension() == 2: point = primitives.Point(values[3], values[4]) elif config.dimension() == 3: point = primitives.Point(values[3], values[4], z) data.append( DataPoint( point, # position angles, ' '.join(substrings[10:]))) # phase name count += 1 # count actual file lines, comments and all prog.setMessage("read %d/%d lines" % (count, nlines)) prog.setFraction(float(count) / nlines) npts = len(data) debug.fmsg("read %d lines, %d data points" % (count, npts)) # We don't yet know if the points are on a rectangular or a # hexagonal lattice, so split the data up into rows. # getrows() is a generator, but we need an actual list so that # we can index into it. rows = list(getrows(data)) if len(rows) < 2: raise ooferror.ErrUserError( "Orientation map data has too few rows.") if rows[0][0].position[0] != rows[1][0].position[0]: # Must be a hexagonal lattice. Throw out every other row. reporter.warn( "Converting hexagonal lattice to rectangular by discarding alternate rows." ) rows = rows[::2] # discard odd numbered rows return rows, npts
def getPoint(self, x, y): if config.dimension() == 2: return primitives.Point(x, y) elif config.dimension() == 3: return self.gfxwindow().oofcanvas.screenCoordsTo3DCoords(x, y)
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.") # 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. else: # firstnode==lastnode, loop case. 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)
def __init__(self, pixel, size): # "pixel" is an iPoint pixel index. self.pixel = pixel pt_x = float(self.pixel[0])*size[0] + 0.5*size[0] pt_y = float(self.pixel[1])*size[1] + 0.5*size[1] self.point = primitives.Point(pt_x, pt_y)
def get_bounds(self): if parallel_enable.enabled(): return self.skeleton.localbounds else: return primitives.Rectangle(primitives.Point(0.0, 0.0), self.ms.size())
def down(self, x, y, button, shift, ctrl): self.startpoint = primitives.Point(x, y)
def select(self, immidge, pointlist, selector): ms = immidge.getMicrostructure() isize = ms.sizeInPixels() psize = primitives.Point(*ms.sizeOfPixels()) mpt = pointlist[0] selector(PointSelection(ms, mpt))
def realelement(self, skeletoncontext, mesh, index, fe_node, seg_dict, elemdict, materialfunc): # Create a real element corresponding to this skeleton # element. The elemdict argument is a dictionary (keyed by the # number of sides of the element) of MasterElement objects, # which contain the information needed to construct the real # elements. "index" is the SkeletonElement's position in the # Skeleton's list, and "fe_node" is a dictionary of real nodes # in the FEMesh, indexed by their corresponding SkeletonNode # objects. The lists give the nodes in the order in which # they were added to the element. # Be safe with indices. if self.meshindex is None: # Zero is nontrivial index. self.meshindex = index else: if index != self.meshindex: raise ooferror2.ErrPyProgrammingError( "Index mismatch in element construction.") nnewnodes = 0 ncn = len(self.nodes) # Corner nodes. # elemdict is a dictionary of MasterElements, keyed by number # of sides. elementtype = elemdict[self.nnodes()] nodes = [] # real nodes for this element for i in range(len(self.nodes)): # i.e. for each edge... c0 = self.nodes[i] nodes.append(fe_node[c0]) # Corner nodes already exist. c1 = self.nodes[(i + 1) % ncn] cset = skeletonnode.canonical_order(c0, c1) # Look up this edge in the dictionary. If it's there, # then nodes have been created on the edge already, and we # should reuse them. try: xtranodes = mesh.getEdgeNodes(cset) # The nodes were created by the neighboring element. # Since elements traverse their edges counterclockwise # when creating nodes, the preexisting nodes are in # the wrong order for the current element. xtranodes.reverse() except KeyError: # The edge wasn't in the dictionary. It's a new edge. xtranodes = [] # Loop over all protonodes on the current # edge of the new element for newproto in elementtype.protodic[i]: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 xtranodes.append(newnode) #Interface branch try: #If the segment represented by cset is a member of an #interface, then new edge nodes (xtranodes) will #not be shared by another element. test = seg_dict[cset] except KeyError: mesh.addEdgeNodes(cset, xtranodes) nodes = nodes + xtranodes # Interior nodes at the end. for newproto in elementtype.protodic['interior']: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 nodes.append(newnode) mesh.addInternalNodes(self, newnode) # Having constructed the list of nodes, call the real # element's constructor. materialfunc returns the element's # material. In normal operation, materialfunc is # SkeletonElement.realmaterial. realel = elementtype.build(self, materialfunc(self, skeletoncontext), nodes) mesh.addElement(realel) # Add to mesh. # Tell the element about its exterior edges. for edge in self.exterior_edges: realel.set_exterior(fe_node[edge[0]], fe_node[edge[1]]) return nnewnodes