def process(self):

        verts = self.inputs['Vertices'].sv_get()

        if self.inputs['PolyEdge'].is_linked:
            poly_edge = self.inputs['PolyEdge'].sv_get()
            polyIn = True
        else:
            polyIn = False
            poly_edge = repeat_last([[]])

        verts_out = []
        poly_edge_out = []
        item_order = []

        polyOutput = polyIn and self.outputs['PolyEdge'].is_linked
        orderOutput = self.outputs['Item order'].is_linked
        vertOutput = self.outputs['Vertices'].is_linked

        if not any((vertOutput, orderOutput, polyOutput)):
            return

        if self.mode == 'XYZ':
            # should be user settable
            op_order = [(0, False), (1, False), (2, False)]

            for v, p in zip(verts, poly_edge):
                s_v = ((e[0], e[1], e[2], i) for i, e in enumerate(v))

                for item_index, rev in op_order:
                    s_v = sorted(s_v, key=itemgetter(item_index), reverse=rev)

                verts_out.append([v[:3] for v in s_v])

                if polyOutput:
                    v_index = {item[-1]: j for j, item in enumerate(s_v)}
                    poly_edge_out.append(
                        [list(map(lambda n: v_index[n], pe)) for pe in p])
                if orderOutput:
                    item_order.append([i[-1] for i in s_v])

        if self.mode == 'DIST':
            if self.inputs['Base Point'].is_linked:
                base_points = self.inputs['Base Point'].sv_get()
                bp_iter = repeat_last(base_points[0])
            else:
                bp = [(0, 0, 0)]
                bp_iter = repeat_last(bp)

            for v, p, v_base in zip(verts, poly_edge, bp_iter):
                s_v = sorted(((v_c, i) for i, v_c in enumerate(v)),
                             key=lambda v: distK(v[0], v_base))
                verts_out.append([vert[0] for vert in s_v])

                if polyOutput:
                    v_index = {item[-1]: j for j, item in enumerate(s_v)}
                    poly_edge_out.append(
                        [list(map(lambda n: v_index[n], pe)) for pe in p])
                if orderOutput:
                    item_order.append([i[-1] for i in s_v])

        if self.mode == 'AXIS':
            if self.inputs['Mat'].is_linked:
                mat = Matrix_generate(self.inputs['Mat'].sv_get())
            else:
                mat = [Matrix.Identity(4)]
            mat_iter = repeat_last(mat)

            def f(axis, q):
                if axis.dot(q.axis) > 0:
                    return q.angle
                else:
                    return -q.angle

            for v, p, m in zip(Vector_generate(verts), poly_edge, mat_iter):
                axis = m * Vector((0, 0, 1))
                axis_norm = m * Vector((1, 0, 0))
                base_point = m * Vector((0, 0, 0))
                intersect_d = [
                    intersect_point_line(v_c, base_point, axis) for v_c in v
                ]
                rotate_d = [
                    f(axis, (axis_norm + v_l[0]).rotation_difference(v_c))
                    for v_c, v_l in zip(v, intersect_d)
                ]
                s_v = ((data[0][1], data[1], i)
                       for i, data in enumerate(zip(intersect_d, rotate_d)))
                s_v = sorted(s_v, key=itemgetter(0, 1))

                verts_out.append([v[i[-1]].to_tuple() for i in s_v])

                if polyOutput:
                    v_index = {item[-1]: j for j, item in enumerate(s_v)}
                    poly_edge_out.append(
                        [list(map(lambda n: v_index[n], pe)) for pe in p])
                if orderOutput:
                    item_order.append([i[-1] for i in s_v])

        if self.mode == 'USER':
            if self.inputs['Index Data'].is_linked:
                index = self.inputs['Index Data'].sv_get()
            else:
                return

            for v, p, i in zip(verts, poly_edge, index):

                s_v = sorted([(data[0], data[1], i)
                              for i, data in enumerate(zip(i, v))],
                             key=itemgetter(0))

                verts_out.append([obj[1] for obj in s_v])

                if polyOutput:
                    v_index = {item[-1]: j for j, item in enumerate(s_v)}
                    poly_edge_out.append([[v_index[k] for k in pe]
                                          for pe in p])
                if orderOutput:
                    item_order.append([i[-1] for i in s_v])

        if vertOutput:
            self.outputs['Vertices'].sv_set(verts_out)
        if polyOutput:
            self.outputs['PolyEdge'].sv_set(poly_edge_out)
        if orderOutput:
            self.outputs['Item order'].sv_set(item_order)
예제 #2
0
    def execute(self, context):

        crv_data = context.object.data
        if len(crv_data.splines) != 2:
            #TODO, make real error
            print('ERROR, curve must have 2 splines in one object')
            return {'CANCELLED'}

        ob = context.object
        mx = ob.matrix_world

        meta_data = bpy.data.metaballs.new('Meta Wax Rim')
        meta_obj = bpy.data.objects.new('Meta Surface', meta_data)
        meta_data.resolution = .8
        meta_data.render_resolution = .8
        context.scene.objects.link(meta_obj)

        me = context.object.to_mesh(context.scene,
                                    apply_modifiers=True,
                                    settings='PREVIEW')
        bme = bmesh.new()
        bme.from_mesh(me)
        bme.verts.ensure_lookup_table()
        bme.edges.ensure_lookup_table()

        loops = edge_loops_from_bmedges(bme, [ed.index for ed in bme.edges])

        vs0 = [bme.verts[i].co for i in loops[0]]
        vs1 = [bme.verts[i].co for i in loops[1]]

        vs_even_0, eds0 = space_evenly_on_path(vs0, [(0, 1), (1, 2)], 60)
        vs_even_1, eds1 = space_evenly_on_path(vs1, [(0, 1), (1, 2)], 60)

        if (vs_even_0[0] - vs_even_1[0]).length > (vs_even_0[0] -
                                                   vs_even_1[-1]).length:
            vs_even_1.reverse()

        for i in range(1, len(vs_even_0) - 1):

            blend = -abs((i - 30) / 30) + 1

            v0_0 = vs_even_0[i]
            v1_1 = vs_even_1[i]

            v0_p1 = vs_even_0[i + 1]
            v1_p1 = vs_even_1[i + 1]

            v0_m1 = vs_even_0[i - 1]
            v1_m1 = vs_even_1[i - 1]

            mid = .5 * v0_0 + .5 * v1_1

            Z = v1_1 - v0_0
            Z.normalize()
            x0, x1 = v0_p1 - v0_m1, v1_p1 - v1_m1
            x0.normalize()
            x1.normalize()
            X = .5 * x0 + .5 * x1
            X.normalize()

            Y = Z.cross(X)
            X_c = Y.cross(Z)  #X corrected

            T = Matrix.Identity(3)
            T.col[0] = X_c
            T.col[1] = Y
            T.col[2] = Z
            quat = T.to_quaternion()

            mb = meta_data.elements.new(type=self.meta_type)
            mb.size_y = .5 * (blend * self.anterior_width +
                              (1 - blend) * self.posterior_width)
            mb.size_z = .5 * (v1_1 - v0_0).length
            mb.size_x = 2
            mb.rotation = quat
            mb.stiffness = 2
            mb.co = mid

        meta_obj.matrix_world = mx

        #if self.finalize:
        #    context.scene.update()
        #    me = meta_obj.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW')
        #    new_ob = bpy.data.objects.new('MetaSurfaceMesh', me)
        #    context.scene.objects.link(new_ob)
        #    new_ob.matrix_world = mx
        #    if meta_obj.data.materials:
        #        new_ob.data.materials.append(meta_obj.data.materials[0])
        #
        #    context.scene.objects.unlink(meta_obj)
        #    bpy.data.objects.remove(meta_obj)
        #    bpy.data.metaballs.remove(meta_data)
        bme.free()

        return {'FINISHED'}
예제 #3
0
def main(context, rand_sample, spin_res, make_sphere):
    start = time.time()
    # rand_sample = 400  #randomly select this many directions on a solid hemisphere to measure from
    # spin_res = 180   #180 steps is 0.5 degrees

    world_mx = context.object.matrix_world
    scale = world_mx.to_scale()
    trans = world_mx.to_translation()

    tr_mx = Matrix.Identity(4)
    sc_mx = Matrix.Identity(4)

    tr_mx[0][3], tr_mx[1][3], tr_mx[2][3] = trans[0], trans[1], trans[2]
    sc_mx[0][0], sc_mx[1][1], sc_mx[2][2] = scale[0], scale[1], scale[2]
    r_mx = world_mx.to_quaternion().to_matrix().to_4x4()

    me = context.object.data
    bme = bmesh.new()
    bme.from_mesh(me)

    convex_hull = bmesh.ops.convex_hull(bme,
                                        input=bme.verts,
                                        use_existing_faces=True)
    total_hull = convex_hull['geom']

    hull_verts = [item for item in total_hull if hasattr(item, 'co')]
    hull_faces = [item for item in total_hull if hasattr(item, 'no')]
    hull_bme = bmesh.new()
    #hull_bme.verts = hull_verts
    #hull_bme.faces = hull_faces

    min_mx = Matrix.Identity(4)
    min_box = bbox_orient(hull_verts, min_mx)
    min_V = bbox_vol(min_box)
    print('initial volume %f' % min_V)
    min_axis = Vector((0, 0, 1))
    min_angle = 0
    axes = []
    for i in range(0, rand_sample):
        u = random.random()
        v = random.random()

        theta = math.pi * u
        phi = math.acos(2 * v - 1)

        x = math.cos(theta) * math.sin(phi)
        y = math.sin(theta) * math.sin(phi)
        z = math.cos(phi)

        axis = Vector((x, y, z))
        axes.append(axis)
        for n in range(0, spin_res):
            angle = math.pi / 2 * n / spin_res
            rot_mx = Matrix.Rotation(angle, 4, axis)

            box = bbox_orient(hull_verts, rot_mx)
            test_V = bbox_vol(box)

            if test_V < min_V:
                min_V = test_V
                min_axis = axis
                min_angle = angle
                min_box = box
                min_mx = rot_mx
    elapsed_time = time.time() - start
    print('did %i iterations in %f seconds' %
          (rand_sample * spin_res, elapsed_time))
    print("final volume %f" % bbox_vol(min_box))
    box_verts = box_cords(min_box)
    bpy.ops.mesh.primitive_cube_add()

    fmx = tr_mx * r_mx * min_mx.inverted() * sc_mx
    context.object.matrix_world = fmx
    context.object.draw_type = 'BOUNDS'
    for i, v in enumerate(box_verts):
        context.object.data.vertices[i].co = v

    # visualize the sample vectors
    if make_sphere:
        sample_sphere = bmesh.new()
        for ax in axes:
            sample_sphere.verts.new(ax)

        sphere_me = bpy.data.meshes.new('Bound Samples')
        dest_ob = bpy.data.objects.new('Bound Samples', sphere_me)
        sample_sphere.to_mesh(sphere_me)
        context.scene.objects.link(dest_ob)
        sample_sphere.free()

    bme.free()
    def modal(self,context,event):
        context.area.tag_redraw()
        
        if event.type == 'RET' and event.value == 'PRESS':
            for drop in self.drops:
                for i in drop.ind_path:
                    self.bme.verts[i].select = True
            
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            self.bme.to_mesh(self.ob.data)
            self.bme.free()
            
            return {'FINISHED'}
          
        
        
        elif event.type == 'Q' and event.value == 'PRESS':
            n_rolling = self.roll_droplets(context)
            
            iters = 0
            while n_rolling > 5 and iters < 400:
                n_rolling = self.roll_droplets(context)
                iters += 1
                
            if iters >= 399:
                print('too much rolling')    
            
            self.consensus_count = 20    
            self.build_concensus(context)
            
            l_co = [self.bme.verts[i].co for i in self.consensus_list]
            test_no = vector_average([self.bme.verts[i].normal for i in self.consensus_list])
            test_no.normalize()
            pt, pno = calculate_plane(l_co)
            
            
            if pno.dot(test_no) < 0:
                pno *= -1
            
            self.pln_pt = pt - 5*pno
            self.pln_no = pno
                
            mx = self.ob.matrix_world
            imx = mx.inverted()
            no_mx = mx.transposed().inverted().to_3x3()
            
            
            Z = no_mx * pno
            loc = mx * pt - 5 * Z
            
            ob_y = no_mx * Vector((0,1,0))
            X = ob_y.cross(Z)
            Y = Z.cross(X)
            
            Z.normalize()
            Y.normalize()
            X.normalize()
            
            wmx = Matrix.Identity(4)
            wmx[0][0], wmx[1][0], wmx[2][0] = X[0], X[1], X[2]
            wmx[0][1], wmx[1][1], wmx[2][1] = Y[0], Y[1], Y[2]
            wmx[0][2], wmx[1][2], wmx[2][2] = Z[0], Z[1], Z[2]
            wmx[0][3], wmx[1][3], wmx[2][3] = loc[0], loc[1], loc[2]
            
            #circ_bm = bmesh.new()
            #bmesh.ops.create_circle(circ_bm, cap_ends = True, cap_tris = False, segments = 10, diameter = .5 *min(context.object.dimensions) + .5 *max(context.object.dimensions))
            
            # Finish up, write the bmesh into a new mesh
            #me = bpy.data.meshes.new("Occlusal Plane")
            #circ_bm.to_mesh(me)
            #circ_bm.free()

            # Add the mesh to the scene
            #scene = bpy.context.scene
            #obj = bpy.data.objects.new("Object", me)
            #scene.objects.link(obj)
            #obj.matrix_world = wmx
            return {'RUNNING_MODAL'}
        
        
        elif event.type == 'W' and event.value == 'PRESS':
            curv_id = self.bme.verts.layers.float['max_curve']
            
            start = time.time()
            cut_geom = self.bme.faces[:] + self.bme.verts[:] + self.bme.edges[:]
            bmesh.ops.bisect_plane(self.bme, geom = cut_geom, dist = .000001, plane_co = self.pln_pt, plane_no = self.pln_no, use_snap_center = False, clear_outer=False, clear_inner=True)
            self.bme.verts.ensure_lookup_table()
            self.bme.faces.ensure_lookup_table()
            
            
            rand_sample = list(set([random.randint(0,len(self.bme.verts)-1) for i in range(math.floor(.2 * len(self.bme.verts)))]))
            self.drops = [CuspWaterDroplet(self.bme.verts[i], self.pln_pt, self.pln_no, curv_id) for i in rand_sample]
            dur = time.time() - start
            print('took %f seconds to cut the mesh and generate drops' % dur)
            
            start = time.time()
            n_rolling = self.roll_droplets(context)
            iters = 0
            while n_rolling > 10 and iters < 100:
                n_rolling = self.roll_droplets(context)
                iters += 1
            
            self.consensus_count = 80
            self.build_concensus(context)
            
            dur = time.time() - start
            print('took %f seconds to roll the drops' % dur)
            return {'RUNNING_MODAL'}
               
        elif event.type == 'UP_ARROW' and event.value == 'PRESS':
            n_rolling = self.roll_droplets(context)
            
            iters = 0
            while n_rolling > 10 and iters < 100:
                n_rolling = self.roll_droplets(context)
                iters += 1
            return {'RUNNING_MODAL'}
        
        
        elif event.type == 'LEFT_ARROW' and event.value == 'PRESS':
            self.consensus_count -= 5
            self.build_concensus(context)
            return {'RUNNING_MODAL'}
        
        elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS':
            self.consensus_count += 5
            self.build_concensus(context)
            return {'RUNNING_MODAL'}
        
        elif event.type == 'C' and event.value == 'PRESS':
            self.build_concensus(context) 
            return {'RUNNING_MODAL'}
        
        elif event.type == 'M' and event.value == 'PRESS':
            self.merge_close_consensus_points()
            return {'RUNNING_MODAL'}
            
        elif event.type == 'B' and event.value == 'PRESS' and self.consensus_generated:
            self.fit_cubic_consensus_points()
            return {'RUNNING_MODAL'}
            
        elif event.type == 'S' and event.value == 'PRESS':
            self.sort_by_value(context)
            return {'RUNNING_MODAL'}
                   
        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            self.bme.to_mesh(self.ob.data)
            self.bme.free()
            return {'CANCELLED'}
        else:
            return {'PASS_THROUGH'}
예제 #5
0
    def load(self, context, **options):
        """load a sketchup file"""

        self.context = context
        self.reuse_material = options['reuse_material']
        self.reuse_group = options['reuse_existing_groups']
        self.max_instance = options['max_instance']
        self.render_engine = options['render_engine']
        self.component_stats = defaultdict(list)
        self.component_skip = proxy_dict()
        self.component_depth = proxy_dict()
        self.group_written = {}
        ren_res_x = context.scene.render.resolution_x
        ren_res_y = context.scene.render.resolution_y
        self.aspect_ratio = ren_res_x / ren_res_y

        skp_log(f'Importing: {self.filepath}')

        addon_name = __name__.split('.')[0]
        self.prefs = context.preferences.addons[addon_name].preferences

        _time_main = time.time()

        try:
            self.skp_model = sketchup.Model.from_file(self.filepath)
        except Exception as e:
            skp_log(f'Error reading input file: {self.filepath}')
            skp_log(e)
            return {'FINISHED'}

        if options['import_scene']:
            for s in self.skp_model.scenes:
                if s.name == options['import_scene']:
                    skp_log(f"Importing Scene '{s.name}'")
                    self.scene = s
                    self.layers_skip = [l for l in s.layers]
                    for l in s.layers:
                        skp_log(f"SKIP: {l.name}")
            if not self.layers_skip:
                skp_log('Could not find scene: {}, importing default.'.format(
                    options['import_scene']))

        if not self.layers_skip:
            self.layers_skip = [
                l for l in self.skp_model.layers if not l.visible
            ]

        skp_log('Skipping Layers ... ')

        for l in sorted([l.name for l in self.layers_skip]):
            skp_log(l)

        self.skp_components = proxy_dict(
            self.skp_model.component_definition_as_dict)

        skp_log(f'Parsed in {(time.time() - _time_main):.4f} sec.')

        if options['scenes_as_camera']:
            for s in self.skp_model.scenes:
                self.write_camera(s.camera, s.name)

        if options['import_camera']:
            if self.scene:
                active_cam = self.write_camera(self.scene.camera,
                                               name=self.scene.name)
                context.scene.camera = active_cam
            else:
                active_cam = self.write_camera(self.skp_model.camera)
                context.scene.camera = active_cam

        _t1 = time.time()
        self.write_materials(self.skp_model.materials)

        skp_log(f'Materials imported in {(time.time() - _t1):.4f} sec.')

        _t1 = time.time()
        D = SKP_util()
        SKP_util.layers_skip = self.layers_skip

        for c in self.skp_model.component_definitions:
            self.component_depth[c.name] = D.component_deps(c.entities)

        skp_log(f'Component depths analyzed in {(time.time() - _t1):.4f} sec.')

        self.write_duplicateable_groups()

        if options["dedub_only"]:
            return {'FINISHED'}

        self.component_stats = defaultdict(list)
        self.write_entities(self.skp_model.entities, "Sketchup",
                            Matrix.Identity(4))

        for k, _v in self.component_stats.items():
            name, mat = k
            if options['dedub_type'] == "VERTEX":
                self.instance_group_dupli_vert(name, mat, self.component_stats)
            else:
                self.instance_group_dupli_face(name, mat, self.component_stats)

        skp_log(f'Entities imported in {(time.time() - _t1):.4f} sec.')
        skp_log('Finished importing in %.4f sec.\n' %
                (time.time() - _time_main))

        return {'FINISHED'}
예제 #6
0
def _convert_cycles_world(exporter, scene, world, is_viewport_render):
    definitions = {
        "importance": world.luxcore.importance,
    }

    node_tree = world.node_tree

    if not world.use_nodes or not node_tree:
        if not _define_constantinfinite(definitions, list(world.color)):
            return None

    output_node = node_tree.get_output_node("CYCLES")
    if not output_node:
        return None

    surface_node = utils_node.get_linked_node(output_node.inputs["Surface"])
    if not surface_node:
        return None

    if surface_node.bl_idname == "ShaderNodeBackground":
        gain = surface_node.inputs["Strength"].default_value

        color_socket = surface_node.inputs["Color"]
        color_node = utils_node.get_linked_node(color_socket)

        if color_node:
            if color_node.bl_idname == "ShaderNodeRGB":
                color = list(color_node.outputs[0].default_value)[:3]
                if not _define_constantinfinite(definitions, color):
                    return None
            elif color_node.bl_idname == "ShaderNodeTexEnvironment":
                image = color_node.image
                if not image:
                    image_missing = True
                else:
                    try:
                        filepath = ImageExporter.export_cycles_node_reader(
                            image)
                        image_missing = False
                        definitions["type"] = "infinite"
                        definitions["file"] = filepath
                        definitions[
                            "gamma"] = 2.2 if image.colorspace_settings.name == "sRGB" else 1

                        # Transformation
                        mapping_node = utils_node.get_linked_node(
                            color_node.inputs["Vector"])
                        if mapping_node:
                            # TODO fix transformation
                            raise NotImplementedError(
                                "Mapping node not supported yet")

                            # tex_loc = Matrix.Translation(mapping_node.inputs["Location"].default_value)
                            #
                            # tex_sca = Matrix()
                            # scale = mapping_node.inputs["Scale"].default_value
                            # tex_sca[0][0] = scale.x
                            # tex_sca[1][1] = scale.y
                            # tex_sca[2][2] = scale.z
                            #
                            # # Prevent "singular matrix in matrixinvert" error (happens if a scale axis equals 0)
                            # for i in range(3):
                            #     if tex_sca[i][i] == 0:
                            #         tex_sca[i][i] = 0.0000000001
                            #
                            # rotation = mapping_node.inputs["Rotation"].default_value
                            # tex_rot0 = Matrix.Rotation(rotation.x, 4, "X")
                            # tex_rot1 = Matrix.Rotation(rotation.y, 4, "Y")
                            # tex_rot2 = Matrix.Rotation(rotation.z, 4, "Z")
                            # tex_rot = tex_rot0 @ tex_rot1 @ tex_rot2
                            #
                            # transformation = tex_loc @ tex_rot @ tex_sca
                        else:
                            infinite_fix = Matrix.Scale(1.0, 4)
                            infinite_fix[0][
                                0] = -1.0  # mirror the hdri map to match Cycles and old LuxBlend
                            transformation = infinite_fix @ Matrix.Identity(
                                4).inverted()

                        definitions["transformation"] = utils.matrix_to_list(
                            transformation)
                    except OSError as image_missing:
                        LuxCoreErrorLog.add_warning("World: " +
                                                    str(image_missing))
                        image_missing = True

                if image_missing:
                    _define_constantinfinite(definitions, MISSING_IMAGE_COLOR)
            elif color_node.bl_idname == "ShaderNodeTexSky":
                if color_node.sky_type != "HOSEK_WILKIE":
                    LuxCoreErrorLog.add_warning(
                        "World: Unsupported sky type: " + color_node.sky_type)

                definitions["type"] = "sky2"
                definitions["ground.enable"] = False
                definitions["groundalbedo"] = [color_node.ground_albedo] * 3
                definitions["turbidity"] = color_node.turbidity
                definitions["dir"] = list(color_node.sun_direction)
                # Found by eyeballing, not super precise
                gain *= 0.000014
        else:
            # No color node linked
            definitions["type"] = "constantinfinite"
            # Alpha not supported
            color = list(color_socket.default_value)[:3]
            if not _define_constantinfinite(definitions, color):
                return None
    else:
        raise Exception("Unsupported node type:", surface_node.bl_idname)

    if gain == 0:
        return None

    definitions["gain"] = [gain] * 3
    return definitions
