def modal(geom_file, num_modes, path):
    # add shell elements from mesh ---------------------------------------------
    with open(geom_file, 'rb') as fh:
        geom_data = json.load(fh)
    mesh = Mesh.from_data(geom_data['mesh'])
    s = structure.Structure()
    s.add_nodes_elements_from_mesh(mesh, element_type='ShellElement')

    # add displacements --------------------------------------------------------
    pts = geom_data['pts']
    nkeys = []
    for pt in pts:
        nkeys.append(s.check_node_exists(pt))
    s.add_set(name='support_nodes', type='NODE', selection=nkeys)
    supppots = FixedDisplacement(name='supports', nodes='support_nodes')
    s.add_displacement(supppots)

    # add materials and sections -----------------------------------------------
    E35 = 35 * 10**9
    concrete = ElasticIsotropic(name='MAT_CONCRETE', E=E35, v=0.2, p=2400)
    s.add_material(concrete)
    section = ShellSection(name='SEC_CONCRETE', t=0.020)
    s.add_section(section)
    prop = ElementProperties(type='SHELL', material='MAT_CONCRETE', section='SEC_CONCRETE', elsets=['ELSET_ALL'])
    s.add_element_properties(prop)

    # add modal step -----------------------------------------------------------

    step = ModalStep(name='modal_analysis', displacements=['supports'], num_modes=num_modes)
    s.add_step(step)
    fnm = path + 'modal.inp'
    ansys.inp_generate(s, filename=fnm)
    # temp = path + '_Temp/'
    s.analyse(path=path, name='modal.inp', temp=None, software='ansys')
    return s
Example #2
0
def mesh_to_mesh(rhino_mesh,trg_len,vis):
    
    print rhino_mesh
    crvs = rs.DuplicateMeshBorder(rhino_mesh)
    
    
    
    vertices = [map(float, vertex) for vertex in rs.MeshVertices(rhino_mesh)]
    faces = map(list, rs.MeshFaceVertices(rhino_mesh))
    
    mesh  = Mesh.from_vertices_and_faces(vertices, faces)
    
    
    pts_objs = rs.GetObjects("Fixed Points",1)
    rs.EnableRedraw(False)
    if pts_objs:
        pts_fixed = [rs.PointCoordinates(obj) for obj in pts_objs]
        
        pts = []
        index_key = {}
        count = 0
        for k, a in mesh.vertices_iter(True):
            pts.append((a['x'], a['y'], a['z'])) 
            index_key[count] = k
            count += 1
        
        fixed = [] 
        for pt_fix in pts_fixed:
            index = rs.PointArrayClosestPoint(pts,pt_fix)
            fixed.append(index_key[index])
    
    

      
    edge_lengths = []
    for u, v in mesh.edges():
        edge_lengths.append(mesh.edge_length(u, v))
    target_start = max(edge_lengths)/2  
     
    id = rs.coerceguid(rhino_mesh, True)
    mesh_rhino_obj = rs.coercemesh(id, False)
    
    boundary = set(mesh.vertices_on_boundary())
    user_func = wrapper_2(crvs,mesh_rhino_obj,fixed,boundary,vis)
        
    rs.HideObject(rhino_mesh)
        
    remesh(mesh,trg_len,
       tol=0.1, divergence=0.01, kmax=400,
       target_start=target_start, kmax_approach=200,
       verbose=False, allow_boundary=True,
       ufunc=user_func)  
        
    rs.DeleteObject(rhino_mesh)
    return draw_light(mesh,temp = False) 
Example #3
0
def mesh_from_ansys_results(output_path):
    nodes, elements = get_nodes_elements_from_result_files(output_path)
    nkeys = sorted(nodes.keys(), key=int)
    vertices = [[nodes[k]['x'], nodes[k]['y'], nodes[k]['z']] for k in nkeys]
    fkeys = sorted(elements.keys(), key=int)
    faces = []
    for fk in fkeys:
        face = elements[fk]['topology']
        face = face[:3]
        faces.append(face)
    mesh = Mesh.from_vertices_and_faces(vertices, faces)
    return mesh
