BoolTools: Add preference to choose boolean solver
Add preference to choose boolean solver. Also refactor preferences UI so humans could actually read it.
This commit is contained in:
parent
4744a96bea
commit
b7f883ed69
|
@ -21,21 +21,20 @@
|
|||
bl_info = {
|
||||
"name": "Bool Tool",
|
||||
"author": "Vitor Balbio, Mikhail Rachinskiy, TynkaTopi, Meta-Androcto",
|
||||
"version": (0, 3, 3),
|
||||
"blender": (2, 77, 0),
|
||||
"version": (0, 3, 4),
|
||||
"blender": (2, 78, 0),
|
||||
"location": "View3D > Toolshelf > BoolTool",
|
||||
"description": "Bool Tools Hotkey: Ctrl Shift B",
|
||||
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Object/BoolTool",
|
||||
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
|
||||
"category": "Object",
|
||||
}
|
||||
"category": "Object"}
|
||||
|
||||
import bpy
|
||||
from bpy.app.handlers import persistent
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
Panel,
|
||||
)
|
||||
Operator,
|
||||
Panel,
|
||||
)
|
||||
|
||||
|
||||
# ------------------- Bool Tool FUNCTIONS------------------------------
|
||||
|
@ -614,8 +613,13 @@ class BTool_Slice(Operator):
|
|||
Operation(context, "SLICE")
|
||||
return {'FINISHED'}
|
||||
|
||||
# Booltron Direct FUNCTIONS ---------------------------------------------------
|
||||
|
||||
# Booltron operators for direct booleans ---------------------------------------------------
|
||||
|
||||
|
||||
def prepare_objects():
|
||||
bpy.ops.object.make_single_user(object=True, obdata=True)
|
||||
bpy.ops.object.convert(target='MESH')
|
||||
|
||||
def mesh_selection(ob, select_action):
|
||||
context = bpy.context
|
||||
|
@ -624,44 +628,27 @@ def mesh_selection(ob, select_action):
|
|||
ops_me = bpy.ops.mesh
|
||||
ops_ob = bpy.ops.object
|
||||
|
||||
def mesh_cleanup():
|
||||
ops_me.select_all(action='SELECT')
|
||||
ops_me.delete_loose()
|
||||
ops_me.select_all(action='SELECT')
|
||||
ops_me.remove_doubles(threshold=0.0001)
|
||||
ops_me.fill_holes(sides=0)
|
||||
ops_me.normals_make_consistent()
|
||||
|
||||
scene.objects.active = ob
|
||||
ops_ob.mode_set(mode="EDIT")
|
||||
ops_ob.mode_set(mode='EDIT')
|
||||
|
||||
mesh_cleanup()
|
||||
ops_me.select_all(action=select_action)
|
||||
ops_ob.mode_set(mode="OBJECT")
|
||||
|
||||
ops_ob.mode_set(mode='OBJECT')
|
||||
scene.objects.active = obj
|
||||
|
||||
|
||||
def modifier_boolean(obj, ob, mode, delete_not=False):
|
||||
md = obj.modifiers.new("BoolTool Direct", 'BOOLEAN')
|
||||
md.show_viewport = False
|
||||
md.show_render = False
|
||||
md.operation = mode
|
||||
md.object = ob
|
||||
|
||||
bpy.ops.object.modifier_apply(modifier="BoolTool Direct")
|
||||
if delete_not is True:
|
||||
return
|
||||
bpy.context.scene.objects.unlink(ob)
|
||||
bpy.data.objects.remove(ob)
|
||||
|
||||
|
||||
def boolean_each(mode):
|
||||
context = bpy.context
|
||||
def get_objects(context):
|
||||
obj = context.active_object
|
||||
|
||||
obj.select = False
|
||||
obs = context.selected_objects
|
||||
|
||||
mesh_selection(obj, 'DESELECT')
|
||||
for ob in obs:
|
||||
mesh_selection(ob, 'SELECT')
|
||||
modifier_boolean(obj, ob, mode)
|
||||
obj.select = True
|
||||
|
||||
|
||||
def objects_get():
|
||||
context = bpy.context
|
||||
obj = context.active_object
|
||||
prepare_objects()
|
||||
|
||||
obj.select = False
|
||||
ob = context.selected_objects[0]
|
||||
|
@ -671,47 +658,90 @@ def objects_get():
|
|||
|
||||
return obj, ob
|
||||
|
||||
# Booltron Direct Operators ---------------------------------------------------
|
||||
|
||||
class DirectBooleans:
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
solver = bpy.props.EnumProperty(
|
||||
name='Boolean Solver',
|
||||
items=(
|
||||
('DEFAULT', 'Default', ''),
|
||||
('BMESH', 'BMesh', ''),
|
||||
('CARVE', 'Carve', ''),
|
||||
),
|
||||
default='DEFAULT',
|
||||
description='Specify solver for boolean operations',
|
||||
options={'SKIP_SAVE'})
|
||||
|
||||
def boolean_each(self, mode):
|
||||
context = bpy.context
|
||||
obj = context.active_object
|
||||
|
||||
prepare_objects()
|
||||
|
||||
obj.select = False
|
||||
obs = context.selected_objects
|
||||
|
||||
mesh_selection(obj, 'DESELECT')
|
||||
for ob in obs:
|
||||
mesh_selection(ob, 'SELECT')
|
||||
self.modifier_boolean(obj, ob, mode)
|
||||
obj.select = True
|
||||
|
||||
def modifier_boolean(self, obj, ob, mode, terminate=True):
|
||||
if self.solver == 'DEFAULT':
|
||||
solver = bpy.context.user_preferences.addons[__name__].preferences.solver
|
||||
else:
|
||||
solver = self.solver
|
||||
|
||||
md = obj.modifiers.new('Immediate apply', 'BOOLEAN')
|
||||
md.show_viewport = False
|
||||
md.show_render = False
|
||||
md.operation = mode
|
||||
md.solver = solver
|
||||
md.object = ob
|
||||
|
||||
bpy.ops.object.modifier_apply(modifier='Immediate apply')
|
||||
if not terminate:
|
||||
return
|
||||
bpy.context.scene.objects.unlink(ob)
|
||||
bpy.data.objects.remove(ob)
|
||||
|
||||
|
||||
class Direct_Union(Operator):
|
||||
class Direct_Union(DirectBooleans, Operator):
|
||||
"""Combine selected objects"""
|
||||
bl_idname = "btool.direct_union"
|
||||
bl_label = "Union"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
boolean_each('UNION')
|
||||
self.boolean_each('UNION')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Direct_Difference(Operator):
|
||||
class Direct_Difference(DirectBooleans, Operator):
|
||||
"""Subtract selected objects from active object"""
|
||||
bl_idname = "btool.direct_difference"
|
||||
bl_label = "Difference"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
boolean_each('DIFFERENCE')
|
||||
self.boolean_each('DIFFERENCE')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Direct_Intersect(Operator):
|
||||
class Direct_Intersect(DirectBooleans, Operator):
|
||||
"""Keep only intersecting geometry"""
|
||||
bl_idname = "btool.direct_intersect"
|
||||
bl_label = "Intersect"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
boolean_each('INTERSECT')
|
||||
self.boolean_each('INTERSECT')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Direct_Slice(Operator):
|
||||
class Direct_Slice(DirectBooleans, Operator):
|
||||
"""Slice active object along the selected object (can handle only two objects at a time)"""
|
||||
bl_idname = "btool.direct_slice"
|
||||
bl_label = "Slice"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -719,7 +749,7 @@ class Direct_Slice(Operator):
|
|||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
obj, ob = objects_get()
|
||||
obj, ob = get_objects(context)
|
||||
|
||||
def object_duplicate(ob):
|
||||
ops_ob = bpy.ops.object
|
||||
|
@ -730,28 +760,28 @@ class Direct_Slice(Operator):
|
|||
return context.selected_objects[0]
|
||||
|
||||
obj_copy = object_duplicate(obj)
|
||||
modifier_boolean(obj, ob, 'DIFFERENCE', delete_not=True)
|
||||
self.modifier_boolean(obj, ob, 'DIFFERENCE', terminate=False)
|
||||
scene.objects.active = obj_copy
|
||||
modifier_boolean(obj_copy, ob, 'INTERSECT')
|
||||
self.modifier_boolean(obj_copy, ob, 'INTERSECT')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Direct_Subtract(Operator):
|
||||
class Direct_Subtract(DirectBooleans, Operator):
|
||||
"""Subtract selected object from active object, """ \
|
||||
"""subtracted object not removed (can handle only two objects at a time))"""
|
||||
bl_idname = "btool.direct_subtract"
|
||||
bl_label = "Subtract"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.selected_objects) == 2
|
||||
|
||||
def execute(self, context):
|
||||
obj, ob = objects_get()
|
||||
modifier_boolean(obj, ob, 'DIFFERENCE', delete_not=True)
|
||||
obj, ob = get_objects(context)
|
||||
self.modifier_boolean(obj, ob, 'DIFFERENCE', terminate=False)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Utils Class ---------------------------------------------------------------
|
||||
|
||||
# Find the Brush Selected in Three View
|
||||
|
@ -1190,68 +1220,97 @@ class BoolTool_Pref(bpy.types.AddonPreferences):
|
|||
default=False,
|
||||
update=UpdateBoolTool_Pref,
|
||||
description=("Replace the Transform HotKeys (G,R,S) "
|
||||
"for a custom version that can optimize the visualization of Brushes")
|
||||
)
|
||||
"for a custom version that can optimize the visualization of Brushes"))
|
||||
|
||||
make_vertex_groups = bpy.props.BoolProperty(
|
||||
name="Make Vertex Groups",
|
||||
default=False,
|
||||
description="When Apply a Brush to de Object it will create a new vertex group of the new faces"
|
||||
)
|
||||
name="Make Vertex Groups",
|
||||
default=False,
|
||||
description="When Apply a Brush to de Object it will create a new vertex group of the new faces")
|
||||
|
||||
make_boundary = bpy.props.BoolProperty(
|
||||
name="Make Boundary",
|
||||
default=False,
|
||||
description="When Apply a Brush to de Object it will create a new vertex group of the bondary boolean area"
|
||||
)
|
||||
name="Make Boundary",
|
||||
default=False,
|
||||
description="When Apply a Brush to de Object it will create a new vertex group of the bondary boolean area")
|
||||
|
||||
use_wire = bpy.props.BoolProperty(
|
||||
name="Use Bmesh",
|
||||
default=False,
|
||||
description="Use The Wireframe Instead Of Boolean"
|
||||
)
|
||||
name="Use Bmesh",
|
||||
default=False,
|
||||
description="Use The Wireframe Instead Of Boolean")
|
||||
|
||||
category = bpy.props.StringProperty(
|
||||
name="Tab Category",
|
||||
description="Choose a name for the category of the panel",
|
||||
default="Bool Tools",
|
||||
update=update_panel)
|
||||
name="Tab Category",
|
||||
description="Choose a name for the category of the panel",
|
||||
default="Bool Tools",
|
||||
update=update_panel)
|
||||
|
||||
solver = bpy.props.EnumProperty(
|
||||
name='Boolean Solver',
|
||||
items=(
|
||||
('BMESH', 'BMesh', ''),
|
||||
('CARVE', 'Carve', ''),
|
||||
),
|
||||
default='BMESH',
|
||||
description='Specify solver for boolean operations')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
split_percent = 0.15
|
||||
|
||||
layout = self.layout
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.label(text="Category:")
|
||||
col.prop(self, "category", text="")
|
||||
layout.separator()
|
||||
layout = self.layout
|
||||
layout.label("Experimental Features:")
|
||||
layout.prop(self, "fast_transform")
|
||||
layout.prop(self, "use_wire", text="Use Wire Instead Of Bbox")
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label(text="Category:")
|
||||
col_2.prop(self, "category", text="")
|
||||
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label('Boolean Solver:')
|
||||
col_2.prop(self, 'solver', text='')
|
||||
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label("Experimental Features:")
|
||||
col_2.prop(self, "fast_transform")
|
||||
col_2.prop(self, "use_wire", text="Use Wire Instead Of Bbox")
|
||||
"""
|
||||
# EXPERIMENTAL
|
||||
layout.prop(self, "make_vertex_groups")
|
||||
layout.prop(self, "make_boundary")
|
||||
col_2.prop(self, "make_vertex_groups")
|
||||
col_2.prop(self, "make_boundary")
|
||||
"""
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.label("Hotkey List:")
|
||||
layout.separator()
|
||||
layout.label("Menu: 'B', 'PRESS', ctrl=True, shift=True")
|
||||
layout.label("Brush Operators:")
|
||||
layout.label("Union: 'NUMPAD_PLUS', 'PRESS', ctrl=True")
|
||||
layout.label("Diff: 'NUMPAD_MINUS', 'PRESS', ctrl=True")
|
||||
layout.label("Intersect: 'NUMPAD_ASTERIX', 'PRESS', ctrl=True")
|
||||
layout.label("Slice: 'NUMPAD_SLASH', 'PRESS', ctrl=True")
|
||||
layout.label("Direct Operators:")
|
||||
layout.label("Direct_Union: 'NUMPAD_PLUS', 'PRESS', ctrl=True, shift=True")
|
||||
layout.label("Direct_Difference: 'NUMPAD_MINUS', 'PRESS', ctrl=True, shift=True")
|
||||
layout.label("Direct_Intersect: 'NUMPAD_ASTERIX', 'PRESS', ctrl=True, shift=True")
|
||||
layout.label("Direct_Slice: 'NUMPAD_SLASH', 'PRESS', ctrl=True, shift=True")
|
||||
layout.label("BTool_BrushToMesh: 'NUMPAD_ENTER', 'PRESS', ctrl=True")
|
||||
layout.label("BTool_AllBrushToMesh: 'NUMPAD_ENTER', 'PRESS', ctrl=True, shift=True")
|
||||
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label("Hotkey List:")
|
||||
col_2.label("Menu: Ctrl Shift B")
|
||||
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label("Brush Operators:")
|
||||
col_2.label("Union: Ctrl Num +")
|
||||
col_2.label("Diff: Ctrl Num -")
|
||||
col_2.label("Intersect: Ctrl Num *")
|
||||
col_2.label("Slice: Ctrl Num /")
|
||||
|
||||
split = layout.split(percentage=split_percent)
|
||||
col_1 = split.column()
|
||||
col_2 = split.column()
|
||||
col_1.label("Direct Operators:")
|
||||
col_2.label("Direct Union: Ctrl Shift Num +")
|
||||
col_2.label("Direct Difference: Ctrl Shift Num -")
|
||||
col_2.label("Direct Intersect: Ctrl Shift Num *")
|
||||
col_2.label("Direct Slice: Ctrl Shift Num /")
|
||||
col_2.label("BTool Brush To Mesh: Ctrl Num Enter")
|
||||
col_2.label("BTool All Brush To Mesh: Ctrl Shift Num Enter")
|
||||
|
||||
|
||||
# ------------------- Class List ------------------------------------------------
|
||||
|
||||
classes = (
|
||||
BoolTool_Pref,
|
||||
# Booltron
|
||||
Direct_Union,
|
||||
Direct_Difference,
|
||||
|
@ -1277,8 +1336,7 @@ classes = (
|
|||
BoolTool_Config,
|
||||
BoolTool_BViwer,
|
||||
BTool_FastTransform,
|
||||
BoolTool_Pref,
|
||||
)
|
||||
)
|
||||
|
||||
# ------------------- REGISTER ------------------------------------------------
|
||||
addon_keymaps = []
|
||||
|
|
Loading…
Reference in New Issue