예제 #7
0
def make_bmesh_geometry(node, obj_index, context, verts, *topology):
    collection = context.scene.collection
    meshes = bpy.data.meshes
    objects = bpy.data.objects
    islands = None

    edges, faces, matrix = topology
    name = node.basedata_name + '.' + str("%04d" % obj_index)

    if name in objects:
        sv_object = objects[name]
    else:
        temp_mesh = default_mesh(name)
        sv_object = objects.new(name, temp_mesh)
        collection.objects.link(sv_object)

    # book-keeping via ID-props!? even this is can be broken by renames
    sv_object['idx'] = obj_index
    sv_object['madeby'] = node.name
    sv_object['basedata_name'] = node.basedata_name

    mesh = sv_object.data
    current_count = len(mesh.vertices)
    propose_count = len(verts)
    difference = (propose_count - current_count)
    ''' With this mode you make a massive assumption about the
        constant state of geometry. Assumes the count of verts
        edges/faces stays the same, and only updates the locations

        node.fixed_verts is not suitable for initial object creation
        but if over time you find that the only change is going to be
        vertices, this mode can be switched to to increase efficiency
    '''
    if node.fixed_verts and difference == 0:
        f_v = list(itertools.chain.from_iterable(verts))
        mesh.vertices.foreach_set('co', f_v)
        mesh.update()
    else:
        ''' get bmesh, write bmesh to obj, free bmesh'''
        bm = bmesh_from_pydata(verts,
                               edges,
                               faces,
                               normal_update=node.calc_normals)
        bm.to_mesh(sv_object.data)
        if node.randomize_vcol_islands:
            islands = find_islands_treemap(bm)
        bm.free()

        sv_object.hide_select = False

    if node.randomize_vcol_islands:
        set_vertices(sv_object, islands)

    if matrix:
        # matrix = matrix_sanitizer(matrix)
        if node.extended_matrix:
            sv_object.data.transform(matrix)
            sv_object.matrix_local = Matrix.Identity(4)
        else:
            sv_object.matrix_local = matrix
    else:
        sv_object.matrix_local = Matrix.Identity(4)
예제 #8
0
def CreateFaceEdgeRotation(context, obj, force_stay_editmode, flip_normal,
                           flip_line, flip_tangent, empty_origin_index,
                           map_normal, map_line, map_tangent):

    error_message = ErrorMessage.none
    vertex_select_amount = 0
    vertices = []

    #TODO: not sure about this mode changing weirdness
    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.mode_set(mode='EDIT')

    for i in context.active_object.data.vertices:
        if i.select:

            vertices.append(i)
            vertex_select_amount += 1

    mat = Matrix.Identity(4)

    if vertex_select_amount == 3:

        if empty_origin_index == 0:

            #Get the vertex coordinate from the index
            localCoord0 = vertices[0].co
            localCoord1 = vertices[1].co
            localCoord2 = vertices[2].co

        if empty_origin_index == 1:
            localCoord0 = vertices[1].co
            localCoord1 = vertices[2].co
            localCoord2 = vertices[0].co

        if empty_origin_index == 2:
            localCoord0 = vertices[2].co
            localCoord1 = vertices[0].co
            localCoord2 = vertices[1].co

        #Transform from local to global
        globalCoord0 = obj.matrix_world * localCoord0
        globalCoord1 = obj.matrix_world * localCoord1
        globalCoord2 = obj.matrix_world * localCoord2

        vertex_position_origin = globalCoord0

        #Calculate the normal from 3 points
        line_vector = globalCoord1 - globalCoord0
        line_vector.normalize()
        line_vector1 = globalCoord2 - globalCoord0
        line_vector1.normalize()

        normal_vector = line_vector.cross(line_vector1)
        normal_vector.normalize()

        tangent_vector = normal_vector.cross(line_vector)
        tangent_vector.normalize()

        if flip_normal is True:
            normal_vector = normal_vector * -1

        if flip_line is True:
            line_vector = line_vector * -1

        if flip_tangent == True:
            tangent_vector = tangent_vector * -1

        if force_stay_editmode is False:
            bpy.ops.object.mode_set(mode='OBJECT')

        #All the axis have to be different (we can't have x, x, z for example)
        if (map_normal != map_line) and (map_normal != map_tangent) and (
                map_line != map_tangent):

            #matrix order: x=0 y=1 z=2 position=3
            if map_line == 'x':
                mat.col[0] = line_vector.to_4d()
            if map_line == 'y':
                mat.col[1] = line_vector.to_4d()
            if map_line == 'z':
                mat.col[2] = line_vector.to_4d()

            if map_normal == 'x':
                mat.col[0] = normal_vector.to_4d()
            if map_normal == 'y':
                mat.col[1] = normal_vector.to_4d()
            if map_normal == 'z':
                mat.col[2] = normal_vector.to_4d()

            if map_tangent == 'x':
                mat.col[0] = tangent_vector.to_4d()
            if map_tangent == 'y':
                mat.col[1] = tangent_vector.to_4d()
            if map_tangent == 'z':
                mat.col[2] = tangent_vector.to_4d()

            mat.col[3] = vertex_position_origin.to_4d()

            #The coordinate system must be right handed
            if IsMatrixRightHanded(mat):
                return True, "", mat

            else:
                error_message = ErrorMessage.not_right_handed
                return False, error_message, mat

        else:
            #Invalid axis mapping, so stay in edit mode
            bpy.ops.object.mode_set(mode='EDIT')
            error_message = ErrorMessage.two_axis_same
            return False, error_message, mat

    #No edge was selected, so stay in edit mode
    else:
        bpy.ops.object.mode_set(mode='EDIT')

        #Deselect all to work around the bug which causes an edge to appear
        #selected in the 3d view while it is not.
        bpy.ops.mesh.select_all(action='DESELECT')

        error_message = ErrorMessage.edge_invalid
        return False, error_message, mat
예제 #9
0
def export_bone(bone, bones, materials, mesh, meshes, group_names):
    """ Returns (bone_data, other_data, ptrs) where:
    bone_data: AlignedBytes is the bytestring of the bone
    name_data: [AlignedBytes] is a list of relevant detached bytestrings
    ptrs: [BytesPtr] is a list of relevant pointers
    
    If bone is None, the model is exported as rooms, so mesh and meshes must be provided.
    """
    bytestr = bytearray()
    aligned = AlignedBytes(bytestr, 4)

    num_bones = len(bones) if bone else len(meshes)
    # Bone ID
    bone_id = bones.find(bone.name) if bone else meshes.index(mesh)
    bytestr += from_uint(bone_id, 4)
    
    # Name
    name_bytes = AlignedBytes(str_to_cstr(bone.name if bone else "r" + str(bone_id)), 1)
    bytestr += from_uint(0, 4)
    name_ptr = BytesPtr(aligned, 4, name_bytes, 0, 4)

    # Offset to parent
    bytestr += from_int(bones.find(bone.parent.name) - bone_id \
            if bone and bone.parent else 0, 2)
    # Has children
    bytestr += from_uint(len(bone.children) > 0 if bone else 0, 2)
    # Next sibling
    sibling_id = 1 if bone_id < num_bones - 1 else 0
    if bone:
        later_siblings = [b for b in bones[bone_id + 1:] if b.parent == bone.parent]
        sibling_id = bones.find(later_siblings[0].name) - bone_id if later_siblings else 0
    bytestr += from_int(sibling_id, 2)
    bytestr += from_uint(0, 2) # padding
    
    # Transform
    transform = bone.matrix_local if bone else Matrix.Identity(4)
    if bone and bone.parent:
        transform = bone.parent.matrix_local.inverted() * transform

    bytestr += from_vec(transform.to_scale(), 4, 12)
    euler = transform.to_euler('XYZ')
    for e in euler:
        bytestr += from_deg(math.degrees(e) / 16) # division by 16 because of format
    bytestr += from_uint(0, 2) # padding
    bytestr += from_vec(transform.to_translation(), 4, 12)

    # Materials and display lists
    indexes = None
    if bone:
        # verts = {i for i,v in enumerate(mesh.vertices) if 
        #         group_names[v.groups[0].group if v.groups else 0] == bone.name}
        # indexes = {p.material_index for p in mesh.polygons if set(p.vertices) & verts}
        indexes = list(range(len(materials))) if bone_id == 0 else []
    else:
        start = sum(len(m.materials) for m in meshes[:bone_id])
        indexes = list(range(start, start + len(materials)))
    bytestr += from_uint(len(indexes), 4)
    bytestr += from_uint(0, 4) * 2 # placeholder pointers

    ids = lambda: AlignedBytes(from_uint_list(indexes, 1), 1)
    mat_ids = ids()
    dl_ids = ids()
    mat_ptr = BytesPtr(aligned, 0x34, mat_ids, 0, 4)
    dl_ptr =  BytesPtr(aligned, 0x38, dl_ids,  0, 4)

    # Billboard
    bytestr += from_uint(0, 4) # No billboard

    return (aligned, [name_bytes, mat_ids, dl_ids], [name_ptr, mat_ptr, dl_ptr])
예제 #10
0
def get_scale_mat(vec_scale):
    mat_scale = Matrix.Identity(4)
    mat_scale[0][0] = vec_scale.x
    mat_scale[1][1] = vec_scale.y
    mat_scale[2][2] = vec_scale.z
    return mat_scale
예제 #11
0
 def getValue(self):
     return Matrix.Identity(4)
예제 #12
0
    def execute(self, context):
        settings = get_settings()
        dbg = settings.debug
        #if bpy.context.mode != 'OBJECT':
        #    bpy.ops.object.mode_set(mode = 'OBJECT')

        sce = context.scene
        #n = sce.odc_implant_index
        #implant_space = sce.odc_implants[n]

        implants = odcutils.implant_selection(context)
        layers_copy = [layer for layer in context.scene.collection.all_objects]
        context.scene.collection.all_objects[0]

        if implants != []:

            for implant_space in implants:
                #check if space already has an implant object.
                #if so, delete, replace, print warning
                if implant_space.implant and implant_space.implant in bpy.data.objects:
                    self.report({
                        'WARNING'
                    }, "replacing the existing implant with the one you chose")
                    Implant = bpy.data.objects[implant_space.implant]

                    #the origin/location of the implant is it's apex
                    L = Implant.location.copy()

                    world_mx = Implant.matrix_world.copy()

                    #the platorm is the length of the implant above the apex, in the local Z direction
                    #local Z positive is out the apex, soit's negative.
                    #Put the cursor there
                    sce.cursor.location = L - Implant.dimensions[
                        2] * world_mx.to_3x3() @ Vector((0, 0, 1))

                    #first get rid of children...so we can use the
                    #parent to find out who the children are
                    if Implant.children:
                        for child in Implant.children:
                            sce.objects.unlink(child)
                            child.user_clear()
                            bpy.data.objects.remove(child)

                    #unlink it from the scene, clear it's users, remove it.
                    sce.objects.unlink(Implant)
                    Implant.user_clear()
                    #remove the object
                    bpy.data.objects.remove(Implant)

                #TDOD what about the children/hardwares?
                else:
                    world_mx = Matrix.Identity(4)

                world_mx[0][3] = sce.cursor.location[0]
                world_mx[1][3] = sce.cursor.location[1]
                world_mx[2][3] = sce.cursor.location[2]

                #is this more memory friendly than listing all objects?
                current_obs = [ob.name for ob in bpy.data.objects]

                #link the new implant from the library
                odcutils.obj_from_lib(settings.imp_lib, self.imp)

                #this is slightly more robust than trusting we don't have duplicate names.
                for ob in bpy.data.objects:
                    if ob.name not in current_obs:
                        Implant = ob

                context.collection.objects.link(Implant)

                #this relies on the associated hardware objects having the parent implant
                #name inside them
                if self.hardware:
                    current_obs = [ob.name for ob in bpy.data.objects]

                    inc = self.imp + '_'
                    hardware_list = odcutils.obj_list_from_lib(
                        settings.imp_lib, include=inc)
                    print(hardware_list)
                    for ob in hardware_list:
                        odcutils.obj_from_lib(settings.imp_lib, ob)

                    for ob in bpy.data.objects:
                        if ob.name not in current_obs:
                            context.collection.objects.link(ob)
                            ob.parent = Implant
                            ob.layers[11] = True

                delta = Implant.dimensions[2] * world_mx.to_3x3() @ Vector(
                    (0, 0, 1))
                print(delta.length)
                world_mx[0][3] += delta[0]
                world_mx[1][3] += delta[1]
                world_mx[2][3] += delta[2]

                Implant.matrix_world = world_mx

                if sce.odc_props.master:
                    Master = bpy.data.objects[sce.odc_props.master]
                    odcutils.parent_in_place(Implant, Master)
                else:
                    self.report({
                        'WARNING'
                    }, 'No Master Model, placing implant anyway, moving objects may not preserve spatial relationships'
                                )

                #looks a little redundant, but it ensure if any
                #duplicates exist our referencing stays accurate
                Implant.name = implant_space.name + '_' + Implant.name
                implant_space.implant = Implant.name

                odcutils.layer_management(sce.odc_implants, debug=dbg)

        else:
            world_mx = Matrix.Identity(4)
            world_mx[0][3] = sce.cursor.location[0]
            world_mx[1][3] = sce.cursor.location[1]
            world_mx[2][3] = sce.cursor.location[2]

            #is this more memory friendly than listing all objects?
            current_obs = [ob.name for ob in bpy.data.objects]

            #link the new implant from the library
            odcutils.obj_from_lib(settings.imp_lib, self.imp)

            #this is slightly more robust than trusting we don't have duplicate names.
            for ob in bpy.data.objects:
                if ob.name not in current_obs:
                    Implant = ob

            context.collection.objects.link(Implant)
            Implant.matrix_world = world_mx

        for i, layer in enumerate(layers_copy):
            context.scene.collection.all_objects[i] = layer
        context.scene.collection.all_objects[11] = True
        return {'FINISHED'}