Example #4
0
def create_quad_mesh(srf,u_div,v_div):
    
  
    
    u_domain = rs.SurfaceDomain(srf, 0)
    v_domain = rs.SurfaceDomain(srf, 1)
    u = (u_domain[1] - u_domain[0]) / (u_div - 1)
    v = (v_domain[1] - v_domain[0]) / (v_div - 1)
    
    #pts =  [[None for i in range(v_div)] for j in range(u_div)]
    mesh_pts = []
    for i in xrange(u_div):
        for j in xrange(v_div):
            #pts[i][j] = rs.EvaluateSurface (srf, u_domain[0] + u * i, v_domain[0] + v * j)
            mesh_pts.append(rs.EvaluateSurface (srf, u_domain[0] + u * i, v_domain[0] + v * j))
            
    faces = []        
    for i in xrange(u_div-1):
         for j in xrange(v_div-1):       
             faces.append(((i*v_div)+j,((i+1)*v_div)+j,((i+1)*v_div)+j+1,(i*v_div)+j+1))

    mesh = Mesh()
    
    for i,pt in enumerate(mesh_pts):
        mesh.add_vertex(str(i),{'x' : pt[0], 'y' : pt[1], 'z' : pt[2]})
    
    for face in faces:
        mesh.add_face(face)  
    
    return mesh        
def harmonic(geom_file, freq_range, freq_steps, damping):
    # add shell elements from mesh ---------------------------------------------
    with open(geom_file, 'rb') as fh:
        geom_data = json.load(fh)
    mesh = Mesh.from_data(geom_data['mesh'])
    s = structure.Structure()
    s.add_nodes_elements_from_mesh(mesh, element_type='ShellElement')

    # add displacements --------------------------------------------------------
    pts = geom_data['pts']
    nkeys = []
    for pt in pts:
        nkeys.append(s.check_node_exists(pt))
    s.add_set(name='support_nodes', type='NODE', selection=nkeys)
    supppots = FixedDisplacement(name='supports', nodes='support_nodes')
    s.add_displacement(supppots)

    # add materials and sections -----------------------------------------------
    E35 = 35 * 10**9
    concrete = ElasticIsotropic(name='MAT_CONCRETE', E=E35, v=0.2, p=2400)
    s.add_material(concrete)
    section = ShellSection(name='SEC_CONCRETE', t=0.020)
    s.add_section(section)
    prop = ElementProperties(type='SHELL', material='MAT_CONCRETE', section='SEC_CONCRETE', elsets=['ELSET_ALL'])
    s.add_element_properties(prop)

    # add loads ----------------------------------------------------------------
    f_pts = geom_data['f_pts']
    nodes = [s.check_node_exists(pt) for pt in f_pts]
    s.add_set(name='load_nodes', type='NODE', selection=nodes)
    load = PointLoad(name='hload', nodes='load_nodes', x=0, y=0, z=1, xx=0, yy=0, zz=0)
    s.add_load(load)

    # add modal step -----------------------------------------------------------
    step = HarmonicStep(name='harmonic_analysis', displacements=['supports'], loads=['hload'],
                        freq_range=freq_range, freq_steps=freq_steps, damping=damping)
    s.add_step(step)
    fnm = path + 'harmonic.inp'
    ansys.inp_generate(s, filename=fnm)
    # temp = path+'_Temp/'
    s.analyse(path=path, name='harmonic.inp', temp=None, software='ansys')
    return s
    import traceback
    from json import encoder

    ipath = sys.argv[1]
    opath = sys.argv[2]

    with open(ipath, 'rb') as f:
        idict = json.load(f)

    try:
        profile = cProfile.Profile()
        profile.enable()
        # ----------------------------------------------------------------------
        # profiler enabled
        # ----------------------------------------------------------------------
        mesh = Mesh.from_data(idict['mesh'])
        main(mesh)
        data = {'mesh': mesh.to_data()}
        # ----------------------------------------------------------------------
        # profiler disabled
        # ----------------------------------------------------------------------
        profile.disable()
        stream = cStringIO.StringIO()
        stats = pstats.Stats(profile, stream=stream)
        stats.strip_dirs()
        stats.sort_stats(1)
        stats.print_stats(20)
        odict = {}
        odict['data'] = data
        odict['error'] = None
        odict['profile'] = stream.getvalue()
