3
$\begingroup$

This script builds a 3-digit, 7-segment red LED display and cycles through 0-315 in steps of 45. But it doesn't quite work.

When changing the first digit to "EDIT" mode in order to change the material of each face (according to the digit pattern) I get an error I don't understand.

NOTE: Set 3D viewport shading to "Rendered" before running script.

This is what it should look like after it finishes running.

enter image description here

ERROR MESSAGE

Traceback (most recent call last): File "/Users/david914/Documents/Blender/BlenderPython/Fishing/3D text writing/text writing 7-seg digital counter v03.blend/Animate 7-segment", line 225, in File "/Applications/blender.app/Contents/MacOS/../Resources/2.74/scripts/modules/bpy/ops.py", line 189, in call ret = op_call(self.idname_py(), None, kw) RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect Error: Python script fail, look in the console for now...

def make_LED_mat(mat_name, color_transp=None, color_emit=None, 
                   emit_strength=None, frac=None):

# modified from HERE: http://blender.stackexchange.com/a/32162/5334
# and HERE:  http://blender.stackexchange.com/q/34609/5334

    LED_mat = bpy.data.materials.new(mat_name)
    LED_mat.use_nodes = True
    tree  = LED_mat.node_tree
    nodes = LED_mat.node_tree.nodes

    for node in nodes:
        tree.nodes.remove(node) # clean it up, start fresh

    out    = nodes.new(type='ShaderNodeOutputMaterial')
    mix    = nodes.new(type='ShaderNodeMixShader')
    emit   = nodes.new(type='ShaderNodeEmission')
    transp = nodes.new(type='ShaderNodeBsdfTransparent')

    out.location      =  300,    0
    mix.location      =    0,    0
    transp.location   = -200,   50
    emit.location     = -200, -100

    # link mix_shader to material output
    a = mix.outputs['Shader']
    b = out.inputs['Surface']
    tree.links.new(a, b)

    # link transp to mix
    a = transp.outputs['BSDF']
    b = mix.inputs[1]  # 'Shader' is used twice, so you access via index.
    tree.links.new(a, b)

    # link emissive to mix
    a = emit.outputs['Emission']
    b =  mix.inputs[2]
    tree.links.new(a, b)

    if color_transp == None:
        color_diff = [0.8, 0.8, 0.8, 1.0]
    if color_emit == None:
        color_emit = [1.0, 0.2, 0.2, 1.0]
    if frac == None:
        frac = 0.5
    if emit_strength == None:
        emit_strength = 2.0

    mix.inputs[0].default_value = frac  # factor
    transp.inputs['Color'].default_value = color_transp
    emit.inputs['Color'].default_value    = color_emit
    emit.inputs['Strength'].default_value = emit_strength

    return LED_mat


def make_7_seg(hw, hl, gapxy, slant_factor):

    xnom = np.array([-hl, -hl+hw, hl-hw, hl, hl-hw, -hl+hw])
    ynom = np.array([0.0, -hw, -hw, 0.0, hw, hw])
    znom = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])

    xoffs = (hl+gapxy) * np.array([0, 1, 1, 0, -1, -1, 0])
    yoffs = (hl+gapxy) * np.array([2, 1, -1, -2, -1, 1, 0])
    rots  = 0.5 * np.pi * np.array([0, 1, 1, 0, 1, 1, 0])
    sinrot, cosrot = np.sin(rots), np.cos(rots)

    X = cosrot[:,None]*xnom[None,:] - sinrot[:,None]*ynom[None,:] + xoffs[:,None]
    Y = sinrot[:,None]*xnom[None,:] + cosrot[:,None]*ynom[None,:] + yoffs[:,None]
    Z = np.zeros_like(X, dtype='float')        

    X = X + slant_factor*Y        

# help from here:http://blender.stackexchange.com/a/35362/5334
# question from here: http://blender.stackexchange.com/questions/35360/having-problems-with-python-int-types-specifying-mesh-faces-again

    faces = np.arange(7*6).reshape(7,6).tolist()
    verts = [ thing for thing in zip(X.flatten(), Y.flatten(), Z.flatten())]

    me = bpy.data.meshes.new('digit')
    ob = bpy.data.objects.new('digit', me)
    bpy.context.scene.objects.link(ob)
    me.from_pydata(verts, [], faces)

    return ob

def segit_dictionary():

