0
$\begingroup$

What I have:

select two points then click “First” (get length between), then other two points - click “Second” (get length between), and then click “Scale” and get value “Second / First”.

Am I right with code, or somewhere it can be simplified? enter image description here

import bpy

import bmesh
from bpy.types import Operator, Panel, PropertyGroup

def get_float1(self):
    return self["l1"]

def set_float1(self, value):
    self["l1"] = value

def get_float2(self):
    return self["l2"]

def set_float2(self, value):
    self["l2"] = value

def length_first():
    obj = bpy.context.edit_object
    me = obj.data
    bm = bmesh.from_edit_mesh(me)

    elem_list1 = []

    for g in bm.select_history:
        elem_list1.append(g)
            
    lf1 = elem_list1[0].co
    lf2 = elem_list1[1].co

    length1 = (lf2 - lf1).length
    print("First value =", length1)
    return length1
    
def length_second():    
    obj = bpy.context.edit_object
    me = obj.data
    bm = bmesh.from_edit_mesh(me)

    elem_list2 = []

    for g in bm.select_history:
        elem_list2.append(g)
            
    ls1 = elem_list2[0].co
    ls2 = elem_list2[1].co

    length2 = (ls2 - ls1).length    
    print("Second value =", length2)    
    return length2  


class VERTS_OT_length (Operator):
    bl_idname = "verts.length"
    bl_label = "l"
    bl_description = ""

    action: bpy.props.EnumProperty (
        items=[('first','first',''),
               ('second','second',''),
               ('scale','scale','')])
    
    def execute(self, context):
        props  = context.scene.LENGTH_PG_main
        if self.action == "first":            
            props.l1 = length_first()            
        if self.action == "second":
            props.l2 = length_second()
        if self.action == "scale":
            scale = props.l2 / props.l1
            print("----------------------")
            #print(props.l1)
            #print(props.l2)
            print("Scale =", scale)
        return {'FINISHED'}


class LENGTH_PG_main (PropertyGroup):

    l1: bpy.props.FloatProperty(
        name="Get",
        subtype="DISTANCE",
        get=get_float1,
        set=set_float1
    )
    
    l2: bpy.props.FloatProperty(
        name="Set",
        subtype="DISTANCE",
        get=get_float2,
        set=set_float2
    )
    
    
class TEST_PT_main(Panel):
    bl_label = "TEST"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'TEST'
    
    def draw(self, context):
        layout = self.layout
        col = layout.column(align = True)
        row1 = col.row(align = True)        
        props  = context.scene.LENGTH_PG_main
        row1.prop(props, "l1", text="")
        row1.operator("verts.length", text="First").action = "first"
        
        col = layout.column(align = True)
        row2 = col.row(align = True)        
        props  = context.scene.LENGTH_PG_main
        row2.prop(props, "l2", text="")
        row2.operator("verts.length", text="Second").action = "second"
        
        col = layout.column()
        col.operator("verts.length", text="Scale").action = "scale"


classes = (
    VERTS_OT_length,
    LENGTH_PG_main,
    TEST_PT_main,
)

register, unregister = bpy.utils.register_classes_factory(classes)

def register():    
    for c in classes:
        bpy.utils.register_class(c)

    bpy.types.Scene.LENGTH_PG_main = bpy.props.PointerProperty(type = LENGTH_PG_main)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
    
    del bpy.types.Scene.LENGTH_PG_main
    
if __name__ == "__main__":
    register()
$\endgroup$
1
0
$\begingroup$

so answer is:

  1. def length_first() and def length_second() can be merged in one def length()
def length():
    obj = bpy.context.edit_object
    me = obj.data
    bm = bmesh.from_edit_mesh(me)

    elem_list1 = []

    for g in bm.select_history:
        elem_list1.append(g)
            
    lf1 = elem_list1[0].co
    lf2 = elem_list1[1].co

    distance = (lf2 - lf1).length
    return length
  1. as @batFINGER sugested
def get_float1(self):
    return self["l1"]

def set_float1(self, value):
    self["l1"] = value

def get_float2(self):
    return self["l2"]

def set_float2(self, value):
    self["l2"] = value

need to replace with own properties to not get error like KeyError: 'bpy_struct[key]: key "l1" not found'

The final code for me look like this:

import bpy

import bmesh
from bpy.types import Operator, Panel, PropertyGroup

def get_float1(self):
    props  = bpy.context.scene.LENGTH_PG_main
    return props.dist1

def set_float1(self, value):
    props  = bpy.context.scene.LENGTH_PG_main
    props.dist1 = value

def get_float2(self):
    props  = bpy.context.scene.LENGTH_PG_main
    return props.dist2

def set_float2(self, value):
    props  = bpy.context.scene.LENGTH_PG_main
    props.dist2 = value

def length():    
    obj = bpy.context.edit_object
    me = obj.data
    bm = bmesh.from_edit_mesh(me)

    elem_list2 = []

    for g in bm.select_history:
        elem_list2.append(g)
            
    ls1 = elem_list2[0].co
    ls2 = elem_list2[1].co

    length = (ls2 - ls1).length    
    print("Second value =", length)    
    return length  


class VERTS_OT_length (Operator):
    bl_idname = "verts.length"
    bl_label = "l"
    bl_description = ""

    action: bpy.props.EnumProperty (
        items=[('first','first',''),
               ('second','second',''),
               ('scale','scale','')])
    
    def execute(self, context):
        props  = context.scene.LENGTH_PG_main
        if self.action == "first":            
            props.l1 = length()            
        if self.action == "second":
            props.l2 = length()
        if self.action == "scale":
            scale = props.l2 / props.l1
            print("----------------------")
            #print(props.l1)
            #print(props.l2)
            print("Scale =", scale)
        return {'FINISHED'}


class LENGTH_PG_main (PropertyGroup):

    dist1: bpy.props.FloatProperty(default=1)
    dist2: bpy.props.FloatProperty(default=1)
    
    l1: bpy.props.FloatProperty(
        name="Get",
        subtype="DISTANCE",
        get=get_float1,
        set=set_float1
    )
    
    l2: bpy.props.FloatProperty(
        name="Set",
        subtype="DISTANCE",
        get=get_float2,
        set=set_float2
    )    
    
class TEST_PT_main(Panel):
    bl_label = "TEST"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'TEST'
    
    def draw(self, context):
        layout = self.layout
        col = layout.column(align = True)
        row1 = col.row(align = True)        
        props  = context.scene.LENGTH_PG_main
        row1.prop(props, "l1", text="")
        row1.operator("verts.length", text="First").action = "first"
        
        col = layout.column(align = True)
        row2 = col.row(align = True)        
        props  = context.scene.LENGTH_PG_main
        row2.prop(props, "l2", text="")
        row2.operator("verts.length", text="Second").action = "second"
        
        col = layout.column()
        col.operator("verts.length", text="Scale").action = "scale"


classes = (
    VERTS_OT_length,
    LENGTH_PG_main,
    TEST_PT_main,
)

register, unregister = bpy.utils.register_classes_factory(classes)

def register():    
    for c in classes:
        bpy.utils.register_class(c)

    bpy.types.Scene.LENGTH_PG_main = bpy.props.PointerProperty(type = LENGTH_PG_main)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
    
    del bpy.types.Scene.LENGTH_PG_main
    
if __name__ == "__main__":
    register()

Hope it will be useful.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.