Example #7
0
    from compas.geometry.elements.polyhedron import Polyhedron

    from compas.datastructures.mesh.mesh import Mesh

    from compas.visualization.viewers.meshviewer import MeshViewer

    # from compas.datastructures.mesh.algorithms import subdivide_mesh_tri
    # from compas.datastructures.mesh.algorithms import subdivide_mesh_quad
    # from compas.datastructures.mesh.algorithms import subdivide_mesh_corner
    # from compas.datastructures.mesh.algorithms import subdivide_mesh_catmullclark
    # from compas.datastructures.mesh.algorithms import subdivide_mesh_doosabin

    cube = Polyhedron.generate(6)

    mesh = Mesh.from_vertices_and_faces(cube.vertices, cube.faces)

    # mesh = subdivide_mesh_tri(mesh, k=1)
    # mesh = subdivide_mesh_corner(mesh, k=1)
    # mesh = subdivide_mesh_quad(mesh, k=1)
    # mesh = subdivide_mesh_catmullclark(mesh, k=3)
    mesh = subdivide_mesh_doosabin(mesh, k=3)

    print(mesh.number_of_vertices())
    print(mesh.number_of_faces())
    print(mesh.number_of_edges())
    print(mesh.number_of_halfedges())

    viewer = MeshViewer(mesh, width=1440, height=900)

    viewer.axes_on = False
Example #8
0
def nurbs_to_mesh(srf,trg_len,vis):
    
    crvs = rs.DuplicateEdgeCurves(srf) 
    
    if len(crvs)>1:
        joint = rs.JoinCurves(crvs,True)
        if joint:
            if len(joint) > 2:
                print "hole" 
    else:
        if rs.IsCurveClosed(crvs[0]):
            joint = [crvs[0]]
            print "closed"#e.g. if it is a disk
        else:
            print "Surface need to be split"#e.g. if it is a sphere
            return None
         

    
    #sort curves (this is cheating: the longer curve is not necessarily the outer boundary!) 
    #todo: an inside outside comparison in uv space
    crvs_len = [rs.CurveLength(crv) for crv in joint] 
    crvs  = [x for (_,x) in sorted(zip(crvs_len,joint))]
    
    outer_crv =  crvs[-1]
    inner_crvs = crvs[:-1]
    
    outer_bound_pts = get_boundary_points(outer_crv,trg_len)
    if inner_crvs: inner_bounds_pts = [get_boundary_points(crvs,trg_len) for crvs in inner_crvs]
    
    all_pts = copy.copy(outer_bound_pts)
    if inner_crvs: 
        for pts in inner_bounds_pts:
            all_pts += pts
    
    outbound_keys = get_boundary_indecies(outer_bound_pts,all_pts)

    inbounds_keys = []
    if inner_crvs:
        for inner_bound_pts in inner_bounds_pts:
            inbounds_keys.append(get_boundary_indecies(inner_bound_pts,all_pts))   
     

    rs.DeleteObjects(crvs)        

    all_pts_uv = convert_to_uv_space(srf,all_pts) 
    tris = delaunay(all_pts_uv,outbound_keys,inbounds_keys)
    
    mesh = Mesh()
    
    for i,pt in enumerate(all_pts):
        mesh.add_vertex(str(i),{'x' : pt[0], 'y' : pt[1], 'z' : pt[2]})
    for tri in tris:
        mesh.add_face(tri)  
    
    edge_lengths = []
    for u, v in mesh.edges():
        edge_lengths.append(mesh.edge_length(u, v))
    
    target_start = max(edge_lengths)/2

    rs.EnableRedraw(False)
    
    srf_id = rs.coerceguid(srf, True)
    brep = rs.coercebrep(srf_id, False)   
    tolerance = rs.UnitAbsoluteTolerance()
    
    fixed = outbound_keys+[item for sublist in inbounds_keys for item in sublist]
    user_func = wrapper(brep,tolerance,fixed,vis)
    

    remesh(mesh,trg_len,
       tol=0.1, divergence=0.01, kmax=300,
       target_start=target_start, kmax_approach=150,
       verbose=False, allow_boundary=False,
       ufunc=user_func)
 
    for k in xrange(10):
        mesh_smooth_centroid(mesh,fixed=fixed,kmax=1) 
        user_func(mesh,k)
    
    return draw_light(mesh,temp = False) 
    

    
    
    


    
