1
$\begingroup$

I need to store a KDTree in my scene, preferably attached to a specific Blender object. When storing standard Blender types associated with objects, I use

my_ob["my list"] = my_list

but a KDTree is not a primitive type, and I get the error "TypeError: only floats, ints and dicts are allowed in ID property arrays".

How can I store my KDTree so that I don't have to regenerate it many times over? This is for an addon, so I don't want to have to save a local file and reload.

Thanks.

$\endgroup$
1
  • 1
    $\begingroup$ Not sure you will have any luck. You can add a string property to hold a filename that holds the cached data. You could also pickle it to a text block in blenders text editor. $\endgroup$
    – sambler
    Mar 16, 2018 at 16:37

1 Answer 1

2
$\begingroup$

For these cases you can use pickle and base64 to string. But be aware that you need to use cKDTree according to https://stackoverflow.com/questions/37722991/unable-to-pickle-scipy-spatial-kdtree-objects

import pickle
import base64

# store kdtree
def _set_kdtree_for_object(my_obj, my_kdtree):
    pickled_kdtree = pickle.dumps(my_kdtree)
    # pickled_kdtree is binary convert it to a string
    base64encoded = base64.b64decode(pickled_kdtree).decode('utf-8')
    my_obj['my_list'] = base64encoded

# read back
def _get_kdtree_for_object(my_obj):
    base64encoded = my_obj['my_list']
    pickled_kdtree = base64.b64encode(base64encoded.encode('utf-8'))
    my_kdtree = pickle.loads(pickled_kdtree)
    return my_kdtree

Be aware that exceptions may happen due to different pickle implementations when python is updated in blender.

Depending on the usecase you could also use a global store on object name. This will not store the kdtree in your blend file, but you need to be able to recreate the kdtree when it is not available. This solves issues of python updates.

kdtree_lookup = {}

def _get_or_rebuild_kdtree_for_object(obj):
    global kdtree_lookup
    result = kdtree_lookup.get(obj)
    if result is None:
        # rebuild the kdtree
        ...
        # store it
        kdtree_lookup[obj] = result
    return result

You could also rebuild the kdtree's after loading of the blendfile using an handler.

$\endgroup$
1
  • $\begingroup$ Thanks for your response, this does indeed solve the question as asked. Unfortunately, my application is for an addon, so I don't want to have to interact with saved local files. I have updated the question accordingly. $\endgroup$
    – Animik
    Mar 19, 2018 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .