Windows, Areas and Screens with Python

Problem: I’m making an addon for aligning complex objects. At one step in the process, the user needs to pick several corresponding reference points on two objects (or more…??)

Option A: This can be done in series on one object, then the other
Option B: Ideally, being able to visualize both objects, side by side, in local space will allow the user to pick corresponding points in parallel, even if the object overlap or block each other in the scene (or if other objects in scene block the view)


Plan:
-Duplicate the current window [done]
-Maximize the 3d view [done]
-Split the frame into two 3dView areas [can this be done in python?]
-Put the each of the areas in to local view
-Add a draw/modal handler and be able to ray cast in each of the areas

What do we think, is it possible or should I just stick with doing it on each object at a time

-Patrick

Option B (as in meshlab) would be great!

That’s what I’m trying to accomplish, however my searching of the API and ops, I haven’t been able to swing it. I may have to settle for doing each object one at a time.

Split 3d view and set localview:

import bpy

window = bpy.context.window
screen = bpy.context.screen
scene = bpy.context.scene

ob_1 = scene.objects[0]
ob_2 = scene.objects[1]

for ob in scene.objects:
    ob.select = False
scene.objects.active = None

for area in screen.areas:
    if area.type == "VIEW_3D":
        break
else:
    raise Exception("No 3D View!")

areas = [area.as_pointer() for area in screen.areas]

override = bpy.context.copy()
override['area'] = area
bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.5, mouse_x=-100, mouse_y=-100)
scene.objects.active = ob_1
ob_1.select = True
bpy.ops.view3d.localview(override)

for area in screen.areas:
    if area.as_pointer() not in areas:
        override = {
            'window': window,
            'screen': screen,
            'area': area,
            'scene': scene
        }
        scene.objects.active = ob_2
        ob_2.select = True
        ob_1.select = False
        bpy.ops.view3d.localview(override)
        break
else:
    print("Splitting failed?!")

Screen.area_split

Thanks!!
Dang, hadn’t found that!! I’ve been using override context for the 3dview maximizing. Should have some neat code tomorrow!

Well, I ran into a hang up, having an area maximized via this function

bpy.ops.screen.screen_full_area(override)

causes that area not be “splitable” in the ui, and thereby this fails

bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.5, mouse_x=-100, mouse_y=-100)

My planned work around is to do area_dupli insead of screen_full_area.

You code works perfectly

1 Like

I’m running into a hangup with the view splitting.

In my operator, immediately before the large code block below, I call this line. This works and brings up a new window, with a single VIEW_3D area.

bpy.ops.screen.area_dupli('INVOKE_DEFAULT') 

If I duplicate the area manually, and then run partial code from my operator in the Blender text editor…It works. The other window (not active) is split successfully by overriding context for the area_split operator.

However, when these things happen sequentially within my operator, the area_split() function returns ‘CANCELLED’


import bpy
context = bpy.context


#in this case, I have duplicated the 3dview area
#into a new window.
for window in context.window_manager.windows: 
    if len(window.screen.areas) == 1 and window.screen.areas[0].type == 'VIEW_3D':
        screen = window.screen  
        for area in screen.areas:
            if area.type == 'VIEW_3D':
                break
        break
               
override = context.copy()
override['window'] = window
override['screen'] = screen
override['area'] = area
        
print('reality check %s, %i' % (area.type, window.width))     
ret = bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.5, mouse_x=-100, mouse_y=-100)
print(ret)

1 Like

Also, for some reason it takes both objects into local view in the 2nd area, no matter what I do, both objects are in one of the local views.

I managed to get a single object per view 3d in localview by setting the scene.objects.active property and by (de-)selecting objects (it’s already in the code i posted). Context overriding did not work, the changes have to happen to the actual scene / objects.

causes that area not be “splitable” in the ui, and thereby this fails

Well, the feature is to maximize one area, so you can’t have two / split the maximized. The info header is the only exception, it stays.

However, when these things happen sequentially within my operator, the area_split() function returns ‘CANCELLED’

Expect timing problems and crashes when dealing with areas and windows. Joining areas with python crashes for instance if there’s not a delay of at least 0.2 seconds, and there’s some weird behavior still (joined area stays visible and has some drawing artefacts at the corners, there needs to be a screen change to force an update).

I used the code you posted, however for some reason, in my test file, it would always take 2 objects in. I deleted those two objects and added 2 new ones and it worked fine. Wastes a LOT of time on that mystery. STill can’t figure out why one of the would hang around in one of the local views.

Re: Area Joining
I read the other thread you had commented on about that. I’ll probably just make the user deal with that.

Solved!!

This was quite a learning experience! I still have a lot of work to do but I have a basic working code now.

drawing, navigating and ray casting in multiple spaces!

I just saw the video now, You did AMAZING job here. Its much much better than Meshlab! Are you going to implement objects volume & dimensions analysis / comparison? It would be very useful feature, at least for dental superimposition…

Thanks! I wouldn’t say better than meshlab since I modelled it after it :slight_smile: I do plan to use this for dental alignment. I am working on a “minimum bounding box” code to fit models into the smallest possible box which can help for alignment as well as milling nesting.