Example #9
0
    return f, g


# ==============================================================================
# Debugging
# ==============================================================================

if __name__ == "__main__":

    import compas
    from compas.datastructures.mesh.mesh import Mesh
    from compas.visualization.plotters.meshplotter import MeshPlotter

    data = compas.get_data('faces.obj')
    mesh = Mesh.from_obj(data)

    mesh_split_edge(mesh, 17, 32)

    print(mesh.face_vertices(11, ordered=True))
    print(mesh.face_vertices(16, ordered=True))

    print(mesh.halfedge[32][36])
    print(mesh.halfedge[36][32])

    print(mesh.halfedge[36][17])
    print(mesh.halfedge[17][36])

    plotter = MeshPlotter(mesh)

    plotter.draw_vertices()
Example #10
0
# Properties

mdl.add_element_properties([
    Properties(name='ep_concrete', material='mat_concrete', section='sec_concrete', elsets='elset_concrete'),
    Properties(name='ep_steel', material='mat_steel', section='sec_ties', elsets='elset_ties')])

# Displacements

mdl.add_displacements([
    RollerDisplacementXY(name='disp_roller', nodes='nset_corners'),
    PinnedDisplacement(name='disp_pinned', nodes='nset_corner1'),
    GeneralDisplacement(name='disp_xdof', nodes='nset_corner2', x=0)])
    
# Loads

mesh = mesh_from_guid(Mesh(), rs.ObjectsByLayer('load_mesh')[0])
mdl.add_loads([
    GravityLoad(name='load_gravity', elements='elset_concrete'),
    PrestressLoad(name='load_prestress', elements='elset_ties', sxx=50*10**6),
    TributaryLoad(mdl, name='load_tributary', mesh=mesh, z=-2000)])

# Steps

mdl.add_steps([
    GeneralStep(name='step_bc', displacements=['disp_roller', 'disp_pinned', 'disp_xdof']),
    GeneralStep(name='step_prestress', loads=['load_prestress']),
    GeneralStep(name='step_loads', loads=['load_gravity', 'load_tributary'], factor=1.1)])
mdl.steps_order = ['step_bc', 'step_prestress', 'step_loads']

