Пример #1
0
def mesh_thickening(mesh, thickness=1):
    """Transforms a mesh with the topology of a perforated disc into a closed mesh.

    Parameters
    ----------
    mesh : Mesh
        Mesh with the topology of a perforated disc.
    thickness : real
        Mesh thickness


    Returns
    -------
    vertices : list, None
        The vertices of the thickened mesh.
        None if thicnkess not striclty positive.
    faces : list, None
        The faces of the thickened mesh.
        None if thicnkess not striclty positive.

    """

    offset_mesh = mesh.copy()

    new_positions = {}
    for vkey in offset_mesh.vertices():
        xyz0 = offset_mesh.vertex_coordinates(vkey)
        if len(offset_mesh.vertex_neighbors(vkey)) == 0:
            xyz1 = [0, 0, 1]
        else:
            xyz1 = offset_mesh.vertex_normal(vkey)
        xyz2 = [thickness * a for a in xyz1]
        xyz = [sum(a) for a in zip(xyz0, xyz2)]
        new_positions[vkey] = xyz

    for vkey, xyz in new_positions.items():
        x, y, z = xyz
        attr = offset_mesh.vertex[vkey]
        attr['x'] = x
        attr['y'] = y
        attr['z'] = z

    mesh_flip_cycles(mesh)

    vertices, faces = join_meshes([mesh, offset_mesh])
    new_mesh = PseudoQuadMesh.from_vertices_and_faces(vertices, faces)

    n = new_mesh.number_of_vertices() / 2

    naked_edges = list(new_mesh.edges_on_boundary())
    for u, v in naked_edges:
        if u >= n:
            continue
        w = v + n
        x = u + n
        new_mesh.add_face([x, w, v, u])

    return new_mesh
Пример #2
0
def clear_faces(mesh, fkeys, vkeys):
    # groups of fkeys must be a topological disc
    # vkeys must be four vertices part of the fkeys boundary

    vertices = [mesh.vertex_coordinates(vkey) for vkey in mesh.vertices()]
    face_vertices = [mesh.face_vertices(fkey) for fkey in fkeys]

    faces_mesh = PseudoQuadMesh.from_vertices_and_faces(vertices, face_vertices)
    faces_boundary_vertices = mesh_boundaries(faces_mesh)[0]
    faces_boundary_vertices = list(reversed(faces_boundary_vertices[:-1]))

    for fkey in fkeys:
        mesh.delete_face(fkey)

    # orientation? reverse boundary vertices?
    fkey = mesh.add_face(faces_boundary_vertices)

    new_fkeys = face_propagation(mesh, fkey, vkeys)

    return new_fkeys
Пример #3
0
import compas_rhino as rhino
from compas_rhino.geometry import RhinoGeometry

from compas.datastructures.mesh import Mesh
from compas_pattern.datastructures.pseudo_quad_mesh import PseudoQuadMesh
from compas_pattern.datastructures.pseudo_quad_mesh import pqm_from_mesh
from compas_pattern.cad.rhino.utilities import draw_mesh

from compas_pattern.algorithms.editing import editing

# mesh selection
guid = rs.GetObject('get mesh')
mesh = RhinoGeometry.from_guid(guid)
vertices, faces = mesh.get_vertices_and_faces()
mesh = PseudoQuadMesh.from_vertices_and_faces(vertices, faces)

poles = rs.GetObjects('pole points', filter=1)
if poles is None:
    poles = []
poles = [rs.PointCoordinates(pole) for pole in poles]

vertices, face_vertices = pqm_from_mesh(mesh, poles)

mesh = PseudoQuadMesh.from_vertices_and_faces(vertices, face_vertices)

editing(mesh)

mesh = mesh.to_mesh()

