blendercam/scripts/addons/cam/opencamlib/oclSample.py

174 wiersze
6.0 KiB
Python

"""Fabex 'oclSample.py'
Functions to sample mesh or curve data for OpenCAMLib processing.
"""
from math import radians, tan
try:
import ocl
except ImportError:
try:
import opencamlib as ocl
except ImportError:
pass
try:
from bl_ext.blender_org.stl_format_legacy import blender_utils
except ImportError:
pass
import mathutils
from ..constants import OCL_SCALE, _PREVIOUS_OCL_MESH
from ..simple import activate
from ..exception import CamException
from ..operators.async_op import progress_async
def get_oclSTL(operation):
"""Get the oclSTL representation from the provided operation.
This function iterates through the objects in the given operation and
constructs an oclSTL object by extracting triangle data from mesh,
curve, font, or surface objects. It activates each object and checks its
type to determine if it can be processed. If no valid objects are found,
it raises an exception.
Args:
operation (Operation): An object containing a collection of objects
Returns:
ocl.STLSurf: An oclSTL object containing the triangles derived from
the valid objects.
Raises:
CamException: If no mesh, curve, or equivalent object is found in
"""
me = None
oclSTL = ocl.STLSurf()
found_mesh = False
for collision_object in operation.objects:
activate(collision_object)
if (
collision_object.type == "MESH"
or collision_object.type == "CURVE"
or collision_object.type == "FONT"
or collision_object.type == "SURFACE"
):
found_mesh = True
global_matrix = mathutils.Matrix.Identity(4)
faces = blender_utils.faces_from_mesh(
collision_object, global_matrix, operation.use_modifiers
)
for face in faces:
t = ocl.Triangle(
ocl.Point(
face[0][0] * OCL_SCALE,
face[0][1] * OCL_SCALE,
(face[0][2] + operation.skin) * OCL_SCALE,
),
ocl.Point(
face[1][0] * OCL_SCALE,
face[1][1] * OCL_SCALE,
(face[1][2] + operation.skin) * OCL_SCALE,
),
ocl.Point(
face[2][0] * OCL_SCALE,
face[2][1] * OCL_SCALE,
(face[2][2] + operation.skin) * OCL_SCALE,
),
)
oclSTL.addTriangle(t)
# FIXME needs to work with collections
if not found_mesh:
raise CamException(
"This Operation Requires a Mesh or Curve Object or Equivalent (e.g. Text, Volume)."
)
return oclSTL
async def ocl_sample(operation, chunks, use_cached_mesh=False):
"""Sample points using a specified cutter and operation.
This function takes an operation and a list of chunks, and samples
points based on the specified cutter type and its parameters. It
supports various cutter types such as 'END', 'BALLNOSE', 'VCARVE',
'CYLCONE', 'BALLCONE', and 'BULLNOSE'. The function can also utilize a
cached mesh for efficiency. The sampled points are returned after
processing all chunks.
Args:
operation (Operation): An object containing the cutter type, diameter,
minimum Z value, tip angle, and other relevant parameters.
chunks (list): A list of chunk objects that contain point data to be
processed.
use_cached_mesh (bool): A flag indicating whether to use a cached mesh
if available. Defaults to False.
Returns:
list: A list of sampled CL points generated by the cutter.
"""
global _PREVIOUS_OCL_MESH
op_cutter_type = operation.cutter_type
op_cutter_diameter = operation.cutter_diameter
op_minz = operation.min_z
op_cutter_tip_angle = radians(operation.cutter_tip_angle) / 2
if op_cutter_type == "VCARVE":
cutter_length = (op_cutter_diameter / tan(op_cutter_tip_angle)) / 2
else:
cutter_length = 10
cutter = None
if op_cutter_type == "END":
cutter = ocl.CylCutter((op_cutter_diameter + operation.skin * 2) * 1000, cutter_length)
elif op_cutter_type == "BALLNOSE":
cutter = ocl.BallCutter((op_cutter_diameter + operation.skin * 2) * 1000, cutter_length)
elif op_cutter_type == "VCARVE":
cutter = ocl.ConeCutter(
(op_cutter_diameter + operation.skin * 2) * 1000, op_cutter_tip_angle, cutter_length
)
elif op_cutter_type == "CYLCONE":
cutter = ocl.CylConeCutter(
(operation.cylcone_diameter / 2 + operation.skin) * 2000,
(op_cutter_diameter + operation.skin * 2) * 1000,
op_cutter_tip_angle,
)
elif op_cutter_type == "BALLCONE":
cutter = ocl.BallConeCutter(
(operation.ball_radius + operation.skin) * 2000,
(op_cutter_diameter + operation.skin * 2) * 1000,
op_cutter_tip_angle,
)
elif op_cutter_type == "BULLNOSE":
cutter = ocl.BullCutter(
(op_cutter_diameter + operation.skin * 2) * 1000,
operation.bull_corner_radius * 1000,
cutter_length,
)
else:
print("Cutter Unsupported: {0}\n".format(op_cutter_type))
quit()
bdc = ocl.BatchDropCutter()
if use_cached_mesh and _PREVIOUS_OCL_MESH is not None:
oclSTL = _PREVIOUS_OCL_MESH
else:
oclSTL = get_oclSTL(operation)
_PREVIOUS_OCL_MESH = oclSTL
bdc.setSTL(oclSTL)
bdc.setCutter(cutter)
for chunk in chunks:
for coord in chunk.get_points_np():
bdc.appendPoint(ocl.CLPoint(coord[0] * 1000, coord[1] * 1000, op_minz * 1000))
await progress_async("OpenCAMLib Sampling")
bdc.run()
cl_points = bdc.getCLPoints()
return cl_points