# Summary
Example #11
0
def nurbs_to_mesh_ani(srf,trg_len_min,trg_len_max,vis):
    trg_len = trg_len_max
    
    
    u_div = 30
    v_div = 30
    u_domain = rs.SurfaceDomain(srf, 0)
    v_domain = rs.SurfaceDomain(srf, 1)
    u = (u_domain[1] - u_domain[0]) / (u_div - 1)
    v = (v_domain[1] - v_domain[0]) / (v_div - 1)
    

    gauss = []
    for i in xrange(u_div):
        for j in xrange(v_div):
            data = rs.SurfaceCurvature (srf, (u_domain[0] + u * i, v_domain[0] + v * j))
            gauss.append(abs(data[7]))
            pt = rs.EvaluateSurface(srf,u_domain[0] + u * i, v_domain[0] + v * j)
            #rs.AddTextDot(round(abs(data[7]),3),pt)
    gauss_max = max(gauss)
    gauss_min = min(gauss)
    
    print gauss_max
    print gauss_min
    

            
    crvs = rs.DuplicateEdgeCurves(srf) 
    
    if len(crvs)>1:
        joint = rs.JoinCurves(crvs,True)
        if joint:
            if len(joint) > 2:
                print "hole" 
    else:
        if rs.IsCurveClosed(crvs[0]):
            joint = [crvs[0]]
            print "closed"#e.g. if it is a disk
        else:
            print "Surface need to be split"#e.g. if it is a sphere
            return None
         

    
    #sort curves (this is cheating: the longer curve is not necessarily the outer boundary!) 
    #todo: an inside outside comparison in uv space
    crvs_len = [rs.CurveLength(crv) for crv in joint] 
    crvs  = [x for (_,x) in sorted(zip(crvs_len,joint))]
    
    outer_crv =  crvs[-1]
    inner_crvs = crvs[:-1]
    
    outer_bound_pts = get_boundary_points(outer_crv,trg_len)
    if inner_crvs: inner_bounds_pts = [get_boundary_points(crvs,trg_len) for crvs in inner_crvs]
    
    all_pts = copy.copy(outer_bound_pts)
    if inner_crvs: 
        for pts in inner_bounds_pts:
            all_pts += pts
    
    outbound_keys = get_boundary_indecies(outer_bound_pts,all_pts)

    inbounds_keys = []
    if inner_crvs:
        for inner_bound_pts in inner_bounds_pts:
            inbounds_keys.append(get_boundary_indecies(inner_bound_pts,all_pts))   
     

    rs.DeleteObjects(crvs)        

    all_pts_uv = convert_to_uv_space(srf,all_pts) 
    tris = delaunay(all_pts_uv,outbound_keys,inbounds_keys)
    
    mesh = Mesh()
    
    for i,pt in enumerate(all_pts):
        mesh.add_vertex(str(i),{'x' : pt[0], 'y' : pt[1], 'z' : pt[2]})
    for tri in tris:
        mesh.add_face(tri)  
    
    edge_lengths = []
    for u, v in mesh.edges():
        edge_lengths.append(mesh.edge_length(u, v))
    
    target_start = max(edge_lengths)/22

    rs.EnableRedraw(False)
    
    srf_id = rs.coerceguid(srf, True)
    brep = rs.coercebrep(srf_id, False)   
    tolerance = rs.UnitAbsoluteTolerance()
    
    fixed = outbound_keys+[item for sublist in inbounds_keys for item in sublist]
    user_func = wrapper(brep,tolerance,fixed,vis)
    

    remesh_ani(srf,mesh,trg_len_min,trg_len_max,gauss_min,gauss_max,
       tol=0.1, divergence=0.008, kmax=400,
       target_start=target_start, kmax_approach=200,
       verbose=False, allow_boundary=False,
       ufunc=user_func)
 
    for k in xrange(1):
        mesh_smooth_on_local_plane(mesh,k=1,d=0.2,fixed=fixed)  
        user_func(mesh,k)
    
    return draw_light(mesh,temp = False)    
    
    


    
Example #12
0
        faces.append(face)
    mesh = Mesh.from_vertices_and_faces(vertices, faces)
    return mesh


def ansys_remesh(mesh, output_path, filename, size=None):
    s = Structure()
    s.add_nodes_elements_from_mesh(mesh, 'ShellElement')
    s = areas_from_mesh(s, mesh)
    write_preprocess(output_path, filename)
    write_request_mesh_areas(s,
                             output_path,
                             filename,
                             size=size,
                             smart_size=None,
                             div=None)
    ansys_launch_process(s, output_path, filename)
    mesh = mesh_from_ansys_results(output_path)
    return mesh


if __name__ == '__main__':

    name = 'remesh.txt'
    path = '//Mac/Home/Desktop/ok/'

    mesh = Mesh.from_obj(compas.get_data('faces.obj'))
    mesh = Mesh.from_data(mesh.to_data())
    mesh = ansys_remesh(mesh, path, name, 0.5)
    mesh.plot()