mesh_guid = draw_mesh(mesh)
Пример #4
0
def densification(mesh, target_length, custom=True):
    """Densifies a quad mesh based on a target length.
	
	Parameters
	----------
	mesh : Mesh
		The quad mesh to densify.
	target_length : float
		Target length for densification.
	custom : bool
		User modification of density parameters.

	Returns
	-------
	dense_mesh: Mesh, None
		Densified quad mesh.
		None if not a quad mesh.

	Raises
	------
	-

	"""

    if not mesh.is_quadmesh():
        return None

    edge_groups, max_group = dual_edge_polylines(mesh)

    dual_polyedges = []
    for i in range(max_group + 1):
        dual_polyedge = []
        for u, v in edge_groups:
            if edge_groups[(u, v)] == i:
                if (v, u) not in dual_polyedge:
                    dual_polyedge.append(([u, v]))
        if len(dual_polyedge) > 0:
            dual_polyedges.append(dual_polyedge)

    # determine subdivision parameter based on target length and dual edge average length
    group_subdivision = {}
    edge_group = {}

    for i, dual_polyedge in enumerate(dual_polyedges):
        average_length = 0
        for u, v in dual_polyedge:
            average_length += mesh.edge_length(u, v)
        average_length /= len(dual_polyedge)

        subdivision_parameter = math.ceil(average_length / target_length)
        group_subdivision[i] = subdivision_parameter

        for u, v in dual_polyedge:
            edge_group[(u, v)] = i
            edge_group[(v, u)] = i

    if custom:
        # propose customization of local density
        count = 100
        while count > 0:
            count -= 1
            rs.EnableRedraw(False)
            all_dots = []
            for dual_polyedge in dual_polyedges:
                u0, v0 = dual_polyedge[0]
                group = edge_group[(u0, v0)]
                parameter = group_subdivision[group]
                dots = []
                for u, v in dual_polyedge:
                    if u > v:
                        continue
                    point = mesh.edge_midpoint(u, v)
                    group = edge_group[(u, v)]
                    parameter = int(group_subdivision[group])
                    dots.append(rs.AddTextDot(parameter, point))
                k = float(group) / float(max_group) * 255
                RGB = [k] * 3
                rs.AddGroup(group)
                rs.ObjectColor(dots, RGB)
                rs.AddObjectsToGroup(dots, group)
                all_dots += dots
            rs.EnableRedraw(True)
            dot = rs.GetObject('edge group to modify', filter=8192)
            if dot is not None:
                group = int(rs.ObjectGroups(dot)[0])
                parameter = rs.GetInteger('subdivision parameter',
                                          number=3,
                                          minimum=1)
                group_subdivision[group] = parameter
            rs.EnableRedraw(False)
            rs.DeleteObjects(all_dots)
            rs.EnableRedraw(True)
            if dot is None:
                break

    # mesh each patch
    meshes = []

    for fkey in mesh.faces():
        a, b, c, d = mesh.face_vertices(fkey)
        # exceptions if pseudo quad face with a (u, u) edge in no groups
        if (a, b) in edge_group:
            group_1 = edge_group[(a, b)]
        else:
            group_1 = edge_group[(c, d)]
        if (b, c) in edge_group:
            group_2 = edge_group[(b, c)]
        else:
            group_2 = edge_group[(d, a)]
        n = int(group_subdivision[group_1])
        m = int(group_subdivision[group_2])
        # subdivision points
        ab = [mesh.edge_point(a, b, float(i) / n) for i in range(0, n + 1)]
        bc = [mesh.edge_point(b, c, float(i) / m) for i in range(0, m + 1)]
        dc = [mesh.edge_point(d, c, float(i) / n) for i in range(0, n + 1)]
        ad = [mesh.edge_point(a, d, float(i) / n) for i in range(0, m + 1)]

        # create mesh
        vertices, face_vertices = discrete_coons_patch(ab, bc, dc, ad)
        face_mesh = PseudoQuadMesh.from_vertices_and_faces(
            vertices, face_vertices)
        meshes.append(face_mesh)

    vertices, face_vertices = join_and_weld_meshes(meshes)
    dense_mesh = PseudoQuadMesh.from_vertices_and_faces(
        vertices, face_vertices)

    # remove pseudo quads: [a, b, c, c] -> [a, b, c]
    for fkey in dense_mesh.faces():
        to_change = False
        face_vertices = dense_mesh.face_vertices(fkey)
        new_face_vertices = []
        for vkey in face_vertices:
            if len(new_face_vertices) == 0 or vkey != new_face_vertices[-1]:
                new_face_vertices.append(vkey)
            else:
                to_change = True
        if new_face_vertices[0] == new_face_vertices[-1]:
            del new_face_vertices[-1]
            to_change = True
        if to_change:
            dense_mesh.delete_face(fkey)
            dense_mesh.add_face(new_face_vertices, fkey)

    # unweld along two-sided openings

    return dense_mesh
