2
$\begingroup$

How can I insert a value in a array of vectors using Python 3.x?

The full code is below. It is using Blender 2.82a:

import bpy
import mathutils
import math

ob = bpy.context.object

#1) Get all vertexes and place in vector array
vec = [v.co for v in ob.data.vertices]

print("vec=%s" % vec)

It creates an array of Vectors of x,y,z values:

vec=[Vector((1.0, 1.0, 1.0)), Vector((1.0, 1.0, -1.0)), Vector((1.0, -1.0, 1.0)), Vector((1.0, -1.0, -1.0)), Vector((-1.0, 1.0, 1.0)), Vector((-1.0, 1.0, -1.0)), Vector((-1.0, -1.0, 1.0)), Vector((-1.0, -1.0, -1.0))]

And I would like to insert a 7 at the start of each vector so it would look like:

vec=[Vector((7, 1.0, 1.0, 1.0)), Vector((7, 1.0, 1.0, -1.0)), Vector((7, 1.0, -1.0, 1.0)), Vector((7, 1.0, -1.0, -1.0)), Vector((7, -1.0, 1.0, 1.0)), Vector((7, -1.0, 1.0, -1.0)), Vector((7, -1.0, -1.0, 1.0)), Vector((7, -1.0, -1.0, -1.0))]

The .insert doesn't seem to work in vectors.

Added animated gif of what it creates

$\endgroup$
2
$\begingroup$

By default Vertices vectors are in 3 dimensions so we need to create a new one with 4 dimensions.

import bpy
from mathutils import Vector

try:
    vectors = [Vector((7.0, v.co.x, v.co.y, v.co.z)) for v in bpy.context.object.data.vertices]    
    print(vectors)
except AttributeError:
    print('Please select a mesh object')

Result :

enter image description here

| improve this answer | |
$\endgroup$
  • 4
    $\begingroup$ One-liner in the console: [Vector((7.0, v.co.x, v.co.y, v.co.z)) for v in C.object.data.vertices] constructing a new Vector per list item using a list comprehension (output is the same). $\endgroup$ – brockmann Apr 27 at 9:58
  • 1
    $\begingroup$ @brockmann Thanks for pointing that out ! $\endgroup$ – Gorgious Apr 27 at 10:18
2
$\begingroup$

Using numpy

Can do this quickly using foreach_get in conjunction with numpy. Speedup will be noticeably quicker for high vertex count meshes.

import bpy
import numpy as np

context = bpy.context
# assume that object is a ob.type == 'MESH'
ob = context.object
me = ob.data


coords = np.empty(len(me.vertices) * 3) # ravelled list
me.vertices.foreach_get("co", coords) # load in coords

coords4d = np.insert(
        np.reshape(coords, (-1, 3)), # reshaped to 3d
        0, # insert before index 0
        values=7, # insert values
        axis=1) # insert a column

Result on default cube

>>> coords4d
array([[ 7.        ,  1.        ,  0.99999994, -1.        ],
       [ 7.        ,  1.        , -1.        , -1.        ],
       [ 7.        , -1.00000012, -0.99999982, -1.        ],
       [ 7.        , -0.99999964,  1.00000036, -1.        ],
       [ 7.        ,  1.00000048,  0.99999946,  1.        ],
       [ 7.        ,  0.99999934, -1.0000006 ,  1.        ],
       [ 7.        , -1.00000036, -0.99999964,  1.        ],
       [ 7.        , -0.99999994,  1.        ,  1.        ]])

Mapping result to a list of vectors

>>> list(map(Vector, coords4d))
[Vector((7.0, 1.0, 0.9999999403953552, -1.0)), Vector((7.0, 1.0, -1.0, -1.0)), Vector((7.0, -1.0000001192092896, -0.9999998211860657, -1.0)), Vector((7.0, -0.9999996423721313, 1.0000003576278687, -1.0)), Vector((7.0, 1.0000004768371582, 0.999999463558197, 1.0)), Vector((7.0, 0.9999993443489075, -1.0000005960464478, 1.0)), Vector((7.0, -1.0000003576278687, -0.9999996423721313, 1.0)), Vector((7.0, -0.9999999403953552, 1.0, 1.0))]

Or similarly with quaternions (as per example)

>>> for q in map(Quaternion, coords4d):
...     q
...     
Quaternion((7.0, 1.0, 0.9999999403953552, -1.0))
Quaternion((7.0, 1.0, -1.0, -1.0))
Quaternion((7.0, -1.0000001192092896, -0.9999998211860657, -1.0))
Quaternion((7.0, -0.9999996423721313, 1.0000003576278687, -1.0))
Quaternion((7.0, 1.0000004768371582, 0.999999463558197, 1.0))
Quaternion((7.0, 0.9999993443489075, -1.0000005960464478, 1.0))
Quaternion((7.0, -1.0000003576278687, -0.9999996423721313, 1.0))
Quaternion((7.0, -0.9999999403953552, 1.0, 1.0))

Related:

Having the coords as a numpy array can do matrix math on list vectors quickly see:

Replace matrix @ vector list comprehensions with something more efficient

Note: re accepted answer, Going to revisit Best practices: Use try except sparingly Rather than checking an object is not a mesh by catching an attribute error can simply check for it

ob = context.object
if ob and ob.type == 'MESH':
     ...
else:
    print("Select a mesh")

IMO use try / except as a last resort. For example a typo like vetrices will pass thru and tell you to select a mesh.. making scripts a nightmare to debug.

| improve this answer | |
$\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.