예제 #13
0
파일: __init__.py 프로젝트: u3dreal/pyslapi
    def load(self, context, **options):
        """load a sketchup file"""

        self.context = context
        self.reuse_material = options['reuse_material']
        self.reuse_group = options['reuse_existing_groups']
        self.max_instance = options['max_instance']
        # self.render_engine = options['render_engine']
        self.component_stats = defaultdict(list)
        self.component_skip = proxy_dict()
        self.component_depth = proxy_dict()
        self.group_written = {}
        ren_res_x = context.scene.render.resolution_x
        ren_res_y = context.scene.render.resolution_y
        self.aspect_ratio = ren_res_x / ren_res_y

        if LOGS:
            skp_log(f'Importing: {self.filepath}')

        addon_name = __name__.split('.')[0]
        self.prefs = context.preferences.addons[addon_name].preferences

        _time_main = time.time()

        try:
            self.skp_model = sketchup.Model.from_file(self.filepath)
        except Exception as e:
            if LOGS:
                skp_log(f'Error reading input file: {self.filepath}')
                skp_log(e)
            return {'FINISHED'}

        if options['import_scene']:
            options['scenes_as_camera'] = False
            options['import_camera'] = True
            for s in self.skp_model.scenes:
                if s.name == options['import_scene']:
                    if not MIN_LOGS:
                        skp_log(f"Importing Scene '{s.name}'")
                    self.scene = s
                    # s.layers are the invisible layers
                    self.layers_skip = [l for l in s.layers]
                    # for l in s.layers:
                    #     skp_log(f"SKIP: {l.name}")
            if not self.layers_skip and not MIN_LOGS:
                skp_log("Scene: '{}' didn't have any invisible layers.".format(
                    options['import_scene']))

        # if not self.layers_skip:
        #     self.layers_skip = [
        #         l for l in self.skp_model.layers if not l.visible
        #     ]

        if self.layers_skip != [] and not MIN_LOGS:
            hidden_layers = [l.name for l in self.layers_skip]
            print('SU | Invisible Layer(s)/Tag(s): \r', end='')
            print(*hidden_layers, sep=', ')

        # for l in sorted([l.name for l in self.layers_skip]):
        #     skp_log(l)

        self.skp_components = proxy_dict(
            self.skp_model.component_definition_as_dict)

        if DEBUG:
            u_comps = [k for k, v in self.skp_components.items()]
            print(f'Components: {len(u_comps)} ||| \r', end='')
            print(*u_comps, sep=', ')

        if not MIN_LOGS:
            skp_log(f'Parsed in {(time.time() - _time_main):.4f} sec.')

        create_nested_collection('SKP Scenes (as Cameras)')

        if options['scenes_as_camera']:
            for s in self.skp_model.scenes:
                self.write_camera(s.camera, s.name)

        if options['import_camera']:
            if self.scene:
                active_cam = self.write_camera(self.scene.camera,
                                               name=self.scene.name)
                context.scene.camera = active_cam
            else:
                active_cam = self.write_camera(self.skp_model.camera)
                context.scene.camera = active_cam

        _time_material = time.time()
        self.write_materials(self.skp_model.materials)

        if not MIN_LOGS:
            skp_log('Materials imported ' +
                    f'in {(time.time() - _time_material):.4f} sec.')

        _time_analyze_depth = time.time()

        D = SKP_util()
        SKP_util.layers_skip = self.layers_skip

        for c in self.skp_model.component_definitions:
            self.component_depth[c.name] = D.component_deps(c.entities)

            if DEBUG:
                print(f'\n-- Comp Depth: {self.component_depth[c.name]}\r',
                      end='')
                print(f' ({c.name}) --')
                print(f'Instances: {c.numInstances}')
                print(f'Instances Used: {c.numUsedInstances}\n')

        if not MIN_LOGS:
            skp_log('Component depths analyzed ' +
                    f'in {(time.time() - _time_analyze_depth):.4f} sec.')

        self.write_duplicateable_groups()

        if options["dedub_only"]:
            return {'FINISHED'}

        # self.component_stats = defaultdict(list)

        _time_mesh_data = time.time()

        create_nested_collection('SKP Mesh Objects')

        self.write_entities(self.skp_model.entities, "_(Loose Entity)",
                            Matrix.Identity(4))

        for k, _v in self.component_stats.items():
            name, mat = k
            if options['dedub_type'] == "VERTEX":
                self.instance_group_dupli_vert(name, mat, self.component_stats)
            else:
                self.instance_group_dupli_face(name, mat, self.component_stats)

        if not MIN_LOGS:
            skp_log('Entities imported ' +
                    f'in {(time.time() - _time_mesh_data):.4f} sec.')

        if LOGS:
            skp_log('Finished entire importing process in %.4f sec.\n' %
                    (time.time() - _time_main))

        # hide_one_level()

        return {'FINISHED'}
예제 #14
0
    def invoke(self, context, event):
        if context.object:
            #self.value_fix_x = 0
            #self.value_fix_y = 0
            #self.value_fix_z = 0

            #################
            # for 360 array #
            #################
            self.bend360 = False
            self.vert = self.tag_vert()

            print("TV:", self.vert)

            self.Q = [Quaternion((1, 0, 0, 0))] * 3
            self.Q[1] = Quaternion((0.707, 0.707, 0, 0))  #Y
            self.Q[2] = Quaternion((0.707, 0, 0.707, 0))  #Z

            #mesh dupe
            self.mesh = context.object.data
            self.mesh_bu = context.object.data.copy()

            self.start_rot = bpy.context.object.rotation_quaternion.copy()
            self.start_mat = Matrix.Identity(4)
            self.start_mat.translation = bpy.context.object.matrix_world.translation

            ##############

            self.first_mouse_x = event.mouse_x
            self.first_value = context.object.location.x

            cArrID = -1
            n = -1

            is_array = False
            for mode in bpy.context.object.modifiers:
                if mode.type == 'ARRAY':
                    is_array = True

            #legacy mess
            for x in bpy.context.object.modifiers:
                n += 1
                if x.name == "Array":
                    cArrID = n
                    oo = bpy.context.object.modifiers[
                        "Array"].constant_offset_displace

                    ixx = 0
                    if oo[1] > 0 or oo[1] < 0: ixx = 1
                    if oo[2] > 0 or oo[2] < 0: ixx = 2
                    self.nd = ixx
                    if self.nd == 0:
                        self.start = oo[0]
                    elif self.nd == 1:
                        self.start = oo[1]
                    elif self.nd == 2:
                        self.start = oo[2]

            if is_array == False:
                bpy.context.object.modifiers.new("Array", "ARRAY")
                bpy.context.object.modifiers[
                    "Array"].use_relative_offset = False
                bpy.context.object.modifiers[
                    "Array"].use_constant_offset = True

            self.first_valuex = -1 * bpy.context.object.modifiers[
                "Array"].constant_offset_displace[0]
            self.first_valuey = -1 * bpy.context.object.modifiers[
                "Array"].constant_offset_displace[1]
            self.first_valuez = -1 * bpy.context.object.modifiers[
                "Array"].constant_offset_displace[2]

            self.click_pos = [event.mouse_region_x, event.mouse_region_y]
            self.mouse_pos = event.mouse_x
            self.first_mouse_x = event.mouse_x
            self.first_mouse_y = event.mouse_x
            self.first_mouse_z = event.mouse_x

            self.exists = False

            # detect serialized state. restore original
            if bpy.data.objects[context.object.name].get('arrAxis') != None:
                self.exists = True

                s360 = None
                for m in context.object.modifiers:
                    if m.type == 'SIMPLE_DEFORM':
                        s360 = m
                        break

                if s360:
                    self.bend360 = True
                    self.bend360_mod = s360
                    self.bend360_mod.angle = 6.28319
                    self.bend360_mod.deform_method = 'BEND'

                self.dir = bpy.data.objects[context.object.name].get('arrAxis')
                br = bpy.data.objects[context.object.name].get('arrBaseRot')
                self.start_rot = Quaternion((br[0], br[1], br[2], br[3]))
                A = Matrix.Identity(4)
                self.start_mat[0] = bpy.data.objects[context.object.name].get(
                    'a0')
                self.start_mat[1] = bpy.data.objects[context.object.name].get(
                    'a1')
                self.start_mat[2] = bpy.data.objects[context.object.name].get(
                    'a2')
                self.start_mat[3] = bpy.data.objects[context.object.name].get(
                    'a3')
                A.translation = self.start_mat.translation
                self.start_mat = A
                bm = bmesh.new()
                bm.from_mesh(self.mesh_bu.copy())

                rot = (self.Q[self.dir]).to_matrix()

                bmesh.ops.rotate(bm,
                                 cent=bpy.context.object.location,
                                 matrix=rot,
                                 verts=bm.verts,
                                 space=self.start_mat)  #,

                bm.to_mesh(self.mesh_bu)
                self.mesh_bu.update()

            ############

            args = (self, context)

            self.id = int(cArrID)

            self._handle = bpy.types.SpaceView3D.draw_handler_add(
                gui_update, args, 'WINDOW', 'POST_PIXEL')

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "No active object, could not finish")
            return {'CANCELLED'}
