def triNoneSplit(skel, anchor, itchy, scratchy, tri): # # scratchy /| | # / | | # / | A | # ____/tri| ===> ----| # anchor\ | | # \ | B | # \ | | # itchy \| | # # Exit conditions if anchor.pinned(): return [] if itchy.pinned() and scratchy.pinned(): return [] change = skeleton.ProvisionalChanges(skel) change.moveNode(anchor, position=0.5 * (itchy.position() + scratchy.position()), mobility=(itchy.movable_x() or scratchy.movable_x(), itchy.movable_y() or scratchy.movable_y())) change.removeElements(tri) change.substituteSegment( skel.getSegment(itchy, scratchy), [skel.getSegment(anchor, itchy), skel.getSegment(anchor, scratchy)]) return [change]
def mergeTriangles(self, element, skel, processed): saved = [None]*3 # saved energy through the merge newels = [None]*3 # new provisional elements from the merge sisters = [None]*3 # sisters changes = [] for i in range(3): node0 = element.nodes[i] node1 = element.nodes[(i+1)%3] sister = element.getSister(skel, node0, node1) # These are not welcome here. if (sister is None or sister.nnodes()!=3 or sister in processed or element.dominantPixel(skel.MS)!=sister.dominantPixel(skel.MS)): continue j = sister.nodes.index(node0) nodeA = sister.nodes[(j+1)%3] nodeB = element.nodes[(i+2)%3] nlist = [node0, nodeA, node1, nodeB] parents = element.getParents() + sister.getParents() change = skeleton.ProvisionalChanges(skel) change.removeElements(element, sister) change.insertElements(ProvisionalQuad(nlist, parents=parents)) changes.append(change) return changes
def tritriSwap(skel, n0, n1, tri0, tri1): # n1 # /|\ / \ # / | \ / \ # / | \ / B \ # n2/ t0| t1\n3 ===> /_______\ # \ | / \ / # \ | / \ A / # \ | / \ / # \|/ \ / # n0 # # Exit condition if (n0.pinned() and n1.pinned()): return [] n2 = tri0.nodes[(tri0.nodes.index(n1) + 1) % 3] n3 = tri1.nodes[(tri1.nodes.index(n0) + 1) % 3] parents = tri0.getParents() + tri1.getParents() A = ProvisionalTriangle([n0, n3, n2], parents=parents) B = ProvisionalTriangle([n1, n2, n3], parents=parents) change = skeleton.ProvisionalChanges(skel) change.removeElements(tri0, tri1) change.insertElements(A, B) # If source elements are 100 % homogeneous with the same dominant pixel, # resulting elements will be so. if tri0.homogeneity(skel.MS)==1. and tri1.homogeneity(skel.MS)==1. and \ tri0.dominantPixel(skel.MS)==tri1.dominantPixel(skel.MS): A.copyHomogeneity(tri0) B.copyHomogeneity(tri0) return [change]
def twoToThreeSwap(skel, tet1, tet2, sn): if (sn[0].pinned() and sn[1].pinned() and sn[2].pinned()): return [] faceToNodeMap = tet1.faceToNodeMap() unsharedNode1 = [n for n in tet1.nodes if n not in sn][0] unsharedNode2 = [n for n in tet2.nodes if n not in sn][0] change = skeleton.ProvisionalChanges(skel) change.removeElements(tet1,tet2) uniform = (tet1.homogeneity(skel.MS, False)==1. and tet2.homogeneity(skel.MS, False)==1. and \ tet1.dominantPixel(skel.MS)==tet2.dominantPixel(skel.MS)) for face in faceToNodeMap: nodes = [tet2.nodes[i] for i in face] if unsharedNode2 in nodes: nodes.reverse() nodes.append(unsharedNode1) tet = ProvisionalTetra(nodes,parents=[tet1,tet2]) if not tet.onBoundary(skel): change.insertElements(tet) if uniform: tet.copyHomogeneity(tet1) return [change]
def slashRight(skel, element): change = skeleton.ProvisionalChanges(skel) nodes = element.nodes parent = element.getParents()[:1] change.removeElements(element) change.insertElements( ProvisionalTriangle([nodes[0], nodes[1], nodes[2]], parents=parent), ProvisionalTriangle([nodes[0], nodes[2], nodes[3]], parents=parent)) return change
def fix(self, skel, element, which): nodes = element.nodes parents = element.getParents() if which%2 == 0: triangles = (ProvisionalTriangle([nodes[0], nodes[1], nodes[2]], parents=parents), ProvisionalTriangle([nodes[0], nodes[2], nodes[3]], parents=parents)) else: triangles = (ProvisionalTriangle([nodes[1], nodes[2], nodes[3]], parents=parents), ProvisionalTriangle([nodes[0], nodes[1], nodes[3]], parents=parents)) change = skeleton.ProvisionalChanges(skel) change.removeElements(element) change.insertElements(*triangles) return [change]
def quadquadSwap(skel, n0, n1, quad0, quad1): # n1 # /|\ # / | \ # / | \ [n0, n4, n2, n3] & [n4, n5, n1, n2] # n2| | |n5 [n0, n4, n5, n3] & [n5, n1, n2, n3] # |q0 |q1 | ==> # n3| | |n4 # \ | / # \ | / # \|/ # n0 # n1 # /|\ # / | \ # / | \ # n2| /n6 |n5 # | / \ | ==> [n0, n4, n6, n3] & [n3, n6, n1, n2] & # n3|/ \|n4 [n6, n4, n5, n1] # \ / n6 = (n3+n4+n1)/3. # \ / # \ / # n0 # n1 # / \ # / \ # / \ # n2|\ /|n5 # | \ / | ==> [n7, n5, n1, n2] & [n3, n0, n7, n2] & # n3| \n7 |n4 [n0, n4, n5, n7] # \ | / n7 = (n2+n0+n5)/3. # \ | / # \|/ # n0 if (n0.pinned() and n1.pinned()) and \ (quad0.dominantPixel(skel.MS) != quad1.dominantPixel(skel.MS)): return [] i = quad0.nodes.index(n1) n2 = quad0.nodes[(i + 1) % 4] n3 = quad0.nodes[(i + 2) % 4] i = quad1.nodes.index(n0) n4 = quad1.nodes[(i + 1) % 4] n5 = quad1.nodes[(i + 2) % 4] parents = quad0.getParents() + quad1.getParents() A = ProvisionalQuad([n0, n4, n2, n3], parents=parents) B = ProvisionalQuad([n4, n5, n1, n2], parents=parents) change0 = skeleton.ProvisionalChanges(skel) change0.insertElements(A, B) change0.removeElements(quad0, quad1) C = ProvisionalQuad([n0, n4, n5, n3], parents=parents) D = ProvisionalQuad([n5, n1, n2, n3], parents=parents) change1 = skeleton.ProvisionalChanges(skel) change1.insertElements(C, D) change1.removeElements(quad0, quad1) pos = (n3.position() + n4.position() + n1.position()) / 3.0 n6 = skel.newNode(pos.x, pos.y) E = ProvisionalQuad([n0, n4, n6, n3], parents=parents) F = ProvisionalQuad([n3, n6, n1, n2], parents=quad0.getParents()) G = ProvisionalQuad([n6, n4, n5, n1], parents=quad1.getParents()) change2 = skeleton.ProvisionalInsertion(skel) change2.addNode(n6) change2.insertElements(E, F, G) change2.removeElements(quad0, quad1) pos = (n2.position() + n0.position() + n5.position()) / 3.0 n7 = skel.newNode(pos.x, pos.y) H = ProvisionalQuad([n7, n5, n1, n2], parents=parents) I = ProvisionalQuad([n3, n0, n7, n2], parents=quad0.getParents()) J = ProvisionalQuad([n0, n4, n5, n7], parents=quad1.getParents()) change3 = skeleton.ProvisionalInsertion(skel) change3.addNode(n7) change3.insertElements(H, I, J) change3.removeElements(quad0, quad1) # If source elements are 100 % homogeneous with the same dominant pixel, # resulting elements will be so. if quad0.homogeneity(skel.MS)==1. and quad1.homogeneity(skel.MS)==1. and \ quad0.dominantPixel(skel.MS)==quad1.dominantPixel(skel.MS): A.copyHomogeneity(quad0) B.copyHomogeneity(quad0) C.copyHomogeneity(quad0) D.copyHomogeneity(quad0) E.copyHomogeneity(quad0) F.copyHomogeneity(quad0) G.copyHomogeneity(quad0) H.copyHomogeneity(quad0) I.copyHomogeneity(quad0) J.copyHomogeneity(quad0) return [change0, change1, change2, change3]
def triquadSwap(skel, n0, n1, tri, quad): # # n3__ n0 # | |\ # | | \ [n4, n0, n3] & [n4, n1, n2, n0] # | | \ [n4, n1, n2] & [n4, n2, n0, n3] # | | \ [n4, n1, n3] & [n1, n2, n0, n3] # | q | \ ==> [n0, n3, n2] & [n3, n4, n1, n2] # | | t /n2 # | | / # | | / # | | / # |__ |/ # n4 n1 # if (n0.pinned() and n1.pinned()) and \ (tri.dominantPixel(skel.MS) != quad.dominantPixel(skel.MS)): return [] n2 = tri.nodes[(tri.nodes.index(n1) + 1) % 3] i = quad.nodes.index(n0) n3 = quad.nodes[(i + 1) % 4] n4 = quad.nodes[(i + 2) % 4] parents = quad.getParents() + tri.getParents() A = ProvisionalQuad([n4, n1, n2, n0], parents=parents) B = ProvisionalTriangle([n4, n0, n3], parents=parents) change0 = skeleton.ProvisionalChanges(skel) change0.insertElements(A, B) change0.removeElements(quad, tri) C = ProvisionalQuad([n4, n2, n0, n3], parents=parents) D = ProvisionalTriangle([n4, n1, n2], parents=parents) change1 = skeleton.ProvisionalChanges(skel) change1.insertElements(C, D) change1.removeElements(quad, tri) E = ProvisionalQuad([n1, n2, n0, n3], parents=parents) F = ProvisionalTriangle([n4, n1, n3], parents=parents) change2 = skeleton.ProvisionalChanges(skel) change2.insertElements(E, F) change2.removeElements(quad, tri) G = ProvisionalQuad([n3, n4, n1, n2], parents=parents) H = ProvisionalTriangle([n0, n3, n2], parents=parents) change3 = skeleton.ProvisionalChanges(skel) change3.insertElements(G, H) change3.removeElements(quad, tri) # If source elements are 100 % homogeneous with the same dominant pixel, # resulting elements will be so. if tri.homogeneity(skel.MS)==1. and quad.homogeneity(skel.MS)==1. and \ tri.dominantPixel(skel.MS)==quad.dominantPixel(skel.MS): A.copyHomogeneity(tri) B.copyHomogeneity(tri) C.copyHomogeneity(tri) D.copyHomogeneity(tri) E.copyHomogeneity(tri) F.copyHomogeneity(tri) G.copyHomogeneity(tri) H.copyHomogeneity(tri) return [change0, change1, change2, change3]
def tetTetSplit(skel, obtusenode, oppnode, tet1, tet2): # obtusenode is the node in tet1 with a wide angle, oppnode is # the node in tet2 that is NOT shared between tet1 and tet2. # print "in tetTetSplit" # print obtusenode.position() changes = [] faces = tet2.faceToNodeMap() unSharedFaces = [] for face in faces: if oppnode in [tet2.nodes[i] for i in face]: unSharedFaces.append(face) sharedNodes = [] for node in tet2.nodes: if node is not oppnode: sharedNodes.append(node) midpoints = _centroidAndMidpoints(skel, sharedNodes) periodic = midpoints[-1][1] is not None # first just split the two into three, without moving the obtusenode if not periodic: change = skeleton.ProvisionalChanges(skel) change.removeElements(tet1, tet2) parents = tet1.getParents() + tet2.getParents() tetra = [] for face in unSharedFaces: nodes = [tet2.nodes[i] for i in face] nodes.reverse() nodes.append(obtusenode) change.insertElements(ProvisionalTetra(nodes, parents=parents)) print change, change.illegal(skel) #print unSharedFaces, [el.illegal() for el in change.elAfter()] changes.append(change) # for the first three midpoints, we split into two tetra #for i in range(3): # pair = (sharedNodes[i],sharedNodes[(i+1)%3]) # midpoint = midpoints[i][0] # if obtusenode.canMoveTo(midpoint): # change = skeleton.ProvisionalChanges(skel) # change.moveNode(obtusenode, midpoint) # change.removeElements(tet1, tet2) # for face in unSharedFaces: # nodes = [tet2.nodes[j] for j in face] # nodes.reverse() # nodes.append(obtusenode) # if not (pair[0] in nodes and pair[1] in nodes): # change.insertElements(ProvisionalTetra(nodes,parents=tet2.getParents())) # else: # otherneighbor = tet2.getSisterPeriodic(skel, nodes) # print midpoint, pair, otherneighbor # print "num elements", len(change.elAfter()) # for el in change.elAfter(): #if el.illegal(): # print "illegal element:" # nodes = el.nodes # for node in el.nodes: # print node.position() # testel = ProvisionalTetra([nodes[0],nodes[2],nodes[1],nodes[3]], parents=parents) # print "reordering tetra: ", testel.illegal() # if otherneighbor == None: # changes.append(change) centroid = midpoints[3][0] if obtusenode.canMoveTo(centroid): change = skeleton.ProvisionalChanges(skel) change.moveNode(obtusenode, centroid) change.removeElements(tet1, tet2) tetra = [] for face in unSharedFaces: nodes = [tet2.nodes[i] for i in face] nodes.reverse() nodes.append(obtusenode) change.insertElements( ProvisionalTetra(nodes, parents=tet2.getParents())) changes.append(change) return changes
def triTriSplit(skel, anchor, itchy, scratchy, tri1, tri2): # # # scratchy /|\ |\ # / | \ | \ # / | \ C | A\ If tri1.dominantPixel is different # /tri|tri\T0 ===> |___\ from tri2.dominantPixel ... # anchor\ 1 | 2 / | / # \ | / D | B/ # \ | / | / # itchy \|/ |/ # # # /|\ / \ # / | \ / \ # / | \ / \ If tri1.dominantPixel is the same as # /tri|tri\ ===> /_______\ from tri2.dominantPixel ... # \ 1 | 2 / \ / # \ | / \ / # \ | / \ / # \|/ \ / # # If itchy and scratchy are pinned, the process should be aborted if itchy.pinned() and scratchy.pinned(): return [] # Find the midpoint of the segment, and its periodic partner, if # it exists. midpoint, midpoint2 = _midpoints(skel, itchy, scratchy) periodic = midpoint2 is not None # Find the nodes of tri2 that correspond to itchy and scratchy. # If the border between tri and quad is a periodic boundary, these # nodes aren't the same as itchy and scratchy! if periodic: partners = itchy.getPartnerPair(scratchy) itchy2, scratchy2 = partners else: itchy2, scratchy2 = itchy, scratchy tri2nodes = tri2.nodes t0 = tri2nodes[(tri2nodes.index(itchy2) + 1) % 3] parents = tri2.getParents() changes = [] if anchor.movable_x() and anchor.movable_y() and not anchor.getPartners(): if not periodic: change0 = skeleton.ProvisionalChanges(skel) change0.moveNode(anchor, midpoint) change0.removeElements(tri1, tri2) change0.insertElements( ProvisionalTriangle([anchor, t0, scratchy], parents=parents), ProvisionalTriangle([anchor, itchy, t0], parents=parents)) else: # periodic change0 = skeleton.ProvisionalInsertion(skel) newanchor = skel.newNode(midpoint.x, midpoint.y) anchor2 = skel.newNode(midpoint2.x, midpoint2.y) newanchor.addPartner(anchor2) elsubs = [(el, el.provisionalReplacement(anchor, newanchor)) for el in anchor.aperiodicNeighborElements(skel) if el is not tri1] change0.removeElements(tri1, tri2) for oldel, newel in elsubs: change0.substituteElement(oldel, newel) change0.insertElements( ProvisionalTriangle([anchor2, t0, scratchy2], parents=parents), ProvisionalTriangle([anchor2, itchy2, t0], parents=parents)) change0.addNode(newanchor) change0.addNode(anchor2) changes.append(change0) if not periodic: change1 = skeleton.ProvisionalChanges(skel) change1.removeElements(tri1, tri2) parents = tri1.getParents() + tri2.getParents() change1.insertElements( ProvisionalTriangle([anchor, t0, scratchy], parents=parents), ProvisionalTriangle([anchor, itchy, t0], parents=parents)) changes.append(change1) return changes
def triQuadSplit(skel, anchor, itchy, scratchy, tri, quad): # If tri.dominantPixel is different from quad.dominantPixel ... # Pick the best of three configurations. # ___________ ______ ______ ______ # scratchy /| Q1 | /| | /| | | # / | | |C / | |B / | | | # / | | | / | | / | | B | # /tri| quad | ===> |/ | |/ | | | # anchor\ | | |\ B | | | |\ | # \ | | | \ | | A | | \ | # \ | | |A \ | | | |A \ | # itchy \|__________Q0 |___\| |____| |___\| # # If tri & quad have same dominantPixel and aren't separated by a # periodic boundary, consider this geometry as well: # ___________ _________ # /| | / . | # / | | / C . | # / | | / . | # /tri| quad | ===> /. B | Three different cases # \ | | \ . | as in the above # \ | | \ . | # \ | | \ A . | # \|__________| \________| # # If itchy and scratchy are pinned, the process should be aborted if itchy.pinned() and scratchy.pinned(): return [] # Find the midpoint of the segment, and its periodic partner, if # it exists. midpoint, midpointQ = _midpoints(skel, itchy, scratchy) periodic = midpointQ is not None # Find the nodes of the quad that correspond to itchy and # scratchy. If the border between tri and quad is a periodic # boundary, these nodes aren't the same as itchy and scratchy! if periodic: partners = itchy.getPartnerPair(scratchy) itchyQ, scratchyQ = partners else: itchyQ, scratchyQ = itchy, scratchy # Find nodes Q0 and Q1 quadnodes = quad.nodes itchyindex = quadnodes.index(itchyQ) q0 = quadnodes[(itchyindex + 1) % 4] q1 = quadnodes[(itchyindex + 2) % 4] parents = quad.getParents() changes = [] # Cases that move the anchor point. Don't do these at all if the # anchor is a periodic node or not otherwise movable: if anchor.movable_x() and anchor.movable_y() and not anchor.getPartners(): # Divide the quad into three triangles. The periodic case is # complicated because it has to replace the aperiodic anchor # Node with a periodic one, and that requires replacing all of # the elements connected to the anchor point. We do the # periodic and aperiodic cases completely separately here. if not periodic: change0 = skeleton.ProvisionalChanges(skel) change0.moveNode(anchor, midpoint) change0.removeElements(tri, quad) change0.insertElements( ProvisionalTriangle([anchor, itchy, q0], parents=parents), ProvisionalTriangle([anchor, q0, q1], parents=parents), ProvisionalTriangle([anchor, q1, scratchy], parents=parents)) change1 = skeleton.ProvisionalChanges(skel) change1.moveNode(anchor, midpoint) change1.removeElements(tri, quad) parents = quad.getParents() change1.insertElements( ProvisionalQuad([anchor, itchy, q0, q1], parents=parents), ProvisionalTriangle([anchor, q1, scratchy], parents=parents)) change2 = skeleton.ProvisionalChanges(skel) change2.moveNode(anchor, midpoint) change2.removeElements(tri, quad) parents = quad.getParents() change2.insertElements( ProvisionalTriangle([anchor, itchy, q0], parents=parents), ProvisionalQuad([anchor, q0, q1, scratchy], parents=parents)) else: # Three ways of moving the anchor point to the *periodic* # boundary and dividing the quad. newanchor, anchorQ, elsubs = triquadhelper(skel, tri, anchor, midpoint, midpointQ) change0 = skeleton.ProvisionalInsertion(skel) change0.removeElements(quad, tri) change0.addNode(newanchor) change0.addNode(anchorQ) for oldel, newel in elsubs: change0.substituteElement(oldel, newel) change0.insertElements( ProvisionalTriangle([anchorQ, itchyQ, q0], parents=parents), ProvisionalTriangle([anchorQ, q0, q1], parents=parents), ProvisionalTriangle([anchorQ, q1, scratchyQ], parents=parents)) newanchor, anchorQ, elsubs = triquadhelper(skel, tri, anchor, midpoint, midpointQ) change1 = skeleton.ProvisionalInsertion(skel) change1.removeElements(quad, tri) change1.addNode(newanchor) change1.addNode(anchorQ) for oldel, newel in elsubs: change1.substituteElement(oldel, newel) change1.insertElements( ProvisionalQuad([anchorQ, itchyQ, q0, q1], parents=parents), ProvisionalTriangle([anchorQ, q1, scratchyQ], parents=parents)) newanchor, anchorQ, elsubs = triquadhelper(skel, tri, anchor, midpoint, midpointQ) change2 = skeleton.ProvisionalInsertion(skel) change2.removeElements(quad, tri) change2.addNode(newanchor) change2.addNode(anchorQ) for oldel, newel in elsubs: change2.substituteElement(oldel, newel) change2.insertElements( ProvisionalTriangle([anchorQ, itchyQ, q0], parents=parents), ProvisionalQuad([anchorQ, q0, q1, scratchyQ], parents=parents)) changes.extend([change0, change1, change2]) # Cases for lazy (immobile) anchor. These can only be done if tri # and quad don't span a periodic boundary. if not periodic: change3 = skeleton.ProvisionalChanges(skel) change3.removeElements(tri, quad) parents = quad.getParents() + tri.getParents() change3.insertElements( ProvisionalTriangle([anchor, itchy, q0], parents=parents), ProvisionalTriangle([anchor, q0, q1], parents=parents), ProvisionalTriangle([anchor, q1, scratchy], parents=parents)) change4 = skeleton.ProvisionalChanges(skel) change4.removeElements(tri, quad) parents = quad.getParents() change4.insertElements( ProvisionalQuad([anchor, itchy, q0, q1], parents=parents), ProvisionalTriangle([anchor, q1, scratchy], parents=parents)) change5 = skeleton.ProvisionalChanges(skel) change5.removeElements(tri, quad) parents = quad.getParents() change5.insertElements( ProvisionalTriangle([anchor, itchy, q0], parents=parents), ProvisionalQuad([anchor, q0, q1, scratchy], parents=parents)) changes.extend([change3, change4, change5]) return changes