3

I want to create a Python script such that it has 1 Input textbox and a Button.

In Input textbox, the user will be putting a configuration which will look something like this .

2-(90),5-(0),4-(-90).

This above configuration means :

Create a Line of 2 units in 90 degrees, 5 units in 0 degrees direction, and lastly, 4 units in -90 degrees.

verts = [
    Vector((0, 0, 0)),
    Vector((0, 0, 2)),
    Vector((5, 0, 2)),
    Vector((5,0,-4)),
   ]

edges = [(0, 1), (1, 2), (2, 3)] faces = []

mesh = bpy.data.meshes.new(name="New Object Mesh") mesh.from_pydata(verts, edges, faces)

useful for development when the mesh may be invalid.

mesh.validate(verbose=True)

object_data_add(context, mesh, operator=self)

I am trying to do this but still cannot figure out how to put the user input in the verts variable. Can someone please help me out with this?

Gorgious
  • 30,723
  • 2
  • 44
  • 101
VatsalG
  • 31
  • 1
  • 1
    Hello, what exactly do you have trouble with ? Do you have trouble reading the input, or creating a parsing function, or finding the correct geometry and trigonometry operations to achieve the result ? – Gorgious Aug 19 '21 at 08:58

1 Answers1

8

A run through using numpy.

Numpy has a nice little method fromstring to very quickly get our string data into an array of floats. Didn't bother with the bracket, hyphen BS, simply made it comma separated list of values, with an expectation of an even amount. There are zillions of ways to string a cat, using python, seek on stackoverflow.

Get flat list from string

>>> import numpy as np
>>> cmd = "2, 90, 5, 0, 4, -90"
>>> data = np.fromstring(cmd, sep=",", dtype=float)
>>> data
array([  2.,  90.,   5.,   0.,   4., -90.])

Reshape into length, angle pairs

>>> data = data.reshape((-1, 2))
>>> data
array([[  2.,  90.],
       [  5.,   0.],
       [  4., -90.]])

Or transposed such that lengths in row 0, angles in next

>>> data.T
array([[  2.,   5.,   4.],
       [ 90.,   0., -90.]])

Radians are required in blender, so convert

>>> data.T[1] = np.radians(data.T[1])
>>> data
array([[ 2.        ,  1.57079633],
       [ 5.        ,  0.        ],
       [ 4.        , -1.57079633]])

Next our starting vert, and direction vector. In the question you have used the $y=0$ or $XZ$ plane, with the origin as starting point. No rotation steps in $X$ axis direction

>>> v0 = (0, 0, 0)
>>> v = Vector((1, 0, 0))
>>> verts = [v0]

Then to get our verts, we scalar multiply our direction vector rotated by angle about $Y$ axis, and add result to the previous, till exhausted

>>> for d, angle in data:
...     R = Matrix.Rotation(angle, 3, 'Y')
...     verts.append(verts[-1] + d * R @ v)
...   

The result

>>> np.array(verts)
array([[ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00],
       [ 1.50995803e-07,  0.00000000e+00, -2.00000000e+00],
       [ 5.00000015e+00,  0.00000000e+00, -2.00000000e+00],
       [ 4.99999998e+00,  0.00000000e+00,  2.00000000e+00]])

Note if looking at plane from above, this will rotate clockwise. To rotate the other way negate one of the axis, or the angle.

edges

>>> edges = [(i - 1, i) for i in range(1, len(verts))]
>>> edges
[(0, 1), (1, 2), (2, 3)]

Now as an operator property

Here is a minor edit to the simple operator template to add a string property, which is converted as above. Since any rubbish can be typed in will require a try except clause.

enter image description here

import bpy
from bpy.props import StringProperty
import numpy as np

def main(context, cmd): try: data = np.fromstring(cmd, sep=",", dtype=float) print(data) except: print("Error with cmd") return False # use as above check it has even length etc

class SimpleOperator(bpy.types.Operator): """Tooltip""" bl_idname = "object.simple_operator" bl_label = "Simple Object Operator" bl_options = {'REGISTER', 'UNDO'} cmd : StringProperty()

def execute(self, context):
    main(context, self.cmd)
    return {'FINISHED'}


def register(): bpy.utils.register_class(SimpleOperator)

def unregister(): bpy.utils.unregister_class(SimpleOperator)

if name == "main": register()

# test call
bpy.ops.object.simple_operator('INVOKE_DEFAULT')

which prints to console

[]
[ 1.  0.  3. 90.  5. 45.]
batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • really, I don't get the point. Parsing a string is not really Blender related (the question may be out of subject). What do you really expect in this (very high) bounty exactly? (I won't give an answer, this is just to know/clarify). – lemon Aug 24 '21 at 18:56
  • Hey @lemon Good to see the "clutch" As stated just the completed operator is fine. It has been asked for over and over, Thought I'd add a sweetener. Also very interested in an answer to this one – batFINGER Aug 24 '21 at 20:00
  • I still don't understand what is to enhance here and why such a bounty. Would you mind explaining? – lemon Aug 30 '21 at 07:58
  • @lemon Wrote the answer below walking thru one way to do this, rather than adding a functioning script, as the question reads very much like an assignment question, especially when another user asks exactly same question, with the one intention of the answer being a script they run. This is about, anyone iterested in learning bpy can they produce that script (either with or without my answer). and get 500 rep as a bonus. In the end it looks like halfbonus will be reward, instead of script. – batFINGER Aug 30 '21 at 13:17