예제 #15
0
def drawBrick(cm, cm_id, bricksDict, key, loc, i, dimensions, zStep, brickSize,
              brickType, split, customData, brickScale, bricksCreated,
              allMeshes, logo, logo_details, mats, brick_mats, internalMat,
              brickHeight, logoResolution, logoDecimate, loopCut, buildIsDirty,
              materialType, materialName, randomMatSeed, studDetail,
              exposedUndersideDetail, hiddenUndersideDetail, randomRot,
              randomLoc, logoType, logoScale, logoInset, circleVerts, randS1,
              randS2, randS3):
    brickD = bricksDict[key]
    # check exposure of current [merged] brick
    if brickD["top_exposed"] is None or brickD[
            "bot_exposed"] is None or buildIsDirty:
        topExposed, botExposed = setAllBrickExposures(bricksDict, zStep, key)
    else:
        topExposed, botExposed = isBrickExposed(bricksDict, zStep, key)

    # get brick material
    mat = getMaterial(cm,
                      bricksDict,
                      key,
                      brickSize,
                      zStep,
                      materialType,
                      materialName,
                      randomMatSeed,
                      brick_mats=brick_mats,
                      seedInc=i)

    # set up arguments for brick mesh
    useStud = (topExposed and studDetail != "NONE") or studDetail == "ALL"
    logoToUse = logo if useStud else None
    undersideDetail = exposedUndersideDetail if botExposed else hiddenUndersideDetail

    ### CREATE BRICK ###

    # add brick with new mesh data at original location
    if brickD["type"].startswith("CUSTOM"):
        m = customData[int(brickD["type"][-1]) - 1]
    else:
        # get brick mesh
        m = getBrickData(brickD, randS3, dimensions, brickSize, brickType,
                         brickHeight, logoResolution, logoDecimate,
                         circleVerts, loopCut, undersideDetail, logoToUse,
                         logoType, logo_details, logoScale, logoInset, useStud)
    # apply random rotation to edit mesh according to parameters
    randomRotMatrix = getRandomRotMatrix(randomRot, randS2,
                                         brickSize) if randomRot > 0 else None
    # get brick location
    locOffset = getRandomLoc(
        randomLoc, randS2, dimensions["width"],
        dimensions["height"]) if randomLoc > 0 else Vector((0, 0, 0))
    brickLoc = getBrickCenter(bricksDict, key, loc, zStep) + locOffset

    if split:
        brick = bpy.data.objects.get(brickD["name"])
        if brick:
            # NOTE: last brick mesh is left in memory (faster)
            # set brick.data to new mesh (resets materials)
            brick.data = m
            # add/remove edge split modifier if necessary
            eMod = brick.modifiers.get('Edge Split')
            if not eMod and useEdgeSplitMod(cm, brickD):
                addEdgeSplitMod(brick)
            elif eMod and not useEdgeSplitMod(cm, brickD):
                brick.modifiers.remove(eMod)
        else:
            # create new object with mesh data
            brick = bpy.data.objects.new(brickD["name"], m)
            brick.cmlist_id = cm_id
            # add edge split modifier
            if useEdgeSplitMod(cm, brickD):
                addEdgeSplitMod(brick)
        # rotate brick by random rotation
        if randomRotMatrix is not None:
            brick.matrix_world = Matrix.Identity(4) * randomRotMatrix
        # set brick location
        brick.location = brickLoc
        # set brick material
        if len(m.materials) > 0 or len(brick.material_slots) > 0:
            m.materials.clear()
        if mat is not None or internalMat is not None:
            m.materials.append(mat or internalMat)
            brick.material_slots[0].link = 'OBJECT'
            brick.material_slots[0].material = mat or internalMat
        # append to bricksCreated
        bricksCreated.append(brick)
    else:
        # apply rotation matrices to edit mesh
        if randomRotMatrix is not None:
            m.transform(randomRotMatrix)
        # transform brick mesh to coordinate on matrix
        m.transform(Matrix.Translation(brickLoc))

        # keep track of mats already use
        if mat in mats:
            matIdx = mats.index(mat)
        elif mat is not None:
            mats.append(mat)
            matIdx = len(mats) - 1

        # set material for mesh
        if len(m.materials) > 0:
            m.materials.clear()
        if mat is not None:
            m.materials.append(mat)
            brickD["mat_name"] = mat.name
            for p in m.polygons:
                p.material_index = matIdx

        # append mesh to allMeshes bmesh object
        allMeshes.from_mesh(m)

        # reset transformations for reference mesh
        m.transform(Matrix.Translation(-brickLoc))
        if randomRotMatrix is not None:
            randomRotMatrix.invert()
            m.transform(randomRotMatrix)

    return bricksDict
예제 #16
0
def import_tabula4(tblzip, jsonmodel, animations_only, scene):
    with ExitStack() as stack:
        bm = bmesh.new()
        stack.callback(bm.free)

        model_name = jsonmodel['modelName']
        author = jsonmodel['authorName']

        mesh = bpy.data.meshes.new(model_name)
        mesh.mcprops.artist = author
        uvmap = mesh.uv_textures.new('UVMap')
        bm.from_mesh(mesh)
        uvloop = bm.loops.layers.uv[uvmap.name]

        identifier_to_cube = set()

        tex_width = jsonmodel['textureWidth']
        tex_height = jsonmodel['textureHeight']
        texture_matrix = Matrix.Identity(3)
        texture_matrix[0][0] = 1 / tex_width
        texture_matrix[1][1] = -1 / tex_height
        texture_matrix[1][2] = 1
        print(texture_matrix)

        texture_name = 'texture.png'
        try:
            tblzip.extract(texture_name, path=bpy.app.tempdir)
            texture_file = os.path.join(bpy.app.tempdir, texture_name)
        except KeyError:
            Reporter.error("Missing texture file", texname=texture_file)
        else:
            image = bpy.data.images.load(texture_file)
            image.pack()
            image.use_alpha = True
            os.remove(texture_file)

        def Position(vec):
            s = Matrix.Identity(4)
            s.row[0][3], s.row[1][3], s.row[2][3] = vec
            return s

        def Scale(vec):
            s = Matrix.Identity(4)
            s.row[0][0], s.row[1][1], s.row[2][2] = vec
            return s

        def Rotation(rot):
            return Euler(rot, 'XYZ').to_matrix().to_4x4()

        def emit_cube(cube, local_to_global):
            offset = Position(cube['offset'])  # Offset
            dim_x, dim_y, dim_z = cube['dimensions']
            dimensions = Scale((dim_x, dim_y, dim_z))
            matrix = local_to_global * offset * dimensions
            tx_transform = Matrix.Identity(3)
            tx_transform.col[2] =\
                cube['txOffset'][0], cube['txOffset'][1], 1
            tx_transform = texture_matrix * tx_transform
            print(tx_transform)

            v0 = bm.verts.new((matrix * Vector((0, 0, 0, 1)))[0:3])
            v1 = bm.verts.new((matrix * Vector((0, 0, 1, 1)))[0:3])
            v2 = bm.verts.new((matrix * Vector((0, 1, 0, 1)))[0:3])
            v3 = bm.verts.new((matrix * Vector((0, 1, 1, 1)))[0:3])
            v4 = bm.verts.new((matrix * Vector((1, 0, 0, 1)))[0:3])
            v5 = bm.verts.new((matrix * Vector((1, 0, 1, 1)))[0:3])
            v6 = bm.verts.new((matrix * Vector((1, 1, 0, 1)))[0:3])
            v7 = bm.verts.new((matrix * Vector((1, 1, 1, 1)))[0:3])
            bm.edges.new((v0, v1))
            bm.edges.new((v0, v2))
            bm.edges.new((v0, v4))
            bm.edges.new((v1, v3))
            bm.edges.new((v1, v5))
            bm.edges.new((v2, v3))
            bm.edges.new((v2, v6))
            bm.edges.new((v3, v7))
            bm.edges.new((v4, v5))
            bm.edges.new((v4, v6))
            bm.edges.new((v5, v7))
            bm.edges.new((v6, v7))
            f0 = bm.faces.new((v0, v1, v3, v2))
            f1 = bm.faces.new((v0, v4, v5, v1))
            f2 = bm.faces.new((v0, v2, v6, v4))
            f3 = bm.faces.new((v4, v6, v7, v5))
            f4 = bm.faces.new((v2, v3, v7, v6))
            f5 = bm.faces.new((v1, v5, v7, v3))
            f0.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f0.loops[1][uvloop].uv = (tx_transform * Vector(
                (0, dim_z, 1)))[0:2]
            f0.loops[2][uvloop].uv = (tx_transform * Vector(
                (0, dim_z + dim_y, 1)))[0:2]
            f0.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z + dim_y, 1)))[0:2]
            f1.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f1.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f1.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, 0, 1)))[0:2]
            f1.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z, 0, 1)))[0:2]
            f2.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f2.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z + dim_y, 1)))[0:2]
            f2.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z + dim_y, 1)))[0:2]
            f2.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f3.loops[0][uvloop].uv = (tx_transform * Vector(
                (2 * dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f3.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f3.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f3.loops[3][uvloop].uv = (tx_transform * Vector(
                (2 * dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f4.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f4.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, 0, 1)))[0:2]
            f4.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, 0, 1)))[0:2]
            f4.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f5.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f5.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z + dim_y, 1)))[0:2]
            f5.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f5.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            bm.verts.index_update()
            bm.edges.index_update()
            bm.faces.index_update()

            bm.normal_update()
            return

        def make_cube(cube, to_global):
            identifier = cube['identifier']
            name = cube['name']

            position = Position(cube['position'])  # Rotation point
            scale = Scale(cube['scale'])
            rotation = Rotation(cube['rotation'])

            local_to_global = to_global * position * rotation * scale

            if identifier in identifier_to_cube:
                Reporter.warning("Identifier reused in the model: {id}",
                                 id=identifier)
            identifier_to_cube.add(identifier)

            emit_cube(cube, local_to_global)

            for child in cube['children']:
                make_cube(child, local_to_global)

        def make_group(group, to_global):
            for cube in group['cubes']:
                make_cube(cube, to_global)
            for child in group['cubeGroups']:
                make_cube(child, to_global)

        model_transform = Matrix.Scale(1 / 16, 4)
        model_transform[1][2] = model_transform[2][2]
        model_transform[2][1] = -model_transform[1][1]
        model_transform[1][1] = model_transform[2][2] = 0
        model_transform[2][3] = 51 / 32
        model_transform *= Scale(jsonmodel['scale'])

        for group in jsonmodel['cubeGroups']:
            make_group(group, model_transform)
        for cube in jsonmodel['cubes']:
            make_cube(cube, model_transform)

        bm.to_mesh(mesh)
        object = bpy.data.objects.new(model_name, mesh)
        scene.objects.link(object)
        scene.update()

    def make_animation(*args):
        pass  # TODO: import animations aswell?

    for animation in jsonmodel['anims']:
        make_animation(animation, model_transform)
예제 #17
0
    def click_add_point(self,context,x,y, label = None):
        '''
        x,y = event.mouse_region_x, event.mouse_region_y
        
        this will add a point into the bezier curve or
        close the curve into a cyclic curve
        '''
        region = context.region
        rv3d = context.region_data
        coord = x, y
        view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
        ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
        ray_target = ray_origin + (view_vector * 1000)

        hit = False
        if self.snap_type == 'SCENE':
            mx = Matrix.Identity(4)  #loc is given in world loc...no need to multiply by obj matrix
            imx = Matrix.Identity(4)
            no_mx = Matrix.Identity(3)
            if bversion() < '002.077.000':
                res, obj, omx, loc, no = context.scene.ray_cast(ray_origin, ray_target)  #changed in 2.77
            else:
                res, loc, no, ind, obj, omx = context.scene.ray_cast(ray_origin, view_vector)
                iomx = omx.inverted()
                no_mx = iomx.to_3x3().transposed()
            hit = res
            if not hit:
                #cast the ray into a plane a
                #perpendicular to the view dir, at the last bez point of the curve
            
                view_direction = rv3d.view_rotation * Vector((0,0,-1))
            
                if len(self.b_pts):
                    plane_pt = self.b_pts[-1]
                else:
                    plane_pt = context.scene.cursor_location
                loc = intersect_line_plane(ray_origin, ray_target,plane_pt, view_direction)
                hit = True
        
        elif self.snap_type == 'OBJECT':
            mx = self.snap_ob.matrix_world
            imx = mx.inverted()
            no_mx = imx.to_3x3().transposed()
            
            if bversion() < '002.077.000':
                loc, no, face_ind = self.snap_ob.ray_cast(imx * ray_origin, imx * ray_target)
                if face_ind != -1:
                    hit = True
            else:
                ok, loc, no, face_ind = self.snap_ob.ray_cast(imx * ray_origin, imx * ray_target - imx*ray_origin)
                if ok:
                    hit = True
            
            if face_ind != -1:
                hit = True
        
        if not hit: 
            self.selected = -1
            return
        
        if self.hovered[0] == None:  #adding in a new point
            self.b_pts.append(mx * loc)
            self.normals.append(no_mx * no)
            self.labels.append(label)
            return True    
        if self.hovered[0] == 'POINT':
            self.selected = self.hovered[1]
            return
예제 #18
0
 def Position(vec):
     s = Matrix.Identity(4)
     s.row[0][3], s.row[1][3], s.row[2][3] = vec
     return s
