2
$\begingroup$

I'm trying to improve my zoom_to method for moving the camera towards an object in the scene:

def zoom_to(scene, camera, object):

    co_list = []
    for point_co in [point[:] for point in object.bound_box]:
        for co in point_co:
            co_list.append(co)

    loc_new_for_cam, foo = camera.camera_fit_coords(scene, co_list)

    camera.location = loc_new_for_cam

However I'm not quite understanding how camera_fit_coords works and I'm wondering if a python generator would improve the code by not having the double for-cycle build a useless list.

I tried with:

def gen_co_list(obj):
    for point_co in [point[:] for point in obj.bound_box]:
        for co in point_co:
            yield co

def zoom_to_g(scene, camera, obj):
    loc_new_for_cam, foo = camera.camera_fit_coords(scene, gen_co_list(obj))
    camera.location = loc_new_for_cam

But I get:

ValueError: Object.camera_fit_coords(): error with argument 2, "coordinates" - sequence expected at dimension 1, not 'generator'

Also, if there is a way of avoiding foo completely, this could be a one-liner even. It might not be as clear, though.

$\endgroup$
2
$\begingroup$

EDIT: found the true improvement thanks to @batFINGER

After using the tip from @batFINGER and some other minor modification (I was initially editing gen_co_list...), the method can become a still comprehensible one-liner:

 def zoom_to_g5(scene, camera, object):
    camera.location, foo = camera.camera_fit_coords(scene, [co for corner in object.bound_box for co in corner])

I wanted a faster method, so I'm using list comprehension instead of a generator. There shouldn't be a memory problem since there are only ever 8 corners in the bounding box.

The method is ~25% faster, clocking in at:

>>>print(min(timeit.Timer('cam.location=0.0,0.0,7.0; zoom_to_g5(scn, cam, obj)', setup=setup).repeat(7, 1000)))
0.007111115999578033

OLD

It seems it was a mistake in my comprehension of generators, and the code should have been:

def gen_co_list(object):
    for point_co in [point[:] for point in object.bound_box]:
        for co in point_co:
            yield co

def zoom_to_g(scene, camera, object):
    loc_new_for_cam, foo = camera.camera_fit_coords(scene, [co for co in gen_co_list(object)])
    camera.location = loc_new_for_cam

That said, trying to time the code yields different results than what I expected:

setup = """
import bpy
scn = bpy.context.scene
cam = bpy.data.objects['Camera']
obj = bpy.data.objects['Cube']
def zoom_to(scene, camera, object):
    co_list = []
    for point_co in [point[:] for point in object.bound_box]:
        for co in point_co:
            co_list.append(co)
    loc_new_for_cam, foo = camera.camera_fit_coords(scene, co_list)
    camera.location = loc_new_for_cam

def gen_co_list(object):
    for point_co in [point[:] for point in object.bound_box]:
        for co in point_co:
            yield co

def zoom_to_g(scene, camera, object):
    loc_new_for_cam, foo = camera.camera_fit_coords(scene, [co for co in gen_co_list(object)])
    camera.location = loc_new_for_cam
"""

>>>print(min(timeit.Timer('cam.location=0.0,0.0,7.0; zoom_to(scn, cam, obj)', setup=setup).repeat(7, 1000)))
0.009414574999937031
>>>print(min(timeit.Timer('cam.location=0.0,0.0,7.0; zoom_to_g(scn, cam, obj)', setup=setup).repeat(7, 1000)))
0.00963822900030209

run on blender's classic cube.

I will therefore stick with the first zoom_to version, even though I thought the contrary would happen.

$\endgroup$
  • 1
    $\begingroup$ Be tempted to return a generator return (axis for p in C.object.bound_box for axis in p) and avoid the list copy point[:] $\endgroup$ – batFINGER Jul 3 '18 at 16:03
  • 1
    $\begingroup$ That's what I was looking for! After 3 more iterations of code improvement I have the better method, and it is ~25% faster than the original one! $\endgroup$ – Laboratorio Cobotica Jul 4 '18 at 12:39

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.