# RegionView3D from Region object and vice versa

How do I get a RegionView3D object from a Region object?

I'm working on an operator in the quad view of the 3D view and I need to determine which region the user clicked in and the relative position to that specific region

• I've tried event.mouse_region_x and y but those are relative to the original region that the operator was ran in
• I've also tried using the ctx object provided to the operator's modal function as well as bpy.context but both seem to be frozen on the original place the operator was ran in?
• Current solution is to check all areas in bpy.context.screen.areas, find the one clicked in and then find the region in that area. This means I now have a region but I can't get the RegionView3D from it. This is because RegionView3D is accessed from a Space object and that doesn't have any actual positional information on the screen.

A RegionView3D is actually a space, the access path is bpy.context.screen.areas[#].spaces.active.region_3d (area being of type VIEW_3D), or in case of quadview mode, ... spaces.active.region_quadviews[#].

There are no direct references from a region to a RegionView3D.

It's possible to find the right quadview region and its space, here's a (modal timer) example:

import bpy
import math

view_orientation = "Camera Persp"

else:
r = lambda x: round(x, 2)

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'}

view_orientation =  orientation_dict.get(tuple(map(r, view_rot)), 'USER').capitalize()
view_orientation += " " + quadview.view_perspective.capitalize()

if space.local_view is not None:
view_orientation += " (Local)"

return view_orientation

for area in context.screen.areas:
if area.type != 'VIEW_3D':
continue
return
i = -1
for region in area.regions:
if region.type == 'WINDOW':
i += 1
if (x >= region.x and
y >= region.y and
x < region.width + region.x and
y < region.height + region.y):

return (area.spaces.active, i)
return (None, None)

class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "Modal Timer Operator"

_timer = None

def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
return self.cancel(context)

if event.type == 'TIMER':
space, i = get_quadview_index(context, event.mouse_x, event.mouse_y)
if space is not None:

return {'PASS_THROUGH'}

def execute(self, context):
wm = context.window_manager
return {'RUNNING_MODAL'}

def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
return {'FINISHED'}

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

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

if __name__ == "__main__":
register()

# test call
bpy.ops.wm.modal_timer_operator()

• Is it safe to assume that in area.regions will have regions in the same order every time? Same with spaces.active.region_quadviews? Because then that simplifies things a lot – Coburn Jan 19 '15 at 18:51
• I believe they are. You may wanna check the code that many all 4 regions available to python. Here's the related bug report: developer.blender.org/T39028 – CodeManX Jan 20 '15 at 9:25

It doesn't actually seem possible.

Using this other topic "Getting the active region" as sort of a jumping off point, you'll have to go through and compare all the regions positions to the indices of the quadviews list (having to assume that quadviews is a fixed list where 0 is Front, 1 is Top, etc.)

Couldn't come up with a better way to sort these but here it is

#+-------------------------------------+
#| reg 1  (TOP/XY)  | reg 3 (USER/USR) |
#|------------------+------------------|
#| reg 0 (FRONT/XZ) | reg 2 (RIGHT/YZ) |
#+-------------------------------------+
#First find reg 0
minReg = None
for reg in ctx.area.regions:
if reg.type != "WINDOW":
continue
if not minReg:
minReg = reg
continue
if reg.x <= minReg.x and reg.y <= minReg.y:
minReg = reg

#Place all the other regions with respect to reg 0
regions = [None, None, None, None]
regions[0] = minReg
for reg in ctx.area.regions:
if reg.type != "WINDOW" or reg == regions[0]:
continue
if reg.x > regions[0].x and reg.y > regions[0].y:
regions[3] = reg
elif reg.x > regions[0].x:
regions[2] = reg
elif reg.y > regions[0].y:
regions[1] = reg

#Make the dictionary
self.viewDict = {