예제 #19
0
    def load(self, context, **options):
        """load a sketchup file"""
        self.context = context
        self.reuse_material = options['reuse_material']
        self.reuse_group = options['reuse_existing_groups']
        self.max_instance = options['max_instance']
        self.component_stats = defaultdict(list)
        self.component_skip = proxy_dict()
        self.component_depth = proxy_dict()
        self.group_written = {}
        self.aspect_ratio = context.scene.render.resolution_x / context.scene.render.resolution_y

        sketchupLog('importing skp %r' % self.filepath)

        addon_name = __name__.split('.')[0]
        self.prefs = context.user_preferences.addons[addon_name].preferences

        time_main = time.time()

        try:
            self.skp_model = sketchup.Model.from_file(self.filepath)
        except Exception as e:
            sketchupLog('Error reading input file: %s' % self.filepath)
            sketchupLog(e)
            return {'FINISHED'}

        if options['import_scene']:
            for s in self.skp_model.scenes:
                if s.name == options['import_scene']:
                    sketchupLog("Importing Scene \"{}\" ".format(s.name))
                    self.scene = s
                    self.layers_skip = [l for l in s.layers]
                    for l in s.layers:
                        sketchupLog("SKIP: {}".format(l.name))
            if not self.layers_skip:
                sketchupLog('Could not find scene {} importing default'.format(
                    options['import_scene']))

        if not self.layers_skip:
            self.layers_skip = [
                l for l in self.skp_model.layers if not l.visible
            ]

        sketchupLog('Skipping layers: ')
        for l in sorted([l.name for l in self.layers_skip]):
            sketchupLog(l)

        self.skp_components = proxy_dict(
            self.skp_model.component_definition_as_dict)

        sketchupLog('parsed skp %r in %.4f sec.' % (self.filepath,
                                                    (time.time() - time_main)))

        if options['scenes_as_camera']:
            for s in self.skp_model.scenes:
                self.write_camera(s.camera, s.name)

        if options['import_camera']:
            if self.scene:
                active_cam = self.write_camera(self.scene.camera,
                                               name=self.scene.name)
                context.scene.camera = active_cam
            else:
                active_cam = self.write_camera(self.skp_model.camera)
                context.scene.camera = active_cam

        t1 = time.time()
        self.write_materials(self.skp_model.materials)
        sketchupLog('imported materials in %.4f sec' % (time.time() - t1))

        t1 = time.time()
        D = SKP_util()
        SKP_util.layers_skip = self.layers_skip

        for c in self.skp_model.component_definitions:
            self.component_depth[c.name] = D.component_deps(c.entities)
        sketchupLog('analyzed component depths in %.4f sec' %
                    (time.time() - t1))

        self.write_duplicateable_groups()

        if options["dedub_only"]:
            return {'FINISHED'}

        self.component_stats = defaultdict(list)
        self.write_entities(self.skp_model.entities, "Sketchup",
                            Matrix.Identity(4))

        for k, v in self.component_stats.items():
            name, mat = k
            if options['dedub_type'] == "VERTEX":
                self.instance_group_dupli_vert(name, mat, self.component_stats)
            else:
                self.instance_group_dupli_face(name, mat, self.component_stats)

        sketchupLog('imported entities in %.4f sec' % (time.time() - t1))

        sketchupLog('finished importing %s in %.4f sec ' %
                    (self.filepath, time.time() - time_main))
        return {'FINISHED'}
예제 #20
0
 def Scale(vec):
     s = Matrix.Identity(4)
     s.row[0][0], s.row[1][1], s.row[2][2] = vec
     return s
예제 #21
0
 def push_custom_matrix_if_present(self, sv_object, matrix):
     if matrix:
         # matrix = matrix_sanitizer(matrix)
         sv_object.matrix_local = matrix
     else:
         sv_object.matrix_local = Matrix.Identity(4)
예제 #22
0
        def emit_cube(cube, local_to_global):
            offset = Position(cube['offset'])  # Offset
            dim_x, dim_y, dim_z = cube['dimensions']
            dimensions = Scale((dim_x, dim_y, dim_z))
            matrix = local_to_global * offset * dimensions
            tx_transform = Matrix.Identity(3)
            tx_transform.col[2] =\
                cube['txOffset'][0], cube['txOffset'][1], 1
            tx_transform = texture_matrix * tx_transform
            print(tx_transform)

            v0 = bm.verts.new((matrix * Vector((0, 0, 0, 1)))[0:3])
            v1 = bm.verts.new((matrix * Vector((0, 0, 1, 1)))[0:3])
            v2 = bm.verts.new((matrix * Vector((0, 1, 0, 1)))[0:3])
            v3 = bm.verts.new((matrix * Vector((0, 1, 1, 1)))[0:3])
            v4 = bm.verts.new((matrix * Vector((1, 0, 0, 1)))[0:3])
            v5 = bm.verts.new((matrix * Vector((1, 0, 1, 1)))[0:3])
            v6 = bm.verts.new((matrix * Vector((1, 1, 0, 1)))[0:3])
            v7 = bm.verts.new((matrix * Vector((1, 1, 1, 1)))[0:3])
            bm.edges.new((v0, v1))
            bm.edges.new((v0, v2))
            bm.edges.new((v0, v4))
            bm.edges.new((v1, v3))
            bm.edges.new((v1, v5))
            bm.edges.new((v2, v3))
            bm.edges.new((v2, v6))
            bm.edges.new((v3, v7))
            bm.edges.new((v4, v5))
            bm.edges.new((v4, v6))
            bm.edges.new((v5, v7))
            bm.edges.new((v6, v7))
            f0 = bm.faces.new((v0, v1, v3, v2))
            f1 = bm.faces.new((v0, v4, v5, v1))
            f2 = bm.faces.new((v0, v2, v6, v4))
            f3 = bm.faces.new((v4, v6, v7, v5))
            f4 = bm.faces.new((v2, v3, v7, v6))
            f5 = bm.faces.new((v1, v5, v7, v3))
            f0.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f0.loops[1][uvloop].uv = (tx_transform * Vector(
                (0, dim_z, 1)))[0:2]
            f0.loops[2][uvloop].uv = (tx_transform * Vector(
                (0, dim_z + dim_y, 1)))[0:2]
            f0.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z + dim_y, 1)))[0:2]
            f1.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f1.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f1.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, 0, 1)))[0:2]
            f1.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z, 0, 1)))[0:2]
            f2.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z, 1)))[0:2]
            f2.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z, dim_z + dim_y, 1)))[0:2]
            f2.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z + dim_y, 1)))[0:2]
            f2.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f3.loops[0][uvloop].uv = (tx_transform * Vector(
                (2 * dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f3.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f3.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f3.loops[3][uvloop].uv = (tx_transform * Vector(
                (2 * dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f4.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            f4.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, 0, 1)))[0:2]
            f4.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, 0, 1)))[0:2]
            f4.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f5.loops[0][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z, 1)))[0:2]
            f5.loops[1][uvloop].uv = (tx_transform * Vector(
                (dim_z + dim_x, dim_z + dim_y, 1)))[0:2]
            f5.loops[2][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z + dim_y, 1)))[0:2]
            f5.loops[3][uvloop].uv = (tx_transform * Vector(
                (dim_z + 2 * dim_x, dim_z, 1)))[0:2]
            bm.verts.index_update()
            bm.edges.index_update()
            bm.faces.index_update()

            bm.normal_update()
            return
    def finish(self, context):
        #ray cast the entire grid into
        
        if 'Posterior Plane' in bpy.data.objects:
            Plane = bpy.data.objects['Posterior Plane']
            Plane.hide = False
                
        else:
            me = bpy.data.meshes.new('Posterior Plane')
            Plane = bpy.data.objects.new('Posterior Plane', me)
            context.scene.objects.link(Plane)
        
        
        pbme = bmesh.new()
        pbme.verts.ensure_lookup_table()
        pbme.edges.ensure_lookup_table()
        pbme.faces.ensure_lookup_table()
        bmesh.ops.create_grid(pbme, x_segments = 200, y_segments = 200, size = 39.9)
        pbme.to_mesh(Plane.data)
        
        pt, pno = calculate_plane(self.crv.b_pts)
        
        if self.splint.jaw_type == 'MANDIBLE':
            Zw = Vector((0,0,-1))
            Xw = Vector((1,0,0))
            Yw = Vector((0,-1,1))
            
        else:
            Zw = Vector((0,0,1))
            Xw = Vector((1,0,0))
            Yw = Vector((0,1,0))
            
        Z = pno
        Z.normalize()
        
        if Zw.dot(Z) < 0:
            Z *= -1
            
        Y = Z.cross(Xw)
        X = Y.cross(Z)
            
        
        R = Matrix.Identity(3)  #make the columns of matrix U, V, W
        R[0][0], R[0][1], R[0][2]  = X[0] ,Y[0],  Z[0]
        R[1][0], R[1][1], R[1][2]  = X[1], Y[1],  Z[1]
        R[2][0] ,R[2][1], R[2][2]  = X[2], Y[2],  Z[2]
        
        R = R.to_4x4()
        T = Matrix.Translation(pt - 5 * Z)
        
        Plane.matrix_world = T * R
    
        pmx = Plane.matrix_world
        ipmx = pmx.inverted()
        
        bme_pln = bmesh.new()
        bme_pln.from_mesh(Plane.data)
        bme_pln.verts.ensure_lookup_table()
        bme_pln.edges.ensure_lookup_table()
        bme_pln.faces.ensure_lookup_table()
        bvh = BVHTree.FromBMesh(bme_pln)
        
        
        #we are going to raycast the user world coordinate points
        #into a grid, and identify all points in the grid from the local Z direction
        #Then we will store the local location of the user picked coordinate in a dictionary
        key_verts = {}
        
        for loc in self.crv.b_pts:

            res = bvh.ray_cast(ipmx * loc, -Z, 30)
            if res[0] != None:
                
                f = bme_pln.faces[res[2]]
                for v in f.verts:
                    key_verts[v] = ipmx * loc
                    v.select_set(True)
                
                continue
            
            res = bvh.ray_cast(ipmx * loc, Z, 30)
            if res[0] != None:
                
                f = bme_pln.faces[res[2]]
                for v in f.verts:
                    key_verts[v] = ipmx * loc
                    v.select_set(True)
                
                continue
        
        #bme_pln.to_mesh(Plane.data)
        #bme_pln.free()
        #return
        kdtree = KDTree(len(key_verts))
        for v in key_verts.keys():
            kdtree.insert(v.co, v.index)
        
        kdtree.balance()
        
        #raycast  the shell if we can
        raycast_shell = False
        if 'Splint Shell' in bpy.data.objects:
            shell = bpy.data.objects.get('Splint Shell')
            bvh_shell = BVHTree.FromObject(shell, context.scene)
            mx_shell = shell.matrix_world
            imx_shell = mx_shell.inverted()
            Z_shell = imx_shell.to_3x3()*Z
            raycast_shell = True
            
        
        right_side = set()
        left_side = set()
        ray_casted = set()
        
        to_delete = set()
        
        for v in bme_pln.verts:
            if v in key_verts:
                v.co[2] = key_verts[v][2]
               
                if v.co[1] > 0:
                    left_side.add(v)
                else:
                    right_side.add(v)
                continue
                
            results = kdtree.find_range(v.co, .5)
            if len(results):
                N = len(results)
                r_total = 0
                v_new = Vector((0,0,0))
                for res in results:
                    r_total += 1/res[2]
                    v_new += (1/res[2]) * key_verts[bme_pln.verts[res[1]]]
                        
                v_new *= 1/r_total
                v.co[2] = v_new[2]
                if v.co[1] > 0:
                    left_side.add(v)
                else:
                    right_side.add(v)
                continue
                        
            results = kdtree.find_range(v.co, 6)
            if len(results):
                N = len(results)
                r_total = 0
                v_new = Vector((0,0,0))
                for res in results:
                    r_total += (1/res[2])**2
                    v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]]
                        
                v_new *= 1/r_total
                v.co[2] = v_new[2]
                if v.co[1] > 0:
                    left_side.add(v)
                else:
                    right_side.add(v)
                continue
            
            loc, no, index, d = bvh_shell.ray_cast(imx_shell * pmx * v.co, Z_shell)
            if loc:
                
                ray_casted.add(v)
                results = kdtree.find_n(v.co, 4)
                N = len(results)
                r_total = 0
                v_new = Vector((0,0,0))
                for res in results:
                    r_total += (1/res[2])**2
                    v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]]
                        
                v_new *= 1/r_total
                v.co[2] = v_new[2]
                continue

        total_verts = ray_casted | left_side | right_side
        
        ant_left = max(left_side, key = lambda x: x.co[0])
        ant_right = max(right_side, key = lambda x: x.co[0])
        
        new_verts = set()
        dilation_verts = set()  
        for v in total_verts:
            for ed in v.link_edges:
                v_new = ed.other_vert(v)
                if v_new in total_verts or v_new in new_verts: 
                    continue
                else:
                    new_verts.add(v_new)
                    
        print('adding %i new verts' % len(new_verts))
        
        
        total_verts.update(new_verts)
        dilation_verts.update(new_verts)
        
        #for v in ray_casted:
        #    if v.co[1] > 0:
        #        if v.co[0] > ant_left.co[0]:
        #            to_delete.add(v)
        #    else:
        #        if v.co[0] > ant_right.co[0]:
        #            to_delete.add(v)
        
        #print('added %i ray_casted' % len(ray_casted))
        #total_verts = ray_casted | left_side | right_side
        #total_verts.difference_update(to_delete)       
        
        #new_verts = set()   
        #for v in total_verts:
        #    for ed in v.link_edges:
        #        v_new = ed.other_vert(v)
        #        if v_new in total_verts: continue
                
        #        if v_new.co[1] > 0 and v_new.co[0] < ant_left.co[0]:
        #            if v in to_delete:
        #                new_verts.add(v)
        #        if v_new.co[1] <= 0 and v_new.co[0] < ant_right.co[0]:
        #            if v in to_delete:
        #                new_verts.add(v)   
        
        #to_delete.difference_update(new_verts)
        
        #print('adding %i new verts' % len(new_verts))   
        for j in range(0,3):
            newer_verts = set()  
            for v in new_verts:
                for ed in v.link_edges:
                    v_new = ed.other_vert(v)
                    if v_new in total_verts or v_new in newer_verts:
                        continue
                     
                    newer_verts.add(v_new)
                    
            
                       
            total_verts.update(newer_verts)
            dilation_verts.update(newer_verts)
            new_verts = newer_verts
        
        to_delete = set(bme_pln.verts[:]) - total_verts
        
        #filter out anteior dilation
        for v in dilation_verts:
            
            if v.co[1] > 0 and v.co[0] > ant_left.co[0]:
                to_delete.add(v)
                continue
            if v.co[1] <= 0 and v.co[0] > ant_right.co[0]:
                to_delete.add(v)
                continue
                
             
            results = kdtree.find_n(v.co, 4)
            N = len(results)
            r_total = 0
            v_new = Vector((0,0,0))
            for res in results:
                r_total += (1/res[2])**2
                v_new += ((1/res[2])**2) * key_verts[bme_pln.verts[res[1]]]
                        
            v_new *= 1/r_total
            v.co[2] = v_new[2]
            
        #filter out anteior dilation
        for v in ray_casted:
            if v.co[1] > 0 and v.co[0] > ant_left.co[0]:
                to_delete.add(v)
                continue
            if v.co[1] <= 0 and v.co[0] > ant_right.co[0]:
                to_delete.add(v)
                continue
                            
        bmesh.ops.delete(bme_pln, geom = list(to_delete), context = 1)
        bme_pln.to_mesh(Plane.data)
        Plane.data.update()
        
        smod = Plane.modifiers.new('Smooth', type = 'SMOOTH')
        smod.iterations = 5
        smod.factor = 1
        
        self.splint.ops_string += 'Mark Posterior Cusps:'
