diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-07-04 12:48:33 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-07-04 12:48:33 +0400 |
commit | 470cb9590535a92561ebf92f9ae50bb626f9e990 (patch) | |
tree | 7a03ba6520304f1d880e295a812a748d36d2e48b /object_fracture_cell | |
parent | 846e736aa0b6eb2e06820567ee36a448e06e35cd (diff) |
rename addon
Diffstat (limited to 'object_fracture_cell')
-rw-r--r-- | object_fracture_cell/__init__.py | 396 | ||||
-rw-r--r-- | object_fracture_cell/fracture_cell_calc.py | 95 | ||||
-rw-r--r-- | object_fracture_cell/fracture_cell_setup.py | 371 |
3 files changed, 862 insertions, 0 deletions
diff --git a/object_fracture_cell/__init__.py b/object_fracture_cell/__init__.py new file mode 100644 index 00000000..d284e205 --- /dev/null +++ b/object_fracture_cell/__init__.py @@ -0,0 +1,396 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +bl_info = { + "name": "Cell Fracture", + "author": "ideasman42", + "version": (0, 1), + "blender": (2, 6, 4), + "location": "Search > Fracture Object & Add -> Fracture Helper Objects", + "description": "Fractured Object, Bomb, Projectile, Recorder", + "warning": "", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\ + "Scripts/Object/Fracture", + "tracker_url": "https://projects.blender.org/tracker/index.php?"\ + "func=detail&aid=21793", + "category": "Object"} + + +#if "bpy" in locals(): +# import imp +# imp.reload(fracture_cell_setup) + +import bpy +from bpy.props import (StringProperty, + BoolProperty, + IntProperty, + FloatProperty, + EnumProperty) + +from bpy.types import Operator + +def main_object(scene, obj, level, **kw): + import random + + # pull out some args + kw_copy = kw.copy() + use_recenter = kw_copy.pop("use_recenter") + use_remove_original = kw_copy.pop("use_remove_original") + recursion = kw_copy.pop("recursion") + recursion_chance = kw_copy.pop("recursion_chance") + recursion_chance_select = kw_copy.pop("recursion_chance_select") + use_layer_next = kw_copy.pop("use_layer_next") + group_name = kw_copy.pop("group_name") + use_island_split = kw_copy.pop("use_island_split") + + from . import fracture_cell_setup + + # not essential but selection is visual distraction. + obj.select = False + + if kw_copy["use_debug_redraw"]: + obj_draw_type_prev = obj.draw_type + obj.draw_type = 'WIRE' + + objects = fracture_cell_setup.cell_fracture_objects(scene, obj, **kw_copy) + objects = fracture_cell_setup.cell_fracture_boolean(scene, obj, objects, + use_island_split=use_island_split, + use_debug_redraw=kw_copy["use_debug_redraw"]) + + # todo, split islands. + + # must apply after boolean. + if use_recenter: + bpy.ops.object.origin_set({"selected_editable_objects": objects}, + type='ORIGIN_GEOMETRY', center='MEDIAN') + + if level < recursion: + + objects_recurse_input = [(i, o) for i, o in enumerate(objects)] + + if recursion_chance != 1.0: + + if 0: + random.shuffle(objects_recurse_input) + else: + from mathutils import Vector + if recursion_chance_select == 'RANDOM': + pass + elif recursion_chance_select == {'SIZE_MIN', 'SIZE_MAX'}: + objects_recurse_input.sort(key=lambda ob_pair: + (Vector(ob_pair[1].bound_box[0]) - + Vector(ob_pair[1].bound_box[6])).length_squared) + if recursion_chance_select == 'SIZE_MAX': + objects_recurse_input.reverse() + elif recursion_chance_select == {'CURSOR_MIN', 'CURSOR_MAX'}: + print(recursion_chance_select) + c = scene.cursor_location.copy() + objects_recurse_input.sort(key=lambda ob_pair: + (ob_pair[1].matrix_world.translation - c).length_squared) + if recursion_chance_select == 'CURSOR_MAX': + objects_recurse_input.reverse() + + objects_recurse_input[int(recursion_chance * len(objects_recurse_input)):] = [] + objects_recurse_input.sort() + + # reverse index values so we can remove from original list. + objects_recurse_input.reverse() + + objects_recursive = [] + for i, obj_cell in objects_recurse_input: + assert(objects[i] is obj_cell) + objects_recursive += main_object(scene, obj_cell, level + 1, **kw) + if use_remove_original: + scene.objects.unlink(obj_cell) + del objects[i] + objects.extend(objects_recursive) + + #-------------- + # Scene Options + + # layer + if use_layer_next: + layers_new = [False] * 20 + layers_new[(obj.layers[:].index(True) + 1) % 20] = True + for obj_cell in objects: + obj_cell.layers = layers_new + # group + if group_name: + group = bpy.data.groups.get(group_name) + if group is None: + group = bpy.data.groups.new(group_name) + for obj_cell in objects: + group.objects.link(obj_cell) + + if kw_copy["use_debug_redraw"]: + obj.draw_type = obj_draw_type_prev + + # testing only! + # obj.hide = True + return objects + + +def main(context, **kw): + import time + t = time.time() + scene = context.scene + obj = context.active_object + objects = main_object(scene, obj, 0, **kw) + + bpy.ops.object.select_all(action='DESELECT') + for obj_cell in objects: + obj_cell.select = True + + print("Done! %d objects in %.4f sec" % (len(objects), time.time() - t)) + + +class FractureCell(Operator): + bl_idname = "object.add_fracture_cell_objects" + bl_label = "Cell Fracture Mesh" + bl_options = {'PRESET'} + + # ------------------------------------------------------------------------- + # Source Options + source = EnumProperty( + name="Source", + items=(('VERT_OWN', "Own Verts", "Use own vertices"), + ('VERT_CHILD', "Child Verts", "Use own vertices"), + ('PARTICLE', "Particles", ("All particle systems of the " + "source object")), + ('PENCIL', "Grease Pencil", "This objects grease pencil"), + ), + options={'ENUM_FLAG'}, + default={'PARTICLE', 'VERT_OWN'} # 'VERT_OWN', 'EDGE_OWN', 'FACE_OWN' + ) + + source_limit = IntProperty( + name="Source Limit", + description="Limit the number of input points, 0 for unlimited", + min=0, max=5000, + default=1000, + ) + + source_noise = FloatProperty( + name="Noise", + description="Randomize point distrobution", + min=0.0, max=1.0, + default=0.0, + ) + + # ------------------------------------------------------------------------- + # Recursion + + recursion = IntProperty( + name="Recursion", + description="Break shards resursively", + min=0, max=5000, + default=0, + ) + + recursion_chance = FloatProperty( + name="Random Factor", + description="Likelyhood of recursion", + min=0.0, max=1.0, + default=1.0, + ) + + recursion_chance_select = EnumProperty( + name="Recurse Over", + items=(('RANDOM', "Random", ""), + ('SIZE_MIN', "Small", "Recursively subdivide smaller objects"), + ('SIZE_MAX', "Big", "Recursively subdivide smaller objects"), + ('CURSOR_MIN', "Cursor Close", "Recursively subdivide objects closer to the cursor"), + ('CURSOR_MAX', "Cursor Far", "Recursively subdivide objects closer to the cursor"), + ), + default='SIZE_MIN', + ) + + # ------------------------------------------------------------------------- + # Mesh Data Options + + use_smooth_faces = BoolProperty( + name="Smooth Faces", + default=False, + ) + + use_smooth_edges = BoolProperty( + name="Smooth Edges", + description="Set sharp edges whem disabled", + default=True, + ) + + use_data_match = BoolProperty( + name="Match Data", + description="Match original mesh materials and data layers", + default=True, + ) + + use_island_split = BoolProperty( + name="Split Islands", + description="Split disconnected meshes", + default=True, + ) + + margin = FloatProperty( + name="Margin", + description="Gaps for the fracture (gives more stable physics)", + min=0.0, max=1.0, + default=0.001, + ) + + material_index = IntProperty( + name="Material", + description="Material index for interior faces", + default=0, + ) + + # ------------------------------------------------------------------------- + # Object Options + + use_recenter = BoolProperty( + name="Recenter", + description="Recalculate the center points after splitting", + default=True, + ) + + use_remove_original = BoolProperty( + name="Remove Original", + description="Removes the parents used to create the shatter", + default=True, + ) + + # ------------------------------------------------------------------------- + # Scene Options + # + # .. dirreferent from object options in that this controls how the objects + # are setup in the scene. + + use_layer_next = BoolProperty( + name="Next Layer", + description="At the object into the next layer", + default=True, + ) + + group_name = StringProperty( + name="Group", + description="Create objects int a group " + "(use existing or create new)", + ) + + # ------------------------------------------------------------------------- + # Debug + use_debug_points = BoolProperty( + name="Debug Points", + description="Create mesh data showing the points used for fracture", + default=False, + ) + + use_debug_redraw = BoolProperty( + name="Show Progress Realtime", + description="Redraw as fracture is done", + default=True, + ) + + def execute(self, context): + keywords = self.as_keywords() # ignore=("blah",) + + main(context, **keywords) + + return {'FINISHED'} + + + def invoke(self, context, event): + print(self.recursion_chance_select) + wm = context.window_manager + return wm.invoke_props_dialog(self, width=600) + + def draw(self, context): + layout = self.layout + box = layout.box() + col = box.column() + col.label("Point Source") + rowsub = col.row() + rowsub.prop(self, "source") + rowsub = col.row() + rowsub.prop(self, "source_limit") + rowsub.prop(self, "source_noise") + rowsub = col.row() + + box = layout.box() + col = box.column() + col.label("Recursive Shatter") + rowsub = col.row(align=True) + rowsub.prop(self, "recursion") + rowsub = col.row() + rowsub.prop(self, "recursion_chance") + rowsub.prop(self, "recursion_chance_select", expand=True) + + box = layout.box() + col = box.column() + col.label("Mesh Data") + rowsub = col.row() + rowsub.prop(self, "use_smooth_faces") + rowsub.prop(self, "use_smooth_edges") + rowsub.prop(self, "use_data_match") + rowsub.prop(self, "material_index") + rowsub = col.row() + # could be own section, control how we subdiv + rowsub.prop(self, "margin") + rowsub.prop(self, "use_island_split") + + box = layout.box() + col = box.column() + col.label("Object") + rowsub = col.row(align=True) + rowsub.prop(self, "use_recenter") + + + box = layout.box() + col = box.column() + col.label("Scene") + rowsub = col.row(align=True) + rowsub.prop(self, "use_layer_next") + rowsub.prop(self, "group_name") + + box = layout.box() + col = box.column() + col.label("Debug") + rowsub = col.row(align=True) + rowsub.prop(self, "use_debug_redraw") + rowsub.prop(self, "use_debug_points") + +#def menu_func(self, context): +# self.layout.menu("INFO_MT_add_fracture_objects", icon="PLUGIN") + + +def register(): + bpy.utils.register_class(FractureCell) + + # Add the "add fracture objects" menu to the "Add" menu + # bpy.types.INFO_MT_add.append(menu_func) + + +def unregister(): + bpy.utils.unregister_class(FractureCell) + + # Remove "add fracture objects" menu from the "Add" menu. + # bpy.types.INFO_MT_add.remove(menu_func) + + +if __name__ == "__main__": + register() diff --git a/object_fracture_cell/fracture_cell_calc.py b/object_fracture_cell/fracture_cell_calc.py new file mode 100644 index 00000000..3b9e5a16 --- /dev/null +++ b/object_fracture_cell/fracture_cell_calc.py @@ -0,0 +1,95 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +# Script copyright (C) Blender Foundation 2012 + + +def points_as_bmesh_cells(verts, points, + margin_bounds=0.05, + margin_cell=0.0): + import mathutils + from mathutils import Vector + + cells = [] + + points_sorted_current = [p for p in points] + plane_indices = [] + vertices = [] + + # there are many ways we could get planes - convex hull for eg + # but it ends up fastest if we just use bounding box + if 1: + xa = [v[0] for v in verts] + ya = [v[1] for v in verts] + za = [v[2] for v in verts] + + xmin, xmax = min(xa) - margin_bounds, max(xa) + margin_bounds + ymin, ymax = min(ya) - margin_bounds, max(ya) + margin_bounds + zmin, zmax = min(za) - margin_bounds, max(za) + margin_bounds + convexPlanes = [ + Vector((+1.0, 0.0, 0.0, -abs(xmax))), + Vector((-1.0, 0.0, 0.0, -abs(xmin))), + Vector((0.0, +1.0, 0.0, -abs(ymax))), + Vector((0.0, -1.0, 0.0, -abs(ymin))), + Vector((0.0, 0.0, +1.0, -abs(zmax))), + Vector((0.0, 0.0, -1.0, -abs(zmin))), + ] + + for i, point_cell_current in enumerate(points): + planes = [None] * len(convexPlanes) + for j in range(len(convexPlanes)): + planes[j] = convexPlanes[j].copy() + planes[j][3] += planes[j].xyz.dot(point_cell_current) + distance_max = 10000000000.0 # a big value! + + points_sorted_current.sort(key=lambda p: (p - point_cell_current).length_squared) + + for j in range(1, len(points)): + normal = points_sorted_current[j] - point_cell_current + nlength = normal.length + if nlength > distance_max: + break + + plane = normal.normalized() + plane.resize_4d() + plane[3] = (-nlength / 2.0) + margin_cell + planes.append(plane) + + vertices[:], plane_indices[:] = mathutils.geometry.points_in_planes(planes) + if len(vertices) == 0: + break + + if len(plane_indices) != len(planes): + planes[:] = [planes[k] for k in plane_indices] + + distance_max = vertices[0].length + for k in range(1, len(vertices)): + distance = vertices[k].length + if distance_max < distance: + distance_max = distance + distance_max *= 2.0 + + if len(vertices) == 0: + continue + + cells.append((point_cell_current, vertices[:])) + vertices[:] = [] + + return cells diff --git a/object_fracture_cell/fracture_cell_setup.py b/object_fracture_cell/fracture_cell_setup.py new file mode 100644 index 00000000..a3365828 --- /dev/null +++ b/object_fracture_cell/fracture_cell_setup.py @@ -0,0 +1,371 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +# Script copyright (C) Blender Foundation 2012 + +import bpy +import bmesh + + +def _redraw_yasiamevil(): + _redraw_yasiamevil.opr(**_redraw_yasiamevil.arg) +_redraw_yasiamevil.opr = bpy.ops.wm.redraw_timer +_redraw_yasiamevil.arg = dict(type='DRAW_WIN_SWAP', iterations=1) + + + +def _points_from_object(obj, source): + + _source_all = { + 'PARTICLE', 'PENCIL', + 'VERT_OWN', 'VERT_CHILD', + } + + print(source - _source_all) + print(source) + assert(len(source | _source_all) == len(_source_all)) + assert(len(source)) + + points = [] + + def edge_center(mesh, edge): + v1, v2 = edge.vertices + return (mesh.vertices[v1].co + mesh.vertices[v2].co) / 2.0 + + def poly_center(mesh, poly): + from mathutils import Vector + co = Vector() + tot = 0 + for i in poly.loop_indices: + co += mesh.vertices[mesh.loops[i].vertex_index].co + tot += 1 + return co / tot + + def points_from_verts(obj): + """Takes points from _any_ object with geometry""" + if obj.type == 'MESH': + mesh = obj.data + matrix = obj.matrix_world.copy() + points.extend([matrix * v.co for v in mesh.vertices]) + else: + try: + mesh = ob.to_mesh(scene=bpy.context.scene, + apply_modifiers=True, + settings='PREVIEW') + except: + mesh = None + + if mesh is not None: + matrix = obj.matrix_world.copy() + points.extend([matrix * v.co for v in mesh.vertices]) + bpy.data.meshes.remove(mesh) + + # geom own + if 'VERT_OWN' in source: + points_from_verts(obj) + + # geom children + if 'VERT_CHILD' in source: + for obj_child in obj.children: + points_from_verts(obj_child) + + # geom particles + if 'PARTICLE' in source: + points.extend([p.location.copy() + for psys in obj.particle_systems + for p in psys.particles]) + + # grease pencil + def get_points(stroke): + return [point.co.copy() for point in stroke.points] + + def get_splines(gp): + if gp.layers.active: + frame = gp.layers.active.active_frame + return [get_points(stroke) for stroke in frame.strokes] + else: + return [] + + if 'PENCIL' in source: + gp = obj.grease_pencil + if gp: + points.extend([p for spline in get_splines(gp) + for p in spline]) + + return points + + +def cell_fracture_objects(scene, obj, + source={'PARTICLE'}, + source_limit=0, + source_noise=0.0, + clean=True, + # operator options + use_smooth_faces=False, + use_smooth_edges=True, + use_data_match=False, + use_debug_points=False, + margin=0.0, + material_index=0, + use_debug_redraw=False, + ): + + from . import fracture_cell_calc + + # ------------------------------------------------------------------------- + # GET POINTS + + points = _points_from_object(obj, source) + + if not points: + # print using fallback + points = _points_from_object(obj, source | {'VERT_OWN'}) + + if not points: + print("no points found") + return [] + + # apply optional clamp + if source_limit != 0 and source_limit < len(points): + import random + random.shuffle(points) + points[source_limit:] = [] + + + # saddly we cant be sure there are no doubles + from mathutils import Vector + to_tuple = Vector.to_tuple + points = list({to_tuple(p, 4): p for p in points}.values()) + del to_tuple + del Vector + + + if source_noise > 0.0: + from random import random + # boundbox approx of overall scale + from mathutils import Vector + matrix = obj.matrix_world.copy() + bb_world = [matrix * Vector(v) for v in obj.bound_box] + scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0) + + from mathutils.noise import random_unit_vector + + points[:] = [p + (random_unit_vector() * (scalar * random())) for p in points] + + # end remove doubles + # ------------------ + + if use_debug_points: + bm = bmesh.new() + for p in points: + bm.verts.new(p) + mesh_tmp = bpy.data.meshes.new(name="DebugPoints") + bm.to_mesh(mesh_tmp) + bm.free() + obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp) + scene.objects.link(obj_tmp) + del obj_tmp, mesh_tmp + + mesh = obj.data + matrix = obj.matrix_world.copy() + verts = [matrix * v.co for v in mesh.vertices] + + cells = fracture_cell_calc.points_as_bmesh_cells(verts, points, + margin_cell=margin) + + # some hacks here :S + cell_name = obj.name + "_cell" + + objects = [] + + for center_point, cell_points in cells: + + # --------------------------------------------------------------------- + # BMESH + + # create the convex hulls + bm = bmesh.new() + for i, co in enumerate(cell_points): + bm_vert = bm.verts.new(co) + bm_vert.tag = True + + import mathutils + bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005) + try: + bmesh.ops.convex_hull(bm, input=bm.verts) + except RuntimeError: + import traceback + traceback.print_exc() + + if clean: + for bm_vert in bm.verts: + bm_vert.tag = True + for bm_edge in bm.edges: + bm_edge.tag = True + bm.normal_update() + try: + bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001) + except RuntimeError: + import traceback + traceback.print_exc() + + if use_smooth_faces: + for bm_face in bm.faces: + bm_face.smooth = True + + if use_smooth_edges: + for bm_edge in bm.edges: + bm_edge.smooth = True + + if material_index != 0: + for bm_face in bm.faces: + bm_face.material_index = material_index + + + # --------------------------------------------------------------------- + # MESH + + mesh_dst = bpy.data.meshes.new(name=cell_name) + + bm.to_mesh(mesh_dst) + bm.free() + del bm + + if use_data_match: + # match materials and data layers so boolean displays them + # currently only materials + data layers, could do others... + mesh_src = obj.data + for mat in mesh_src.materials: + mesh_dst.materials.append(mat) + for lay_attr in ("vertex_colors", "uv_textures"): + lay_src = getattr(mesh_src, lay_attr) + lay_dst = getattr(mesh_dst, lay_attr) + for key in lay_src.keys(): + lay_dst.new(name=key) + + # --------------------------------------------------------------------- + # OBJECT + + obj_cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst) + scene.objects.link(obj_cell) + # scene.objects.active = obj_cell + obj_cell.location = center_point + + objects.append(obj_cell) + + if use_debug_redraw: + scene.update() + _redraw_yasiamevil() + + scene.update() + + + # move this elsewhere... + for obj_cell in objects: + game = obj_cell.game + game.physics_type = 'RIGID_BODY' + game.use_collision_bounds = True + game.collision_bounds_type = 'CONVEX_HULL' + + return objects + + +def cell_fracture_boolean(scene, obj, objects, + apply=True, + clean=True, + use_island_split=False, + use_debug_redraw=False, + ): + + objects_boolean = [] + + for obj_cell in objects: + mod = obj_cell.modifiers.new(name="Boolean", type='BOOLEAN') + mod.object = obj + mod.operation = 'INTERSECT' + + if apply: + mesh_new = obj_cell.to_mesh(scene, + apply_modifiers=True, + settings='PREVIEW') + mesh_old = obj_cell.data + obj_cell.data = mesh_new + obj_cell.modifiers.remove(mod) + + # remove if not valid + if not mesh_old.users: + bpy.data.meshes.remove(mesh_old) + if not mesh_new.vertices: + scene.objects.unlink(obj_cell) + if not obj_cell.users: + bpy.data.objects.remove(obj_cell) + obj_cell = None + if not mesh_new.users: + bpy.data.meshes.remove(mesh_new) + mesh_new = None + + if clean and mesh_new is not None: + bm = bmesh.new() + bm.from_mesh(mesh_new) + for bm_vert in bm.verts: + bm_vert.tag = True + for bm_edge in bm.edges: + bm_edge.tag = True + bm.normal_update() + try: + bmesh.ops.dissolve_limit(bm, verts=bm.verts, edges=bm.edges, angle_limit=0.001) + except RuntimeError: + import traceback + traceback.print_exc() + bm.to_mesh(mesh_new) + bm.free() + + if obj_cell is not None: + objects_boolean.append(obj_cell) + + if use_debug_redraw: + _redraw_yasiamevil() + + if apply and use_island_split: + # this is ugly and Im not proud of this - campbell + objects_islands = [] + for obj_cell in objects_boolean: + + scene.objects.active = obj_cell + + group_island = bpy.data.groups.new(name="Islands") + group_island.objects.link(obj_cell) + + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.separate(type='LOOSE') + bpy.ops.object.mode_set(mode='OBJECT') + + objects_islands.extend(group_island.objects[:]) + + bpy.data.groups.remove(group_island) + + scene.objects.active = None + + objects_boolean = objects_islands + + scene.update() + + return objects_boolean |