5
$\begingroup$

Is it possible to access the alignment of the view from python? (e.g 'TOP', 'FRONT', 'RIGHT', etc.)

I looked in the api docs, but the closest I could find was view_perspective.

$\endgroup$
6
$\begingroup$

Looking at the implementation of view3d.viewnumpad in view3d_edit.c, it's just switch-ing over FRONT, BACK, etc. enumerations and setting the view matrix accordingly. The only way I found is through deducing the orientation from view matrix in Python, in the following barebones example using either view_matrix:

import math

def get_view_orientation_from_matrix(view_matrix):
    r = lambda x: round(x, 2)
    view_rot = view_matrix.to_euler()

    orientation_dict = {(0.0, 0.0, 0.0) : 'TOP',
                        (r(math.pi), 0.0, 0.0) : 'BOTTOM',
                        (r(-math.pi/2), 0.0, 0.0) : 'FRONT',
                        (r(math.pi/2), 0.0, r(-math.pi)) : 'BACK',
                        (r(-math.pi/2), r(math.pi/2), 0.0) : 'LEFT',
                        (r(-math.pi/2), r(-math.pi/2), 0.0) : 'RIGHT'}

    return orientation_dict.get(tuple(map(r, view_rot)), 'UNDEFINED')

... or view_rotation as @WChargin suggested, seeing that it's normalized as stated in API docs:

def get_view_orientation_from_quaternion(view_quat):
    r = lambda x: round(x, 3)
    view_rot = view_quat.to_euler()

    orientation_dict = {(0.0, 0.0, 0.0) : 'TOP',
                        (r(math.pi), 0.0, 0.0) : 'BOTTOM',
                        (r(math.pi/2), 0.0, 0.0) : 'FRONT',
                        (r(math.pi/2), 0.0, r(math.pi)) : 'BACK',
                        (r(math.pi/2), 0.0, r(-math.pi/2)) : 'LEFT',
                        (r(math.pi/2), 0.0, r(math.pi/2)) : 'RIGHT'}

    return orientation_dict.get(tuple(map(r, view_rot)), 'UNDEFINED')

It currently ignores perspective/orthogonal and camera view, but that can be easily deduced from the region's other variables.

enter image description here

$\endgroup$
  • $\begingroup$ Where are you getting the pi/2 from? Those vectors aren't even normalized (e.g., 2pi^2/4 is not 1). You probably mean sqrt(2) for the ones with two nonzero components and 1 for the ones with just one... $\endgroup$ – wchargin Oct 21 '13 at 3:15
  • $\begingroup$ Especially considering the #define M_SQRT1_2 0.70710678118654752440 in conjunction with axis_set_view(C, v3d, ar, 0.0, 0.0, -M_SQRT1_2, -M_SQRT1_2, viewnum, nextperspo, align_active, smooth_viewtx); (for example). $\endgroup$ – wchargin Oct 21 '13 at 3:17
  • $\begingroup$ I get these constants the stupid way: executing each view shortcuts, and see the resulting matrix :D On second thought, maybe I should've used view_rotation.to_euler() as you suggested. $\endgroup$ – Adhi Oct 21 '13 at 4:26
4
$\begingroup$

Based on Adhi's solution, here's a complete operator to print all view3d perspectives like shown in the left-upper corner:

import bpy
import math


def main(context):
    view_orientations = []

    for area in context.screen.areas:
        if area.type == 'VIEW_3D':
            r3d = area.spaces.active.region_3d # fine for right-upper quadview view
            view_matrix = r3d.view_matrix

            view_orientation = get_view_orientation_from_matrix(view_matrix).capitalize()
            view_orientation += " " + r3d.view_perspective.capitalize()
            if area.spaces.active.local_view is not None:
                view_orientation += " (Local)"

            view_orientations.append(view_orientation)

    return view_orientations


def get_view_orientation_from_matrix(view_matrix):
    r = lambda x: round(x, 2)
    view_rot = view_matrix.to_euler()

    orientation_dict = {(0.0, 0.0, 0.0) : 'TOP',
                        (r(math.pi), 0.0, 0.0) : 'BOTTOM',
                        (r(-math.pi/2), 0.0, 0.0) : 'FRONT',
                        (r(math.pi/2), 0.0, r(-math.pi)) : 'BACK',
                        (r(-math.pi/2), r(math.pi/2), 0.0) : 'LEFT',
                        (r(-math.pi/2), r(-math.pi/2), 0.0) : 'RIGHT'}

    return orientation_dict.get(tuple(map(r, view_rot)), 'USER')


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"

    def execute(self, context):
        print("\n".join(main(context)))
        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()

Note: does only take the right-upper view in quadview mode into account.

$\endgroup$
1
$\begingroup$

It doesn't look like there's a clean way to do it.

Here's an excerpt of the painting code for the 3D viewport:

// view3d_draw.c:803
// in method: view3d_get_name
switch (rv3d->view) {
    case RV3D_VIEW_FRONT:
        if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho");
        else name = IFACE_("Front Persp");
        break;
    case RV3D_VIEW_BACK:
        if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho");
        else name = IFACE_("Back Persp");
        break;
    // etc ...
}
return name;

As you can see, it's simply checking these manually and looking them up (the IFACE_ is for localization). The string is never stored in a value anywhere.

You could perform a similar check in Python using the view_rotation property. See this answer for a starting point.

$\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.