예제 #24
0
def scale_matrix(factor):
    m = Matrix.Identity(4)
    m[0][0] = factor
    m[1][1] = factor
    m[2][2] = factor
    return m
예제 #25
0
 def getDefaultValue(cls):
     return Matrix.Identity(4)
예제 #26
0
def ImportMD3(model_name, zoffset, import_tags):
    
    mesh = None
    skip = False
    try:
        file = open(model_name, "rb")
    except:
        return mesh

    if (not skip):
        magic_nr = file.read(4)
        version_nr = struct.unpack("<i", file.read(4))[0]
                    
        md3 = MD3(file, magic_nr, version_nr)
        if (not md3.valid):
            print("this md3 version is not supported\n")
            skip = True
        
    if (not skip):
        name        = file.read(64).decode("utf-8", errors="ignore").strip("\0")
        print("Import MD3: " + name)
        flags       = struct.unpack("<i", file.read(4))[0]
        numFrames   = struct.unpack("<i", file.read(4))[0]
        numTags     = struct.unpack("<i", file.read(4))[0]
        numSurfaces = struct.unpack("<i", file.read(4))[0]
        numSkins    = struct.unpack("<i", file.read(4))[0]
        ofsFrames   = struct.unpack("<i", file.read(4))[0]
        ofsTags     = struct.unpack("<i", file.read(4))[0]
        ofsSurfaces = struct.unpack("<i", file.read(4))[0]
        ofsEnd      = struct.unpack("<i", file.read(4))[0]
        
        print("flags: " + str(flags))
        print("numFrames: " + str(numFrames))
        print("numTags: " + str(numTags))
        print("numSurfaces: " + str(numSurfaces))
        print("numSkins: " + str(numSkins))
        
        print("ofsFrames: " + str(ofsFrames))
        print("ofsTags: " + str(ofsTags))
        print("ofsSurfaces: " + str(ofsSurfaces))
        print("ofsEnd: " + str(ofsEnd))
        
        surface_lumps = []
        for surface_lump in range(numSurfaces):
            surface = lump(md3.surface)
            surface.set_offset_count([ofsSurfaces,1])
            surface.readFrom(file)
            surface.data[0].vertices.readFrom(file,ofsSurfaces)
            surface.data[0].tcs.readFrom(file,ofsSurfaces)
            surface.data[0].shaders.readFrom(file,ofsSurfaces)
            surface.data[0].triangles.readFrom(file,ofsSurfaces)
            
            surface_lumps.append(surface)
            ofsSurfaces += surface.data[0].off_end
            
        frames = lump(md3.frame)
        frames.set_offset_count([ofsFrames, numFrames])
        frames.readFrom(file)
        for frame_id, frame in enumerate(frames.data):
            print("\tFrame Nr " + str(frame_id))
            print("\t\tName: " + str(frame.name))
            print("\t\tLocal Origin: " + str(frame.local_origin))
            print("\t\tRadius: " + str(frame.radius))
            
        
        if import_tags:
            tag_lump = lump(md3.tag)
            tag_lump.set_offset_count([ofsTags, numTags])
            tag_lump.readFrom(file)
            
            for tag in range(numTags):
                bpy.ops.object.empty_add(type="ARROWS")
                tag_obj = bpy.context.object
                tag_obj.name = tag_lump.data[tag].name
                matrix = Matrix.Identity(4)
                matrix[0] = [*tag_lump.data[tag].axis_1, 0.0]
                matrix[1] = [*tag_lump.data[tag].axis_2, 0.0]
                matrix[2] = [*tag_lump.data[tag].axis_3, 0.0]
                matrix.transpose()
                matrix.translation = tag_lump.data[tag].origin
                tag_obj.matrix_world = matrix
            
        vertex_pos = []
        vertex_nor = []
        vertex_tc = []
        face_indices = []
        face_tcs = []
        face_shaders = []
        shaderindex = 0
        face_index_offset = 0
        face_material_index = []
        
        #vertex groups
        surfaces = {}
        for surface_id, surface in enumerate(surface_lumps):
            print("\tSurface Nr " + str(surface_id))
            n_indices = 0
            surface_indices = []
            for vertex, tc in zip(surface.data[0].vertices.data, surface.data[0].tcs.data):
                vertex_pos.append(vertex.position)
                vertex_nor.append(vertex.normal)
                vertex_tc.append(tc.tc)
                n_indices += 1
                
            for triangle in surface.data[0].triangles.data:
                triangle_indices = [ triangle.indices[0] + face_index_offset,
                                     triangle.indices[1] + face_index_offset,
                                     triangle.indices[2] + face_index_offset]
                surface_indices.append(triangle_indices)
                face_indices.append(triangle_indices)
                    
                face_tcs.append(vertex_tc[triangle_indices[0]])
                face_tcs.append(vertex_tc[triangle_indices[1]])
                face_tcs.append(vertex_tc[triangle_indices[2]])
                face_material_index.append(shaderindex)
            
            print("\t\tnumTriangles: " + str(len(surface.data[0].triangles.data)))
            print("\t\tnumShaders: " + str(len(surface.data[0].shaders.data)))
            for shader_id, shader in enumerate(surface.data[0].shaders.data):
                print("\t\t\t" + str(shader_id) + ": " + str(shader.name))
            
            surfaces[surface.data[0].name] = unpack_list(surface_indices)
            face_shaders.append(surface.data[0].shaders.data[0])
            shaderindex += 1
            face_index_offset += n_indices
        
        guessed_name = guess_model_name( model_name.lower() ).lower()
        if guessed_name.endswith(".md3"):
            guessed_name = guessed_name[:-len(".md3")]
        
        mesh = bpy.data.meshes.new( guessed_name )
        mesh.from_pydata(vertex_pos, [], face_indices)
            
        #oh man...
        if zoffset == 0:
            material_suffix = ".grid"
        else:
            material_suffix = "." + str(zoffset) + "grid"
            
        for texture_instance in face_shaders:
            mat = bpy.data.materials.get(texture_instance.name + material_suffix)
            if (mat == None):
                mat = bpy.data.materials.new(name=texture_instance.name + material_suffix)
            mesh.materials.append(mat)
                        
        mesh.polygons.foreach_set("material_index", face_material_index)
            
        for poly in mesh.polygons:
            poly.use_smooth = True
                        
        mesh.vertices.foreach_set("normal", unpack_list(vertex_nor))
        mesh.normals_split_custom_set_from_vertices(vertex_nor)
        
        mesh.uv_layers.new(do_init=False,name="UVMap")
        mesh.uv_layers["UVMap"].data.foreach_set("uv", unpack_list(face_tcs))
        
        mesh.use_auto_smooth = True
                    
        mesh.update()
            
    file.close
    return mesh