#
#  ---A---
# |       |
# F       B
# |       |
#  ---G---
# |       |
# E       C
# |       |
#  ---D---
#
#      A  B  C  D  E  F  G
# "0"  X  X  X  X  X  X  -
# "1"  -  X  X  -  -  -  -
# "2"  X  X  -  X  X  -  X
# "3"  X  X  X  X  -  -  X
# "4"  -  X  X  -  -  X  X
# "5"  X  -  X  X  -  X  X
# "6"  X  -  X  X  X  X  X
# "7"  X  X  X  -  -  -  -
# "8"  X  X  X  X  X  X  X
# "9"  X  X  X  X  -  X  X
# " *ALTERNATES* "
# "9*" X  X  X  -  -  X  X
# "7*" X  X  X  -  -  X  -
# "6*" -  -  X  X  X  X  X
# "1*" -  -  -  -  X  X  -
#
#

    segit = dict()
    segit[0] = [1,1,1,1,1,1,0]
    segit[1] = [0,1,1,0,0,0,0]
    segit[2] = [1,1,0,1,1,0,1]
    segit[3] = [1,1,1,1,0,0,1]
    segit[4] = [0,1,1,0,0,1,1]
    segit[5] = [1,0,1,1,0,1,1]
    segit[6] = [1,0,1,1,1,1,1]
    segit[7] = [1,1,1,0,0,0,0]
    segit[8] = [1,1,1,1,1,1,1]
    segit[9] = [1,1,1,1,0,1,1]
    digits = [thing for thing in segit]

    for digit in digits:
        segit[str(digit)] = segit[digit]  # text is OK too

    for thing in ['blank', 'BLANK', 'dark', 'DARK', 'null', 'NULL']:
        segit[thing] = [0,0,0,0,0,0,0]

    return segit



import bpy
import bmesh
import numpy as np
import time

# MAKE MATERIALS
ON_mat = make_LED_mat("ON", color_transp= (0.8, 0.8, 0.8, 1.0), 
                            color_emit  = (1.0, 0.0, 0.0, 1.0),
                            emit_strength =1.0, frac=1.0)

OFF_mat = make_LED_mat("OFF", color_transp= (0.8, 0.8, 0.8, 1.0), 
                              color_emit  = (1.0, 0.0, 0.0, 1.0),
                              emit_strength =1.0, frac=0.0)

# MAKE DISPLAY
# MAKE DIGITS
ones_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
tens_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
hundreds_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
ones_digit.name = "ones_digit"
tens_digit.name = "tens_digit"
hundreds_digit.name = "hundreds_digit"
digits = [hundreds_digit, tens_digit, ones_digit]

# PLACE THEM UPRIGHT
for i, digit in enumerate(digits):
    digit.rotation_euler = ((0.5*np.pi, 0.0, 0.0))
    digit.location = ((7.0*(i-1), 0, 5.0))
    digit.data.materials.append(OFF_mat)  # material index 0
    digit.data.materials.append(ON_mat)   # material index 1
    #digit.active_material = ON_mat    # turn everything on first

# GET DICTIONARY
S = segit_dictionary()

# later we'll put SUZANNE behind the semi-transparent LEDs and rotate her by these angles

angles_deg = list(range(0, 350, 45))
angles = [thing*np.pi/180.0 for thing in angles_deg]


# try to animate the 3D window
# setup some stuff first
# from HERE:  https://gist.github.com/zeffii/a422d4d7dc04ed023a57#file-proof2-py
context = bpy.context
for area in context.screen.areas:
    if area.type == "VIEW_3D":
        ctx = { "window": context.window, "area": area, "region":None}
        break
US = lambda: bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)

# if ready to go:
if 1 == 1:
    #bpy.context.space_data.viewport_shade = 'RENDERED'

    for a, adeg in zip(angles, angles_deg):
        astr = str(adeg+1000)[1:]
        # hundreds:
        if astr[0] == "0":
            p_hundreds = S['blank']  # leading zero suppresion
        else:
            p_hundreds = S[astr[0]]
        # tens:
        if astr[1] == "0" and astr[0] == "0":  # leading zero suppresion
            p_tens = S['blank']
        else:
            p_tens = S[astr[1]]
        # ones:
        p_ones = S[astr[2]]
        patterns = [p_hundreds, p_tens, p_ones]

        if 1 == 1:
            print(adeg, " ", astr)
            print(p_hundreds)
            print(p_tens)
            print(p_ones)
            print(" ")

        if 1 == 1:
            for dig, pat in zip(digits, patterns):
                bpy.ops.object.select_all(action='DESELECT')
                dig.select = True
                bpy.ops.object.mode_set(mode='EDIT')
                bm = bmesh.from_edit_mesh(dig.data)
                for f, p in zip(bm.faces, pat):  # each face coresponds to one value in pattern list
                    f.material_index = p         # index 0 or 1
                dig.data.update()
                bpy.ops.object.mode_set(mode='OBJECT')

            US()
            time.sleep(1.0)
$\endgroup$
  • $\begingroup$ Can you try NOT switching to edit mode? I've had this error as well, and I could not find a solution except changing modes earlier in my script. $\endgroup$ – beiller Aug 10 '15 at 13:55
4
$\begingroup$

Try changing the following:

bpy.ops.object.select_all(action='DESELECT')
dig.select = True
#ADD THIS LINE
bpy.context.scene.objects.active = dig
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(dig.data)
$\endgroup$
  • $\begingroup$ Hey that's great! I still get "active" and "selected" confused even though I know better. Problem with scripting instead of using mouse - you forget you have to click things pythonically. Thank you @beiller! $\endgroup$ – uhoh Aug 10 '15 at 14:35

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.