Пример #5
0
from compas_pattern.cad.rhino.utilities import draw_mesh

guids = rs.GetObjects('get meshes')
poles = rs.GetObjects('pole points', filter=1)
if poles is None:
    poles = []
poles = [rs.PointCoordinates(pole) for pole in poles]
target_length = rs.GetReal('target length for densification', number=1)

for guid in guids:
    mesh = RhinoGeometry.from_guid(guid)
    vertices, faces = mesh.get_vertices_and_faces()
    coarse_quad_mesh = Mesh.from_vertices_and_faces(vertices, faces)

    rs.EnableRedraw(False)

    vertices, face_vertices = pqm_from_mesh(coarse_quad_mesh, poles)

    coarse_quad_mesh = PseudoQuadMesh.from_vertices_and_faces(
        vertices, face_vertices)

    quad_mesh = densification(coarse_quad_mesh, target_length)

    quad_mesh_guid = draw_mesh(quad_mesh)

    #layer = 'quad_mesh'
    #rs.AddLayer(layer)
    #rs.ObjectLayer(quad_mesh_guid, layer = layer)

    rs.EnableRedraw(True)
Пример #6
0
def start():
    # -2. layer structure
    layers = ['shape_and_features', 'delaunay_mesh', 'initial_coarse_quad_mesh', 'edited_coarse_quad_mesh', 'quad_mesh', 'pattern_topology', 'pattern_geometry']
    colours = [[255,0,0], [255, 255, 255], [0,0,0], [0,0,0], [200,200,200], [100,100,100], [0,0,0]]
    for layer, colour in zip(layers, colours):
        rs.AddLayer(layer)
        rs.LayerColor(layer, colour)
        objects = rs.ObjectsByLayer(layer)
        rs.DeleteObjects(objects)
    
    # -1. template
    coarse_quad_mesh = None
    if rs.GetString('use template?', defaultString = 'False', strings = ['True', 'False']) == 'True':
            vertices, faces = templating()
            coarse_quad_mesh = PseudoQuadMesh.from_vertices_and_faces(vertices, faces)
            if len(mesh_boundaries(coarse_quad_mesh)) == 0:
                coarse_quad_mesh_guid = draw_mesh(coarse_quad_mesh)
                rs.ObjectLayer(coarse_quad_mesh_guid, layer = 'initial_coarse_quad_mesh')
                rs.LayerVisible('initial_coarse_quad_mesh', visible = True)
                return
    
    # 0. input
    surface_guid = rs.GetObject('select surface', filter = 8)
    if surface_guid is None:
        box = bounding_box([coarse_quad_mesh.vertex_coordinates(vkey) for vkey in coarse_quad_mesh.vertices()])
        points = box[:4]
        surface_guid = rs.AddSrfPt(points)
    rs.ObjectColor(surface_guid, [255,0,0])
    surface_guid = rs.CopyObject(surface_guid)
    rs.ObjectLayer(surface_guid, 'shape_and_features')
    curve_features_guids = rs.GetObjects('select curve features', filter = 4)
    if curve_features_guids is None:
        curve_features_guids = []
    rs.ObjectColor(curve_features_guids, [255,0,0])
    curve_features_guids = rs.CopyObjects(curve_features_guids)
    rs.ObjectLayer(curve_features_guids, 'shape_and_features')
    point_features_guids = rs.GetObjects('select point features', filter = 1)
    if point_features_guids is None:
        point_features_guids = []
    rs.ObjectColor(point_features_guids, [255,0,0])
    point_features_guids = rs.CopyObjects(point_features_guids)
    rs.ObjectLayer(point_features_guids, 'shape_and_features')
    
    if coarse_quad_mesh is None:
        # 1. mapping
        discretisation = rs.GetReal('NURBS element discretisation', number = 1)
        rs.EnableRedraw(False)
        planar_boundary_polyline, planar_hole_polylines, planar_polyline_features, planar_point_features = mapping(discretisation, surface_guid, curve_features_guids = curve_features_guids, point_features_guids = point_features_guids)
        
        # 2. triangulation
        delaunay_mesh = triangulation(planar_boundary_polyline, holes = planar_hole_polylines, polyline_features = planar_polyline_features, point_features = planar_point_features)
        delaunay_mesh_remapped = delaunay_mesh.copy()
        remapping(delaunay_mesh_remapped, surface_guid)
        delaunay_mesh_guid = draw_mesh(delaunay_mesh_remapped)
        rs.ObjectLayer(delaunay_mesh_guid, layer = 'delaunay_mesh')
        rs.LayerVisible('delaunay_mesh', visible = True)
        
        # 3. decomposition
        medial_branches, boundary_polylines = decomposition(delaunay_mesh)
        
        # 4. extraction
        vertices, faces, edges_to_polyline = extraction(boundary_polylines, medial_branches)
        patch_decomposition = PseudoQuadMesh.from_vertices_and_faces(vertices, faces)
        
        # 5. conforming
        
        coarse_quad_mesh = conforming(patch_decomposition, delaunay_mesh, medial_branches, boundary_polylines, edges_to_polyline, planar_point_features, planar_polyline_features)
        
        # 6. remapping
        remapping(coarse_quad_mesh, surface_guid)
    
    rs.LayerVisible('delaunay_mesh', visible = False)
    coarse_quad_mesh_guid = draw_mesh(coarse_quad_mesh)
    rs.ObjectLayer(coarse_quad_mesh_guid, layer = 'initial_coarse_quad_mesh')
    rs.LayerVisible('initial_coarse_quad_mesh', visible = True)
    
    # 7. editing
    rs.EnableRedraw(False)
    rs.LayerVisible('initial_coarse_quad_mesh', visible = False)
    editing(coarse_quad_mesh)
    rs.EnableRedraw(True)
    thickening = rs.GetString('thicken?', defaultString = 'False', strings = ['True', 'False'])
    if thickening == 'True':
        thickness = rs.GetReal(message = 'thickness', number = 1, minimum = .0001, maximum = 1000)
        coarse_quad_mesh = mesh_thickening(coarse_quad_mesh, thickness = thickness)
        #closed_mesh_guid = draw_mesh(closed_mesh.to_mesh())
        #rs.ObjectLayer(closed_mesh_guid, layer = 'edited_coarse_quad_mesh')
        #rs.LayerVisible('edited_coarse_quad_mesh', visible = True)
        #return
    coarse_quad_mesh_guid = draw_mesh(coarse_quad_mesh.to_mesh())
    rs.ObjectLayer(coarse_quad_mesh_guid, layer = 'edited_coarse_quad_mesh')
    rs.LayerVisible('edited_coarse_quad_mesh', visible = True)
    
    
    # 8. densification
    rs.EnableRedraw(True)
    target_length = rs.GetReal('target length for densification', number = 1)
    quad_mesh = densification(coarse_quad_mesh, target_length)
    quad_mesh = quad_mesh.to_mesh()
    quad_mesh_guid = draw_mesh(quad_mesh)
    rs.ObjectLayer(quad_mesh_guid, layer = 'quad_mesh')
    rs.LayerVisible('edited_coarse_quad_mesh', visible = False)
    rs.LayerVisible('quad_mesh', visible = True)
    
    # 9. patterning
    rs.EnableRedraw(True)
    operators = ['dual', 'join', 'ambo', 'kis', 'needle', 'gyro']
    patterning_operator = rs.GetString('patterning operator', strings = operators)
    rs.EnableRedraw(False)    
    pattern_topology = patterning(quad_mesh, patterning_operator)
    pattern_topology_guid = draw_mesh(pattern_topology)
    rs.ObjectLayer(pattern_topology_guid, layer = 'pattern_topology')
    rs.LayerVisible('quad_mesh', visible = False)
    rs.LayerVisible('pattern_topology', visible = True)
    
    # 10. smoothing
    pattern_geometry = pattern_topology.copy()
    pattern_geometry.cull_vertices()
    rs.EnableRedraw(True)
    smoothing_iterations = rs.GetInteger('number of iterations for smoothing', number = 20)
    if smoothing_iterations == 0:
        pattern_geometry_guid = draw_mesh(pattern_geometry)
        rs.ObjectLayer(pattern_geometry_guid, layer = 'pattern_geometry')
        rs.LayerVisible('pattern_topology', visible = False)
        rs.LayerVisible('pattern_geometry', visible = True)
        return
    damping_value = rs.GetReal('damping value for smoothing', number = .5)
    rs.EnableRedraw(False)
    constraints, surface_boundaries = define_constraints(pattern_geometry, surface_guid, curve_constraints = curve_features_guids, point_constraints = point_features_guids)
    fixed_vertices = [vkey for vkey, constraint in constraints.items() if constraint[0] == 'point']
    mesh_smooth_area(pattern_geometry, fixed = fixed_vertices, kmax = smoothing_iterations, damping = damping_value, callback = apply_constraints, callback_args = [pattern_geometry, constraints])
    #vertex_keys = pattern_geometry.vertices()
    #vertices = [pattern_geometry.vertex_coordinates(vkey) for vkey in vertex_keys]
    #adjacency = [[vertex_keys.index(nbr) for nbr in pattern_geometry.vertex_neighbours(vkey)] for vkey in vertex_keys]
    #smooth_centroid_cpp(vertices, adjacency, fixed_vertices, kmax = smoothing_iterations, callback = apply_constraints, callback_args = [pattern_geometry, constraints])
    rs.DeleteObjects(surface_boundaries)
    pattern_geometry_guid = draw_mesh(pattern_geometry)
    rs.ObjectLayer(pattern_geometry_guid, layer = 'pattern_geometry')
    rs.LayerVisible('pattern_topology', visible = False)
    rs.LayerVisible('pattern_geometry', visible = True)
    
    print_metrics(pattern_geometry)