예제 #27
0
def main_SVD(context, down_sample, method, spin_res, make_box):
    start = time.time()

    world_mx = context.object.matrix_world
    scale = world_mx.to_scale()
    trans = world_mx.to_translation()

    tr_mx = Matrix.Identity(4)
    sc_mx = Matrix.Identity(4)

    tr_mx[0][3], tr_mx[1][3], tr_mx[2][3] = trans[0], trans[1], trans[2]
    sc_mx[0][0], sc_mx[1][1], sc_mx[2][2] = scale[0], scale[1], scale[2]
    r_mx = world_mx.to_quaternion().to_matrix().to_4x4()

    me = context.object.data
    bme = bmesh.new()
    bme.from_mesh(me)

    convex_hull = bmesh.ops.convex_hull(bme,
                                        input=bme.verts,
                                        use_existing_faces=True)
    total_hull = convex_hull['geom']

    hull_verts = [item for item in total_hull if hasattr(item, 'co')]
    hull_faces = [item for item in total_hull if hasattr(item, 'no')]
    #hull_bme = bmesh.new()
    #hull_bme.verts = hull_verts
    #hull_bme.faces = hull_faces

    vert_data = [v.co for v in hull_verts]  # ToDo...world coords better?
    v0 = np.array(vert_data, dtype=np.float64, copy=True)
    ndims = v0.shape[0]

    # move data to origin
    t0 = -np.mean(v0, axis=1)
    M0 = np.identity(ndims + 1)
    M0[:ndims, ndims] = t0
    v0 += t0.reshape(ndims, 1)

    U, s, V = np.linalg.svd(v0, full_matrices=True)

    # make a rotation matrix from eigenvectors (easy)
    rmx = Matrix.Identity(4)
    rmx[0][0], rmx[0][1], rmx[0][2] = V[0][0], V[0][1], V[0][2]
    rmx[1][0], rmx[1][1], rmx[1][2] = V[1][0], V[1][1], V[1][2]
    rmx[2][0], rmx[2][1], rmx[2][2] = V[2][0], V[2][1], V[2][2]

    min_box = bbox_orient(vert_data, rmx)
    min_vol = bbox_vol(min_box)
    min_angle = 0
    min_mx = rmx

    # these are our PCA directions
    X = Vector((V[0][0], V[0][1], V[0][2]))
    Y = Vector((V[1][0], V[1][1], V[1][2]))
    Z = Vector((V[2][0], V[2][1], V[2][2]))

    for n in range(0, 2 * spin_res):
        angle = math.pi * n / (2 * spin_res)

        rmx = Matrix.Identity(4)

        if method == 'pca_x':  # keep x axis and rotate around it
            rmx[0][0], rmx[0][1], rmx[0][2] = X[0], X[1], X[2]

            y = math.cos(angle) * Y + math.sin(angle) * Z
            y.normalize()
            rmx[1][0], rmx[1][1], rmx[1][2] = y[0], y[1], y[2]

            z = -math.sin(angle) * Y + math.cos(angle) * Z
            z.normalize()
            rmx[2][0], rmx[2][1], rmx[2][2] = z[0], z[1], z[2]

        elif method == 'pca_y':  # keep y axis and rotate around it
            x = math.cos(angle) * X - math.sin(angle) * Z
            x.normalize()
            rmx[0][0], rmx[0][1], rmx[0][2] = x[0], x[1], x[2]
            # keep y
            rmx[1][0], rmx[1][1], rmx[1][2] = Y[0], Y[1], Y[2]

            z = math.sin(angle) * X + math.cos(angle) * Z
            z.normalize()
            rmx[2][0], rmx[2][1], rmx[2][2] = z[0], z[1], z[2]

        else:
            x = math.cos(angle) * X + math.sin(angle) * Y
            x.normalize()
            rmx[0][0], rmx[0][1], rmx[0][2] = x[0], x[1], x[2]

            y = -math.sin(angle) * X + math.cos(angle) * Y
            y.normalize()
            rmx[1][0], rmx[1][1], rmx[1][2] = y[0], y[1], y[2]

            # Keep Z
            rmx[2][0], rmx[2][1], rmx[2][2] = Z[0], Z[1], Z[2]

        box = bbox_orient(vert_data, rmx)
        test_V = bbox_vol(box)
        if test_V < min_vol:
            min_angle = angle
            min_box = box
            min_mx = rmx
            min_vol = test_V

        if make_box:
            box_verts = box_cords(box)
            bpy.ops.mesh.primitive_cube_add()

            context.object.matrix_world = rmx.transposed().inverted(
            ) * world_mx
            context.object.draw_type = 'BOUNDS'
            for i, v in enumerate(box_verts):
                context.object.data.vertices[i].co = v

    elapsed_time = time.time() - start

    print(
        'found bbox of volume %f in %f seconds with SVD followed by rotating calipers'
        % (min_vol, elapsed_time))

    box_verts = box_cords(min_box)
    bpy.ops.mesh.primitive_cube_add()
    #FinalMatrix = TranslationMatrix * RotationMatrix * ScaleMatrix
    fmx = tr_mx * r_mx * min_mx.inverted() * sc_mx

    context.object.matrix_world = fmx
    context.object.draw_type = 'BOUNDS'
    for i, v in enumerate(box_verts):
        context.object.data.vertices[i].co = v

    bme.free()
예제 #28
0
def join_bmesh(source, target, src_trg_map, src_mx = None, trg_mx = None):
    '''
    
    '''
    L = len(target.verts)
    print('Target has %i verts' % L)
    
    print('Source has %i verts' % len(source.verts))
    l = len(src_trg_map)
    print('is the src_trg_map being sticky...%i' % l)
    if not src_mx:
        src_mx = Matrix.Identity(4)
    
    if not trg_mx:
        trg_mx = Matrix.Identity(4)
        i_trg_mx = Matrix.Identity(4)
    else:
        i_trg_mx = trg_mx.inverted()
        
        

    new_bmverts = []
    
    source.verts.ensure_lookup_table()

    for v in source.verts:
        if v.index not in src_trg_map:
            new_ind = len(target.verts)
            new_bv = target.verts.new(i_trg_mx * src_mx * v.co)
            new_bmverts.append(new_bv)
            #new_bv.index = new_ind
            src_trg_map[v.index] = new_ind
    
    #new_bmverts = [target.verts.new(i_trg_mx * src_mx * v.co) for v in source.verts]# if v.index not in src_trg_map]

    #def src_to_trg_ind(v):
    #    subbed = False
    #    if v.index in src_trg_map:

    #       new_ind = src_trg_map[v.index]
    #        subbed = True
    #    else:
    #        new_ind = v.index + L  #TODO, this takes the actual versts from sources, these verts are in target
            
    #    return new_ind, subbed
    
    #new_bmfaces = [target.faces.new(tuple(new_bmverts[v.index] for v in face.verts)) for face in source.faces]
    target.verts.index_update()
    #target.verts.sort()  #does this still work?
    target.verts.ensure_lookup_table()
    #print('new faces')
    #for f in source.faces:
        #print(tuple(src_to_trg_ind(v) for v in f.verts))
    
    #subbed = set()
    new_bmfaces = []
    for f in source.faces:
        v_inds = []
        for v in f.verts:
            new_ind = src_trg_map[v.index]
            v_inds.append(new_ind)
          
        new_bmfaces += [target.faces.new(tuple(target.verts[i] for i in v_inds))]
    
    #new_bmfaces = [target.faces.new(tuple(target.verts[src_to_trg_ind(v)] for v in face.verts)) for face in source.faces]
    target.faces.ensure_lookup_table()
    target.verts.ensure_lookup_table()
    target.verts.index_update()
    
    #throw away the loose verts...not very elegant with edges and what not
    #n_removed = 0
    #for vert in new_bmverts:
    #    if (vert.index - L) in src_trg_map: #these are verts that are not needed
    #        target.verts.remove(vert)
    #        n_removed += 1
    
    #bmesh.ops.delete(target, geom=del_verts, context=1)
            
    target.verts.index_update()        
    target.verts.ensure_lookup_table()
    target.faces.ensure_lookup_table()
    
    new_L = len(target.verts)
    
    if src_trg_map:
        if new_L != L + len(source.verts) -l:
            print('seems some verts were left in that should not have been')
            
    del src_trg_map
예제 #29
0
def join_bmesh_map(source, target, src_trg_map = None, src_mx = None, trg_mx = None):
    '''
    
    '''
    
 
    L = len(target.verts)
    
    if not src_trg_map:
        src_trg_map = {-1:-1}
    l = len(src_trg_map)
    print('There are %i items in the vert map' % len(src_trg_map))
    if not src_mx:
        src_mx = Matrix.Identity(4)
    
    if not trg_mx:
        trg_mx = Matrix.Identity(4)
        i_trg_mx = Matrix.Identity(4)
    else:
        i_trg_mx = trg_mx.inverted()
        
        
    old_bmverts = [v for v in target.verts]  #this will store them in order
    new_bmverts = [] #these will be created in order
    
    source.verts.ensure_lookup_table()

    for v in source.verts:
        if v.index not in src_trg_map:
            new_ind = len(target.verts)
            new_bv = target.verts.new(i_trg_mx * src_mx * v.co)
            new_bmverts.append(new_bv)  #gross...append
            src_trg_map[v.index] = new_ind
            
        else:
            print('vert alread in the map %i' % v.index)
    
    lverts = old_bmverts + new_bmverts
    
    target.verts.index_update()
    target.verts.ensure_lookup_table()
    
    new_bmfaces = []
    for f in source.faces:
        v_inds = []
        for v in f.verts:
            new_ind = src_trg_map[v.index]
            v_inds.append(new_ind)
            
        if any([i > len(lverts)-1 for i in v_inds]):
            print('impending index error')
            print(len(lverts))
            print(v_inds)
            
        if target.faces.get(tuple(lverts[i] for i in v_inds)):
            print(v_inds)
            continue
        new_bmfaces += [target.faces.new(tuple(lverts[i] for i in v_inds))]
    
        target.faces.ensure_lookup_table()
    target.verts.ensure_lookup_table()

    new_L = len(target.verts)
    
    if src_trg_map:
        if new_L != L + len(source.verts) -l:
            print('seems some verts were left in that should not have been')
예제 #30
0
    def calc_vert_tangents_wire(self, obmat, viewmat):
        """self.loop_tris.bmのWIREフラグが立っている頂点のtangentを計算。
        """
        WIRE = self.WIRE
        loop_tris = self.loop_tris

        vert_tangents = {}  # eve: Vector

        if viewmat:
            obmat3 = obmat.to_3x3()
            vmat3 = viewmat.to_3x3()
        else:
            obmat3 = Matrix.Identity(3)
            vmat3 = Matrix.Identity(3)

        edges = [
            eed for eed in loop_tris.bm.edges if loop_tris.eflags[eed] & WIRE
        ]
        paths = vabm.make_paths_from_edges(edges=edges)
        for path in paths:
            verts = path[:]
            if verts[0] == verts[-1]:
                verts = verts[:-1]
            vecs = [v.co for v in verts]

            bbmat, bbscale = vam.get_obb(vecs)
            bbmat3 = bbmat.to_3x3()

            # 点
            if bbscale[0] < EPS:
                pass

            # 直線。tangentの方向はview_matrixに依存
            elif bbscale[1] < EPS:
                axis = vmat3 * obmat3 * bbmat3.col[0]
                axis.normalize()
                ax = Vector((-axis[1], axis[0], 0))
                vec = obmat3.inverted() * (vmat3.inverted() * ax)
                vec.normalize()
                # vec: 画面と平行でpathと垂直なベクトル
                for eve in verts:
                    if loop_tris.vflags[eve] & WIRE:
                        vert_tangents[eve] = [vec.copy() for i in range(3)]
            else:
                # 平面、立体
                imat3 = bbmat3.inverted()
                vecs2d = [(imat3 * v).to_2d() for v in vecs]  # obb座標
                # しばらくVectorを2Dで処理
                tangents = []  # 内側のベクトル。最初は左回りを想定した計算を行う
                angles = []  # vec1からvec2への差。合計が負なら右回り
                rmat = Matrix.Rotation(math.pi / 2, 2)
                for i in range(len(vecs2d)):
                    # .______________.______________.
                    # v  -(vec1)->  vec  -(vec2)->  v
                    vec = vecs2d[i]
                    vec1 = vec - vecs2d[i - 1]
                    vec2 = vecs2d[(i + 1) % len(vecs2d)] - vec

                    # 先頭・末尾
                    if not path.cyclic and (i == 0 or i == len(vecs2d) - 1):
                        if i == 0 and vec2.length > 0.0:
                            tangents.append(rmat * vec2.normalized())
                        elif i == len(vecs2d) - 1 and vec1.length > 0.0:
                            tangents.append(rmat * vec1.normalized())
                        else:
                            tangents.append(Vector((0, 0)))
                        angles.append(0.0)

                    # 他
                    else:
                        if vec1.length > 0.0 or vec2.length > 0.0:
                            if vec1.length > 0.0:
                                vec1.normalize()
                            if vec2.length > 0.0:
                                vec2.normalize()
                            if vec1.length > 0.0 and vec2.length > 0.0:
                                v = (rmat * ((vec1 + vec2) / 2)).normalized()
                                f = abs(vam.cross2d(vec2, v))
                                if f > EPS:
                                    tangents.append(v / f)
                                else:
                                    tangents.append(Vector((0, 0)))
                                f = vam.cross2d(vec1, vec2)
                                f = max(-1.0, min(f, 1.0))
                                angles.append(math.asin(f))
                            else:
                                if vec1.length > 0.0:
                                    v = (rmat * vec1).normalized()
                                else:
                                    v = (rmat * vec2).normalized()
                                f = abs(vam.cross2d(vec2, v))
                                if f > EPS:
                                    tangents.append(v / f)
                                else:
                                    tangents.append(Vector((0, 0)))
                                angles.append(0.0)
                        else:
                            tangents.append(Vector((0, 0)))
                            angles.append(0.0)

                # エッジが右回りだったならベクトルを反転する
                if sum(angles) < 0.0:
                    for v in tangents:
                        v.negate()

                for eve, vec in zip(verts, tangents):
                    if loop_tris.vflags[eve] & WIRE:
                        v = bbmat3 * vec.to_3d()
                        vert_tangents[eve] = [v.copy() for i in range(3)]
        return vert_tangents