Example #13
0
                        'start': key_xyz[u],
                        'end': key_xyz[v],
                        'color': (0.1, 0.1, 0.1),
                        'width': 1.
                    })
                xdraw_polygons(poly)
                xdraw_lines(lines)

        def keyPressAction(self, key):
            if key == Qt.Key_1:
                self.subd = self.subdfunc(self.mesh, k=1)
            if key == Qt.Key_2:
                self.subd = self.subdfunc(self.mesh, k=2)
            if key == Qt.Key_3:
                self.subd = self.subdfunc(self.mesh, k=3)
            if key == Qt.Key_4:
                self.subd = self.subdfunc(self.mesh, k=4)
            if key == Qt.Key_5:
                self.subd = self.subdfunc(self.mesh, k=5)

    poly = Polyhedron.generate(6)
    mesh = Mesh.from_vertices_and_faces(poly.vertices, poly.faces)

    app = QApplication(sys.argv)

    view = View(mesh, subdivide_mesh_doosabin)
    view.resize(640, 480)
    view.show()

    sys.exit(app.exec_())
def relax_mesh_on_surface():
    
    srf = rs.ObjectsByLayer("re_01_trg_srf")[0]
    srf_id = rs.coerceguid(srf, True)
    brep = rs.coercebrep(srf_id, False)
    
    polylines = rs.ObjectsByLayer("re_02_polys")
    pts_objs = rs.ObjectsByLayer("re_03_points")
    guides = rs.ObjectsByLayer("re_04_guides")
    
    vis = 1
    
    rs.LayerVisible("re_02_polys", False)
    rs.LayerVisible("re_03_points", False)
    
    pts = get_points_coordinates(pts_objs)
    
    mesh = Mesh()
    
    for i,pt in enumerate(pts):
        color = rs.ObjectColor(pts_objs[i])
        type, guide_srf,guide_crv = None, None, None

        if [rs.ColorRedValue(color),rs.ColorGreenValue(color),rs.ColorBlueValue(color)] == [255,0,0]:
            type = 'fixed'
        elif [rs.ColorRedValue(color),rs.ColorGreenValue(color),rs.ColorBlueValue(color)] == [255,255,255]:
            type = 'free'
        elif [rs.ColorRedValue(color),rs.ColorGreenValue(color),rs.ColorBlueValue(color)] == [0,0,0]:
            type = 'surface'
            guide_srf = brep
        else:
            type = 'guide'
            for guide in guides:
                if rs.ObjectColor(guide) == color:
                    crv_id = rs.coerceguid(guide, True)
                    crv = rs.coercecurve(crv_id, False)
                    guide_crv = crv
                    break       
            
        mesh.add_vertex(str(i),{'x' : pt[0], 'y' : pt[1], 'z' : pt[2], 'color' : color, 'type' : type,'guide_srf' : guide_srf,'guide_crv' : guide_crv})
    

    
    polys = get_polyline_points(polylines)
    tris = get_faces_from_polylines(polys,pts)
    
    for tri in tris:
        mesh.add_face(tri)     
     
     
        
    user_function = wrapper(vis)    
    fixed = [key for key, a in mesh.vertices_iter(True) if a['type'] == 'fixed']
    
    mesh_smooth_centerofmass(mesh, fixed=fixed, kmax=150, d=1.0, ufunc=user_function)
    
    #mesh_smooth_angle(mesh, fixed=fixed, kmax=150, ufunc=user_function)
    
    #mesh_smooth_centroid(mesh, fixed=fixed, kmax=150, d=1.0, ufunc=user_function)
    
    #mesh_smooth_area(mesh, fixed=fixed, kmax=150, d=1.0, ufunc=user_function)
    
    
    #draw_light(mesh,temp = False)
    
    draw(mesh,"re_03_points","re_02_polys")
Example #15
0
    s.add_step(step)
    s.set_steps_order(['harmonic_analysis'])

    # analysis -----------------------------------------------------------------
    s.path = path
    s.name = name
    fields = ['all']
    s.write_input_file('ansys', fields=fields)
    s.analyse(software='ansys', cpus=4)
    s.extract_data(software='ansys', fields=fields, steps='last')
    return s