Пример #7
0
def apply_rule(mesh, rule):

    if rule == 'face_pole':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        face_pole(mesh, fkey)

    elif rule == 'edge_pole':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.face_halfedges(fkey)})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        edge_pole(mesh, fkey, edge)

    elif rule == 'vertex_pole':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        pole = rhino_helper.mesh_select_vertex(mesh, message='pole')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        vertex_pole(mesh, fkey, pole)

    elif rule == 'add_opening':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        face_opening(mesh, fkey)

    elif rule == 'close_opening':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        boundaries = mesh_boundaries(mesh)
        artist.draw_vertexlabels(
            text={
                key: str(key)
                for key in
                [vkey for boundary in boundaries for vkey in boundary]
            })
        artist.redraw()
        vkey = rhino_helper.mesh_select_vertex(
            mesh, message='vertex on the opening to close')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        for boundary in boundaries:
            if vkey in boundary:
                vkeys = boundary
                break

        close_opening(mesh, vkeys)

    elif rule == 'flat_corner_2':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        corner = rhino_helper.mesh_select_vertex(mesh, message='corner')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        flat_corner_2(mesh, fkey, corner)

    elif rule == 'flat_corner_3':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        corner = rhino_helper.mesh_select_vertex(mesh, message='corner')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        flat_corner_3(mesh, fkey, corner)

    elif rule == 'flat_corner_33':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        corner = rhino_helper.mesh_select_vertex(mesh, message='corner')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        flat_corner_33(mesh, fkey, corner)

    elif rule == 'split_35':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.face_halfedges(fkey)})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        split_35(mesh, fkey, edge)

    elif rule == 'split_35_diag':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        corner = rhino_helper.mesh_select_vertex(mesh, message='corner')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        split_35_diag(mesh, fkey, corner)

    elif rule == 'split_26':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.face_halfedges(fkey)})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        split_26(mesh, fkey, edge)

    elif rule == 'simple_split':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.face_halfedges(fkey)})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        simple_split(mesh, fkey, edge)

    elif rule == 'double_split':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        double_split(mesh, fkey)

    elif rule == 'insert_pole':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        pole = rhino_helper.mesh_select_vertex(mesh, message='pole')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        insert_pole(mesh, fkey, pole)

    elif rule == 'insert_partial_pole':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        pole = rhino_helper.mesh_select_vertex(mesh, message='pole')
        artist.clear_layer()
        artist.redraw()

        artist.draw_edgelabels({(u, v): "{}-{}".format(u, v)
                                for u, v in mesh.face_halfedges(fkey)
                                if u != pole and v != pole})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        insert_partial_pole(mesh, fkey, pole, edge)

    elif rule == 'singular_boundary_1':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.edges()})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(text={key: str(key) for key in edge})
        artist.redraw()
        vkey = rhino_helper.mesh_select_vertex(mesh, message='vkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        singular_boundary_1(mesh, edge, vkey)

    elif rule == 'singular_boundary_2':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_edgelabels(text={(u, v): "{}-{}".format(u, v)
                                     for u, v in mesh.edges()})
        artist.redraw()
        edge = rhino_helper.mesh_select_edge(mesh, message='edge')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(text={key: str(key) for key in edge})
        artist.redraw()
        vkey = rhino_helper.mesh_select_vertex(mesh, message='vkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        singular_boundary_2(mesh, edge, vkey)

    elif rule == 'singular_boundary_minus_1':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey = rhino_helper.mesh_select_face(mesh, message='fkey')
        artist.clear_layer()
        artist.redraw()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.face_vertices(fkey)})
        artist.redraw()
        vkey = rhino_helper.mesh_select_vertex(mesh, message='vkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        singular_boundary_minus_1(mesh, fkey, vkey)

    elif rule == 'face_strip_collapse':
        edge_groups, max_group = dual_edge_polylines(mesh)

        groups = {}

        for edge, group in edge_groups.items():
            u, v = edge
            if group in groups:
                if (v, u) not in groups[group]:
                    groups[group].append((u, v))
            else:
                groups[group] = [(u, v)]

        rs.EnableRedraw(False)
        dots = {}
        for group, edges in groups.items():
            k = float(group) / float(max_group) * 255
            RGB = [k] * 3
            rs.AddGroup(group)
            for u, v in edges:
                dot = rs.AddTextDot(group, mesh.edge_midpoint(u, v))
                dots[dot] = (u, v)
                rs.ObjectColor(dot, RGB)
                rs.AddObjectToGroup(dot, group)
        rs.EnableRedraw(True)

        dot = rs.GetObject('dual polyedge to collapse', filter=8192)
        u, v = dots[dot]
        rs.DeleteObjects(dots)

        face_strip_collapse(PseudoQuadMesh, mesh, u, v)

    elif rule == 'face_strip_insert':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        count = mesh.number_of_vertices() * 1.5
        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.vertices_on_boundary()})
        artist.redraw()
        vertex_path = [rhino_helper.mesh_select_vertex(mesh, message='vertex')]
        artist.clear_layer()
        count = mesh.number_of_vertices() * 1.5
        while count > 0:
            count -= 1
            artist.draw_vertexlabels(text={
                key: str(key)
                for key in mesh.vertex_neighbors(vertex_path[-1])
            })
            artist.redraw()
            vkey = rhino_helper.mesh_select_vertex(mesh, message='vertex')
            artist.clear_layer()
            artist.redraw()
            if vkey is None:
                break
            else:
                vertex_path.append(vkey)

        rs.DeleteLayer('mesh_artist')

        #start_pole = rs.GetInteger(message='pole at the start?', number=0, minimum=0, maximum=1)
        #end_pole = rs.GetInteger(message='pole at the end?', number=0, minimum=0, maximum=1)
        start_pole = 0
        end_pole = 0

        mesh = face_strip_insert(PseudoQuadMesh,
                                 mesh,
                                 vertex_path,
                                 pole_extremities=[start_pole, end_pole])

    elif rule == 'rotate_vertex':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.vertices()})
        artist.redraw()
        vkey = rhino_helper.mesh_select_vertex(mesh, message='vkey')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        rotate_vertex(mesh, vkey)

    elif rule == 'clear_faces':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkeys = rhino_helper.mesh_select_faces(mesh, message='fkeys')
        artist.clear_layer()
        artist.redraw()

        vertices = [mesh.vertex_coordinates(vkey) for vkey in mesh.vertices()]
        face_vertices = [mesh.face_vertices(fkey) for fkey in fkeys]

        faces_mesh = PseudoQuadMesh.from_vertices_and_faces(
            vertices, face_vertices)
        faces_boundary_vertices = mesh_boundaries(faces_mesh)[0]

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in faces_boundary_vertices})
        artist.redraw()
        vkeys = rhino_helper.mesh_select_vertices(mesh, message='vkeys')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        clear_faces(mesh, fkeys, vkeys)

    elif rule == 'add_handle':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey_1 = rhino_helper.mesh_select_face(mesh, message='fkey_1')
        artist.clear_layer()
        artist.redraw()

        artist.draw_facelabels()
        artist.redraw()
        fkey_2 = rhino_helper.mesh_select_face(mesh, message='fkey_2')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        add_handle(mesh, fkey_1, fkey_2)

    elif rule == 'close_handle':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_facelabels()
        artist.redraw()
        fkey_1 = rhino_helper.mesh_select_face(mesh, message='fkey_1')
        artist.clear_layer()
        artist.redraw()

        artist.draw_facelabels(
            text={key: str(key)
                  for key in mesh.face_neighbors(fkey_1)})
        artist.redraw()
        fkey_2 = rhino_helper.mesh_select_face(mesh, message='fkey_2')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        count = mesh.number_of_faces()
        fkeys = [fkey_1, fkey_2]
        while count > 0:
            count -= 1
            u, v = mesh.face_adjacency_halfedge(fkeys[-2], fkeys[-1])
            w = mesh.face_vertex_ancestor(fkeys[-1], v)
            x = mesh.face_vertex_ancestor(fkeys[-1], w)
            if x in mesh.halfedge[w] and mesh.halfedge[w][x] is not None:
                fkey_3 = mesh.halfedge[w][x]
                fkeys.append(fkey_3)
                if fkeys[-1] == fkeys[0]:
                    break

        close_handle(mesh, fkeys)

    elif rule == 'close_handle_2':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        edge_paths = []
        for i in range(2):

            vertex_path = []

            artist.draw_vertexlabels(
                text={key: str(key)
                      for key in mesh.vertices()})
            artist.redraw()
            vertex_path.append(
                rhino_helper.mesh_select_vertex(mesh, message='vertex'))
            artist.clear_layer()
            artist.redraw()

            count = mesh.number_of_vertices()
            while count > 0:
                count -= 1
                artist.draw_vertexlabels(
                    text={
                        key: str(key)
                        for key in mesh.vertex_neighbors(vertex_path[-1])
                    })
                artist.redraw()
                vkey = rhino_helper.mesh_select_vertex(mesh, message='vertex')
                if vkey is None:
                    break
                artist.clear_layer()
                artist.redraw()
                if vkey in list(mesh.vertices()):
                    vertex_path.append(vkey)
                else:
                    break
                if vkey == vertex_path[0]:
                    break
            del vertex_path[-1]
            edge_paths.append([[vertex_path[i - 1], vertex_path[i]]
                               for i in range(len(vertex_path))])

        rs.DeleteLayer('mesh_artist')

        edge_path_1, edge_path_2 = edge_paths

        mesh = close_handle_2(mesh, edge_path_1, edge_path_2)

    elif rule == 'move_vertices':
        artist = rhino_artist.MeshArtist(mesh, layer='mesh_artist')
        artist.clear_layer()

        artist.draw_vertexlabels(
            text={key: str(key)
                  for key in mesh.vertices()})
        artist.redraw()
        vkeys = rhino_helper.mesh_select_vertices(mesh, message='vkeys')
        artist.clear_layer()
        artist.redraw()

        rs.DeleteLayer('mesh_artist')

        x1, y1, z1 = rs.GetPoint(message='from...')
        x2, y2, z2 = rs.GetPoint(message='...to')

        for vkey in vkeys:
            attr = mesh.vertex[vkey]
            attr['x'] += x2 - x1
            attr['y'] += y2 - y1
            attr['z'] += z2 - z1

    elif rule == 'project_on_surface':
        srf = rs.GetObject('surface for projection', filter=8)
        for vkey in mesh.vertices():
            u, v = rs.SurfaceClosestPoint(srf, mesh.vertex_coordinates(vkey))
            x, y, z = rs.EvaluateSurface(srf, u, v)
            attr = mesh.vertex[vkey]
            attr['x'] = x
            attr['y'] = y
            attr['z'] = z

    return 0