Source code for cam.slice

"""BlenderCAM 'slice.py' © 2021 Alain Pelletier

Very simple slicing for 3D meshes, useful for plywood cutting.
Completely rewritten April 2021.
"""

import bpy
from bpy.props import (
    BoolProperty,
    FloatProperty,
)
from bpy.types import PropertyGroup

from . import (
    constants,
    utils,
)


[docs] def slicing2d(ob, height): """Slice a 3D object at a specified height and convert it to a curve. This function applies transformations to the given object, switches to edit mode, selects all vertices, and performs a bisect operation to slice the object at the specified height. After slicing, it resets the object's location and applies transformations again before converting the object to a curve. If the conversion fails (for instance, if the mesh was empty), the function deletes the mesh and returns False. Otherwise, it returns True. Args: ob (bpy.types.Object): The Blender object to be sliced and converted. height (float): The height at which to slice the object. Returns: bool: True if the conversion to curve was successful, False otherwise. """ # April 2020 Alain Pelletier # let's slice things bpy.ops.object.transform_apply(location=True, rotation=False, scale=False) bpy.ops.object.mode_set(mode='EDIT') # force edit mode bpy.ops.mesh.select_all(action='SELECT') # select all vertices # actual slicing here bpy.ops.mesh.bisect(plane_co=(0.0, 0.0, height), plane_no=(0.0, 0.0, 1.0), use_fill=True, clear_inner=True, clear_outer=True) # slicing done bpy.ops.object.mode_set(mode='OBJECT') # force object mode # bring all the slices to 0 level and reset location transform ob.location[2] = -1 * height bpy.ops.object.transform_apply(location=True, rotation=False, scale=False) bpy.ops.object.convert(target='CURVE') # convert it to curve if bpy.context.active_object.type != 'CURVE': # conversion failed because mesh was empty so delete mesh bpy.ops.object.delete(use_global=False, confirm=False) return False bpy.ops.object.select_all(action='DESELECT') # deselect everything return True
[docs] def slicing3d(ob, start, end): """Slice a 3D object along specified planes. This function applies transformations to a given object and slices it in the Z-axis between two specified values, `start` and `end`. It first ensures that the object is in edit mode and selects all vertices before performing the slicing operations using the `bisect` method. After slicing, it resets the object's location and applies the transformations to maintain the changes. Args: ob (Object): The 3D object to be sliced. start (float): The starting Z-coordinate for the slice. end (float): The ending Z-coordinate for the slice. Returns: bool: True if the slicing operation was successful. """ # April 2020 Alain Pelletier # let's slice things bpy.ops.object.transform_apply(location=True, rotation=False, scale=False) bpy.ops.object.mode_set(mode='EDIT') # force edit mode bpy.ops.mesh.select_all(action='SELECT') # select all vertices # actual slicing here bpy.ops.mesh.bisect(plane_co=(0.0, 0.0, start), plane_no=(0.0, 0.0, 1.0), use_fill=False, clear_inner=True, clear_outer=False) bpy.ops.mesh.select_all(action='SELECT') # select all vertices which bpy.ops.mesh.bisect(plane_co=(0.0, 0.0, end), plane_no=(0.0, 0.0, 1.0), use_fill=True, clear_inner=False, clear_outer=True) # slicing done bpy.ops.object.mode_set(mode='OBJECT') # force object mode # bring all the slices to 0 level and reset location transform ob.location[2] = -1 * start bpy.ops.object.transform_apply(location=True, rotation=False, scale=False) bpy.ops.object.select_all(action='DESELECT') # deselect everything return True
[docs] def sliceObject(ob): """Slice a 3D object into layers based on a specified thickness. This function takes a 3D object and slices it into multiple layers according to the specified thickness. It creates a new collection for the slices and optionally creates text labels for each slice if the indexes parameter is set. The slicing can be done in either 2D or 3D based on the user's selection. The function also handles the positioning of the slices based on the object's bounding box. Args: ob (bpy.types.Object): The 3D object to be sliced. """ # April 2020 Alain Pelletier # get variables from menu thickness = bpy.context.scene.cam_slice.slice_distance slice3d = bpy.context.scene.cam_slice.slice_3d indexes = bpy.context.scene.cam_slice.indexes above0 = bpy.context.scene.cam_slice.slice_above0 # setup the collections scollection = bpy.data.collections.new("Slices") bpy.context.scene.collection.children.link(scollection) if indexes: tcollection = bpy.data.collections.new("Text") bpy.context.scene.collection.children.link(tcollection) bpy.ops.object.mode_set(mode='OBJECT') # force object mode minx, miny, minz, maxx, maxy, maxz = utils.getBoundsWorldspace([ob]) start_height = minz if above0 and minz < 0: start_height = 0 # calculate amount of layers needed layeramt = 1 + int((maxz - start_height) // thickness) for layer in range(layeramt): height = round(layer * thickness, 6) # height of current layer t = str(layer) + "-" + str(height * 1000) slicename = "slice_" + t # name for the current slice tslicename = "t_" + t # name for the current slice text height += start_height print(slicename) ob.select_set(True) # select object to be sliced bpy.context.view_layer.objects.active = ob # make object to be sliced active bpy.ops.object.duplicate() # make a copy of object to be sliced bpy.context.view_layer.objects.active.name = slicename # change the name of object # attribute active object to obslice obslice = bpy.context.view_layer.objects.active scollection.objects.link(obslice) # link obslice to scollecton if slice3d: # slice 3d at desired height and stop at desired height slicesuccess = slicing3d(obslice, height, height + thickness) else: # slice object at desired height slicesuccess = slicing2d(obslice, height) if indexes and slicesuccess: # text objects bpy.ops.object.text_add() # new text object textob = bpy.context.active_object textob.data.size = 0.006 # change size of object textob.data.body = t # text content textob.location = (0, 0, 0) # text location textob.name = tslicename # change the name of object bpy.ops.object.select_all(action='DESELECT') # deselect everything tcollection.objects.link(textob) # add to text collection textob.parent = obslice # make textob child of obslice # select all slices for obj in bpy.data.collections['Slices'].all_objects: obj.select_set(True)
[docs] class SliceObjectsSettings(PropertyGroup): """Stores All Data for Machines"""
[docs] slice_distance: FloatProperty( name="Slicing Distance", description="Slices distance in z, should be most often " "thickness of plywood sheet.", min=0.001, max=10, default=0.005, precision=constants.PRECISION, unit="LENGTH", )
[docs] slice_above0: BoolProperty( name="Slice Above 0", description="only slice model above 0", default=False, )
[docs] slice_3d: BoolProperty( name="3D Slice", description="For 3D carving", default=False, )
[docs] indexes: BoolProperty( name="Add Indexes", description="Adds index text of layer + index", default=True, )