if __name__ == '__main__':

    import compas_fea

    with open(compas_fea.get('flat20x20.json'), 'r') as fp:
        data = json.load(fp)
    mesh = Mesh.from_data(data['mesh'])
    pts = data['pts']

    freq_list = [50, 51, 52, 55]
    thick = 0.02
    damping = 0.003

    path = compas_fea.TEMP
    name = 'harmonic_pressure'

    harmonic_pressure(mesh, pts, freq_list, path, name, damping=damping)
def relax_mesh_on_surface():

    polylines = rs.ObjectsByLayer("re_02_polys")
    pts_objs = rs.ObjectsByLayer("re_03_points")

    vis = 5
    kmax = 2000
    dis = 0.3
    dev_threshold = 0.003
    angle_max = 30

    pts = get_points_coordinates(pts_objs)

    mesh = Mesh()

    for i, pt in enumerate(pts):
        mesh.add_vertex(str(i), {'x': pt[0], 'y': pt[1], 'z': pt[2]})

    polys = get_polyline_points(polylines)
    tris = get_faces_from_polylines(polys, pts)

    for tri in tris:
        mesh.add_face(tri)

    rs.EnableRedraw(False)

    pts = []
    for key, a in mesh.vertices_iter(True):

        pt1 = (a['x'], a['y'], a['z'])
        pts.append(pt1)
        vec = mesh.vertex_normal(key)
        vec = scale(normalize(vec), dis)
        pt2 = add_vectors(pt1, vec)

        pt2 = add_vectors(pt1, vec)
        a['x2'] = pt2[0]
        a['y2'] = pt2[1]
        a['z2'] = pt2[2]

        a['normal'] = vec
        #rs.AddLine(pt1,pt2)

    faces_1 = draw(mesh, dev_threshold)
    rs.HideObjects(faces_1)

    for k in range(kmax):
        nodes_top_dict = {key: [] for key in mesh.vertices()}
        polys = []
        max_distances = []
        for u, v in mesh.edges():
            pt1 = mesh.vertex_coordinates(u)
            pt2 = mesh.vertex_coordinates(v)
            pt3 = mesh.vertex[u]['x2'], mesh.vertex[u]['y2'], mesh.vertex[u][
                'z2']
            pt4 = mesh.vertex[v]['x2'], mesh.vertex[v]['y2'], mesh.vertex[v][
                'z2']
            points = [pt1, pt2, pt3, pt4]

            points = rs.coerce3dpointlist(points, True)
            rc, plane = Rhino.Geometry.Plane.FitPlaneToPoints(points)
            pt3, pt4 = [plane.ClosestPoint(pt) for pt in points[2:]]

            vec = scale(normalize(subtract_vectors(pt3, pt1)), dis)
            pt3 = add_vectors(pt1, vec)

            vec = scale(normalize(subtract_vectors(pt4, pt2)), dis)
            pt4 = add_vectors(pt2, vec)

            nodes_top_dict[u].append(pt3)
            nodes_top_dict[v].append(pt4)

            distances = [
                distance(pt1, pt2) for pt1, pt2 in zip(points[2:], [pt3, pt4])
            ]
            max_distances.append(max(distances))

        for key, a in mesh.vertices_iter(True):
            cent = centroid(nodes_top_dict[key])
            pt = mesh.vertex_coordinates(key)
            vec = subtract_vectors(cent, pt)
            norm = a['normal']

            if angle_smallest(vec, norm) < angle_max:
                a['x2'] = cent[0]
                a['y2'] = cent[1]
                a['z2'] = cent[2]

        if k % vis == 0:
            rs.Prompt(
                "Iteration {0} of {1} with with deviation sum {2}".format(
                    k, kmax, round(sum(max_distances), 4)))
            draw_light(mesh, temp=True)
        if max(max_distances) < dev_threshold or k == kmax:
            print "Iteration {0} of {1} with deviation sum {2}".format(
                k, kmax, round(sum(max_distances), 4))
            break

    dfaces_2 = draw(mesh, dev_threshold)
    rs.ShowObjects(faces_1)
    rs.EnableRedraw(True)
    print max(max_distances)