Source code for fabex.utilities.waterline_utils
try:
import ocl
except ImportError:
try:
import opencamlib as ocl
except ImportError:
pass
from ..constants import (
OCL_SCALE,
)
from .async_utils import progress_async
from .chunk_builder import CamPathChunk
from .chunk_utils import sort_chunks
from .logging_utils import log
from .ocl_utils import get_oclSTL
[docs]
def oclWaterlineLayerHeights(operation):
"""Generate a list of waterline layer heights for a given operation.
This function calculates the heights of waterline layers based on the
specified parameters of the operation. It starts from the maximum height
and decrements by a specified step until it reaches the minimum height.
The resulting list of heights can be used for further processing in
operations that require layered depth information.
Args:
operation (object): An object containing the properties `minz`,
`maxz`, and `stepdown` which define the
minimum height, maximum height, and step size
for layer generation, respectively.
Returns:
list: A list of waterline layer heights from maximum to minimum.
"""
layers = []
l_last = operation.min_z
l_step = operation.stepdown
l_first = operation.max_z - l_step
l_depth = l_first
while l_depth > (l_last + 0.0000001):
layers.append(l_depth)
l_depth -= l_step
layers.append(l_last)
return layers
[docs]
async def oclGetWaterline(operation, chunks):
"""Generate waterline paths for a given machining operation.
This function calculates the waterline paths based on the provided
machining operation and its parameters. It determines the appropriate
cutter type and dimensions, sets up the waterline object with the
corresponding STL file, and processes each layer to generate the
machining paths. The resulting paths are stored in the provided chunks
list. The function also handles different cutter types, including end
mills, ball nose cutters, and V-carve cutters.
Args:
operation (Operation): An object representing the machining operation,
containing details such as cutter type, diameter, and minimum Z height.
chunks (list): A list that will be populated with the generated
machining path chunks.
"""
layers = oclWaterlineLayerHeights(operation)
oclSTL = get_oclSTL(operation)
op_cutter_type = operation.cutter_type
op_cutter_diameter = operation.cutter_diameter
op_minz = operation.min_z
if op_cutter_type == "VCARVE":
op_cutter_tip_angle = operation["cutter_tip_angle"]
cutter = None
# TODO: automatically determine necessary cutter length depending on object size
cutter_length = 150
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
)
else:
log.info(f"Cutter Unsupported: {op_cutter_type}\n")
quit()
waterline = ocl.Waterline()
waterline.setSTL(oclSTL)
waterline.setCutter(cutter)
waterline.setSampling(0.1) # TODO: add sampling setting to UI
last_pos = [0, 0, 0]
for count, height in enumerate(layers):
layer_chunks = []
await progress_async("Waterline", int((100 * count) / len(layers)))
waterline.reset()
waterline.setZ(height * OCL_SCALE)
waterline.run2()
wl_loops = waterline.getLoops()
for l in wl_loops:
inpoints = []
for p in l:
inpoints.append((p.x / OCL_SCALE, p.y / OCL_SCALE, p.z / OCL_SCALE))
inpoints.append(inpoints[0])
chunk = CamPathChunk(inpoints=inpoints)
chunk.closed = True
layer_chunks.append(chunk)
# sort chunks so that ordering is stable
chunks.extend(await sort_chunks(layer_chunks, operation, last_pos=last_pos))
if len(chunks) > 0:
last_pos = chunks[-1].get_point(-1)