Skip to content
Snippets Groups Projects
Commit b7f883ed authored by Mikhail Rachinskiy's avatar Mikhail Rachinskiy
Browse files

BoolTools: Add preference to choose boolean solver

Add preference to choose boolean solver.
Also refactor preferences UI so humans could actually read it.
parent 4744a96b
No related branches found
No related tags found
No related merge requests found
...@@ -21,14 +21,13 @@ ...@@ -21,14 +21,13 @@
bl_info = { bl_info = {
"name": "Bool Tool", "name": "Bool Tool",
"author": "Vitor Balbio, Mikhail Rachinskiy, TynkaTopi, Meta-Androcto", "author": "Vitor Balbio, Mikhail Rachinskiy, TynkaTopi, Meta-Androcto",
"version": (0, 3, 3), "version": (0, 3, 4),
"blender": (2, 77, 0), "blender": (2, 78, 0),
"location": "View3D > Toolshelf > BoolTool", "location": "View3D > Toolshelf > BoolTool",
"description": "Bool Tools Hotkey: Ctrl Shift B", "description": "Bool Tools Hotkey: Ctrl Shift B",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Object/BoolTool", "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/", "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Object", "category": "Object"}
}
import bpy import bpy
from bpy.app.handlers import persistent from bpy.app.handlers import persistent
...@@ -614,8 +613,13 @@ class BTool_Slice(Operator): ...@@ -614,8 +613,13 @@ class BTool_Slice(Operator):
Operation(context, "SLICE") Operation(context, "SLICE")
return {'FINISHED'} 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): def mesh_selection(ob, select_action):
context = bpy.context context = bpy.context
...@@ -624,94 +628,120 @@ def mesh_selection(ob, select_action): ...@@ -624,94 +628,120 @@ def mesh_selection(ob, select_action):
ops_me = bpy.ops.mesh ops_me = bpy.ops.mesh
ops_ob = bpy.ops.object ops_ob = bpy.ops.object
scene.objects.active = ob def mesh_cleanup():
ops_ob.mode_set(mode="EDIT") ops_me.select_all(action='SELECT')
ops_me.select_all(action=select_action) ops_me.delete_loose()
ops_ob.mode_set(mode="OBJECT") ops_me.select_all(action='SELECT')
scene.objects.active = obj 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')
def modifier_boolean(obj, ob, mode, delete_not=False): mesh_cleanup()
md = obj.modifiers.new("BoolTool Direct", 'BOOLEAN') ops_me.select_all(action=select_action)
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)
ops_ob.mode_set(mode='OBJECT')
scene.objects.active = obj
def boolean_each(mode): def get_objects(context):
context = bpy.context
obj = context.active_object obj = context.active_object
prepare_objects()
obj.select = False obj.select = False
obs = context.selected_objects ob = context.selected_objects[0]
mesh_selection(obj, 'DESELECT') mesh_selection(obj, 'DESELECT')
for ob in obs:
mesh_selection(ob, 'SELECT') mesh_selection(ob, 'SELECT')
modifier_boolean(obj, ob, mode)
obj.select = True
return obj, ob
class DirectBooleans:
bl_options = {'REGISTER', 'UNDO'}
def objects_get(): 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 context = bpy.context
obj = context.active_object obj = context.active_object
prepare_objects()
obj.select = False obj.select = False
ob = context.selected_objects[0] obs = context.selected_objects
mesh_selection(obj, 'DESELECT') mesh_selection(obj, 'DESELECT')
for ob in obs:
mesh_selection(ob, 'SELECT') mesh_selection(ob, 'SELECT')
self.modifier_boolean(obj, ob, mode)
obj.select = True
return obj, ob 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
# Booltron Direct Operators --------------------------------------------------- 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""" """Combine selected objects"""
bl_idname = "btool.direct_union" bl_idname = "btool.direct_union"
bl_label = "Union" bl_label = "Union"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
boolean_each('UNION') self.boolean_each('UNION')
return {'FINISHED'} return {'FINISHED'}
class Direct_Difference(Operator): class Direct_Difference(DirectBooleans, Operator):
"""Subtract selected objects from active object""" """Subtract selected objects from active object"""
bl_idname = "btool.direct_difference" bl_idname = "btool.direct_difference"
bl_label = "Difference" bl_label = "Difference"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
boolean_each('DIFFERENCE') self.boolean_each('DIFFERENCE')
return {'FINISHED'} return {'FINISHED'}
class Direct_Intersect(Operator): class Direct_Intersect(DirectBooleans, Operator):
"""Keep only intersecting geometry""" """Keep only intersecting geometry"""
bl_idname = "btool.direct_intersect" bl_idname = "btool.direct_intersect"
bl_label = "Intersect" bl_label = "Intersect"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context): def execute(self, context):
boolean_each('INTERSECT') self.boolean_each('INTERSECT')
return {'FINISHED'} 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)""" """Slice active object along the selected object (can handle only two objects at a time)"""
bl_idname = "btool.direct_slice" bl_idname = "btool.direct_slice"
bl_label = "Slice" bl_label = "Slice"
bl_options = {'REGISTER', 'UNDO'}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
...@@ -719,7 +749,7 @@ class Direct_Slice(Operator): ...@@ -719,7 +749,7 @@ class Direct_Slice(Operator):
def execute(self, context): def execute(self, context):
scene = context.scene scene = context.scene
obj, ob = objects_get() obj, ob = get_objects(context)
def object_duplicate(ob): def object_duplicate(ob):
ops_ob = bpy.ops.object ops_ob = bpy.ops.object
...@@ -730,28 +760,28 @@ class Direct_Slice(Operator): ...@@ -730,28 +760,28 @@ class Direct_Slice(Operator):
return context.selected_objects[0] return context.selected_objects[0]
obj_copy = object_duplicate(obj) 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 scene.objects.active = obj_copy
modifier_boolean(obj_copy, ob, 'INTERSECT') self.modifier_boolean(obj_copy, ob, 'INTERSECT')
return {'FINISHED'} return {'FINISHED'}
class Direct_Subtract(Operator): class Direct_Subtract(DirectBooleans, Operator):
"""Subtract selected object from active object, """ \ """Subtract selected object from active object, """ \
"""subtracted object not removed (can handle only two objects at a time))""" """subtracted object not removed (can handle only two objects at a time))"""
bl_idname = "btool.direct_subtract" bl_idname = "btool.direct_subtract"
bl_label = "Subtract" bl_label = "Subtract"
bl_options = {'REGISTER', 'UNDO'}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return len(context.selected_objects) == 2 return len(context.selected_objects) == 2
def execute(self, context): def execute(self, context):
obj, ob = objects_get() obj, ob = get_objects(context)
modifier_boolean(obj, ob, 'DIFFERENCE', delete_not=True) self.modifier_boolean(obj, ob, 'DIFFERENCE', terminate=False)
return {'FINISHED'} return {'FINISHED'}
# Utils Class --------------------------------------------------------------- # Utils Class ---------------------------------------------------------------
# Find the Brush Selected in Three View # Find the Brush Selected in Three View
...@@ -1190,24 +1220,22 @@ class BoolTool_Pref(bpy.types.AddonPreferences): ...@@ -1190,24 +1220,22 @@ class BoolTool_Pref(bpy.types.AddonPreferences):
default=False, default=False,
update=UpdateBoolTool_Pref, update=UpdateBoolTool_Pref,
description=("Replace the Transform HotKeys (G,R,S) " 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( make_vertex_groups = bpy.props.BoolProperty(
name="Make Vertex Groups", name="Make Vertex Groups",
default=False, default=False,
description="When Apply a Brush to de Object it will create a new vertex group of the new faces" description="When Apply a Brush to de Object it will create a new vertex group of the new faces")
)
make_boundary = bpy.props.BoolProperty( make_boundary = bpy.props.BoolProperty(
name="Make Boundary", name="Make Boundary",
default=False, default=False,
description="When Apply a Brush to de Object it will create a new vertex group of the bondary boolean area" 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( use_wire = bpy.props.BoolProperty(
name="Use Bmesh", name="Use Bmesh",
default=False, default=False,
description="Use The Wireframe Instead Of Boolean" description="Use The Wireframe Instead Of Boolean")
)
category = bpy.props.StringProperty( category = bpy.props.StringProperty(
name="Tab Category", name="Tab Category",
...@@ -1215,43 +1243,74 @@ class BoolTool_Pref(bpy.types.AddonPreferences): ...@@ -1215,43 +1243,74 @@ class BoolTool_Pref(bpy.types.AddonPreferences):
default="Bool Tools", default="Bool Tools",
update=update_panel) update=update_panel)
def draw(self, context): 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 layout = self.layout
row = layout.row() split_percent = 0.15
col = row.column()
col.label(text="Category:") split = layout.split(percentage=split_percent)
col.prop(self, "category", text="") col_1 = split.column()
layout.separator() col_2 = split.column()
layout = self.layout col_1.label(text="Category:")
layout.label("Experimental Features:") col_2.prop(self, "category", text="")
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('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 # EXPERIMENTAL
layout.prop(self, "make_vertex_groups") col_2.prop(self, "make_vertex_groups")
layout.prop(self, "make_boundary") col_2.prop(self, "make_boundary")
""" """
layout = self.layout
layout.separator() split = layout.split(percentage=split_percent)
layout.label("Hotkey List:") col_1 = split.column()
layout.separator() col_2 = split.column()
layout.label("Menu: 'B', 'PRESS', ctrl=True, shift=True") col_1.label("Hotkey List:")
layout.label("Brush Operators:") col_2.label("Menu: Ctrl Shift B")
layout.label("Union: 'NUMPAD_PLUS', 'PRESS', ctrl=True")
layout.label("Diff: 'NUMPAD_MINUS', 'PRESS', ctrl=True") split = layout.split(percentage=split_percent)
layout.label("Intersect: 'NUMPAD_ASTERIX', 'PRESS', ctrl=True") col_1 = split.column()
layout.label("Slice: 'NUMPAD_SLASH', 'PRESS', ctrl=True") col_2 = split.column()
layout.label("Direct Operators:") col_1.label("Brush Operators:")
layout.label("Direct_Union: 'NUMPAD_PLUS', 'PRESS', ctrl=True, shift=True") col_2.label("Union: Ctrl Num +")
layout.label("Direct_Difference: 'NUMPAD_MINUS', 'PRESS', ctrl=True, shift=True") col_2.label("Diff: Ctrl Num -")
layout.label("Direct_Intersect: 'NUMPAD_ASTERIX', 'PRESS', ctrl=True, shift=True") col_2.label("Intersect: Ctrl Num *")
layout.label("Direct_Slice: 'NUMPAD_SLASH', 'PRESS', ctrl=True, shift=True") col_2.label("Slice: Ctrl Num /")
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("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 ------------------------------------------------ # ------------------- Class List ------------------------------------------------
classes = ( classes = (
BoolTool_Pref,
# Booltron # Booltron
Direct_Union, Direct_Union,
Direct_Difference, Direct_Difference,
...@@ -1277,7 +1336,6 @@ classes = ( ...@@ -1277,7 +1336,6 @@ classes = (
BoolTool_Config, BoolTool_Config,
BoolTool_BViwer, BoolTool_BViwer,
BTool_FastTransform, BTool_FastTransform,
BoolTool_Pref,
) )
# ------------------- REGISTER ------------------------------------------------ # ------------------- REGISTER ------------------------------------------------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment