3

I tried to do the same thing as an existing answer but Under Object -> Set Origin. I mean, the Set Origin currently shows 5 elements. How can I append First Menu at the bottom of it so that the Set Origin would have 6 elements?

import bpy

class MyCustomMenu(bpy.types.Menu): bl_label = "First Menu" bl_idname = "OBJECT_MT_custom_menu"

def draw(self, context):
    layout = self.layout
    layout.label(text="Hello First Menu!", icon='WORLD_DATA')

def draw_menu(self, context): self.layout.menu(MyCustomMenu.bl_idname)

def register(): bpy.utils.register_class(MyCustomMenu) #bpy.types.VIEW3D_MT_curve_add.append(draw_menu) bpy.ops.object.origin_set.append(draw_menu) #Does not work.

def unregister(): bpy.types.VIEW3D_MT_curve_add.remove(draw_menu) bpy.utils.unregister_class(MyCustomMenu)

if name == "main": register()

brockmann
  • 12,613
  • 4
  • 50
  • 93
Damn Vegetables
  • 825
  • 6
  • 18
  • 2
    It is not a menu you can append to using method shown in linked answer. It is a menu created from the enum items available for type property of origin set operator. layout.operator_menu_enum("object.origin_set", "type") – batFINGER Jun 10 '20 at 08:54
  • @batFINGER So, it is not possible to add a menu item under "Set Origin" using add-on? – Damn Vegetables Jun 10 '20 at 09:04
  • 1
    Not impossible, would need to overwrite (rewrite) set origin operator, or blenders UI code, both options I would not recommend. (Altering UI code is IMO a very slippery slope to go down) Writing a new operator with same bl_idname is a lesser of two evils. Low level versions of most options for origin type have been used as answers here. Do you want to go down this road? – batFINGER Jun 10 '20 at 09:19
  • batFINGER is right, it's the only item of that menu which you can not append to, see the source code: https://i.stack.imgur.com/pnJrb.png – brockmann Jun 10 '20 at 09:21
  • @batFINGER. I am not familiar with Python or Blender add-on. What is the least hacky way for doing it with an add-on? If adding a submenu below "Set Origin" is a difficult one with no clean way, I could just add the item at the bottom of the "Object" menu. Sure, having a menu for setting a custom origin at the bottom of the Object menu is not as well-organised or convenient as having that in the "Set Origin" submenu, but if Blender has been designed that way... In case that it is not that hacky, please show me an example to add a menu there by creating a new operator with the same name. – Damn Vegetables Jun 10 '20 at 09:35
  • 1
    Just replace VIEW3D_MT_curve_add menu type with VIEW3D_MT_object, done. – brockmann Jun 10 '20 at 10:04

1 Answers1

7

Adding a new op and / or overriding the old.

It is not a menu you can append to using method shown in linked answer. It is a menu created from the enum items available for type property of origin set operator.

layout.operator_menu_enum("object.origin_set", "type")

Not impossible, would need to overwrite (rewrite) set origin operator, or blenders UI code, both options I would not recommend. (Altering UI code is IMO a very slippery slope to go down) Writing a new operator with same bl_idname is a lesser of two evils. Low level versions of most options for origin type have been used as answers here. Do you want to go down this road?

In case that it is not that hacky, please show me an example to add a menu there by creating a new operator with the same name

Ok let's go down that road. Overriding an operator is as simple as registering a new one with the same bl_idname

enter image description here Ran the code first with bl_idname = "object.simple_operator" and the next time with origin set. Simple is prepended atop menu, the latter replaces the enums of original in menu

The example below uses the simple operator template. The options for the type property of the original are used to build the items of the new.

Have only added code to change origin for bottom center (using code from https://blender.stackexchange.com/a/42110/15543 )

NOTE: test code below overrides the origin set operator. Will most likely need to restart blender to get the old one back.

import bpy
from bpy.props import EnumProperty
from mathutils import Vector, Matrix

def origin_to_bottom(ob, matrix=Matrix()): me = ob.data mw = ob.matrix_world local_verts = [matrix @ Vector(v[:]) for v in ob.bound_box] o = sum(local_verts, Vector()) / 8 o.z = min(v.z for v in local_verts) o = matrix.inverted() @ o me.transform(Matrix.Translation(-o))

mw.translation = mw @ o

def main(context, origin_type): ob = context.object if origin_type == 'BOTTOM_CENTER': origin_to_bottom(ob) else: print(f"Add code for {origin_type}")

class SimpleOperator(bpy.types.Operator): """Tooltip""" #bl_idname = "object.simple_operator" bl_idname = "object.origin_set" # override the old one bl_label = "Simple Object Operator"

def items():
    items = []
    rna = bpy.ops.object.origin_set.get_rna_type()
    for i in rna.properties['type'].enum_items:
        items.append((i.identifier, i.name, i.description))
    items.append(('BOTTOM_CENTER', "Bottom Center", "Set origin to Bottom Center"))
    return items

type : EnumProperty(
    items=items(),
    default=rna.properties['type'].default)

@classmethod
def poll(cls, context):
    return context.active_object is not None

def execute(self, context):
    main(context, self.type)
    return {'FINISHED'}

def draw_menu(self, context): self.layout.operator_menu_enum("object.simple_operator", "type")

def register(): #bpy.types.VIEW3D_MT_object.prepend(draw_menu) bpy.utils.register_class(SimpleOperator)

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

if name == "main": register()

Prepend another or overwrite the old?

Leaving the choice up to you. Not currently aware of a way to copy the execute method of a built in operator hence will need to rewrite each of the other origin types. Some are covered in the links below.

My suggestion would be to not override, instead make a new operator that uses the bounding box as a coordinate system. The origin (arbitrarily the) front bottom left corner and all other corners scaled such that opposite corner to origin is (1, 1, 1). In this case bottom center would be (0.5, 0.5, 0)

The user could be given the option of choosing from predefined list (that sets the offset) or a custom option with popup to set the offset themselves. eg origin a third along bottom front edge of bbox set offset to (1/ 3, 0, 0)

Related

How to compute the centroid of a mesh with triangular faces without using Blender's built-in functions?

Get center of geometry of an object

https://blender.stackexchange.com/questions/161823/origins-to-the-down-of-the-object-by-default/163258?r=SearchResults&s=6|8.6222#163258

Setting mesh's origin in python (2.8)

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • There is a problem. After running the script, only the newly added "bottom centre" works and existing methods like "Origin to 3D cursor" do not work any more. – Damn Vegetables Jun 21 '20 at 17:45
  • Please read the answer fully. "Have only added code to change origin for bottom center" in way of example of how to append to that menu, – batFINGER Jun 22 '20 at 05:16