diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml new file mode 100644 index 00000000..19c3ed62 --- /dev/null +++ b/.github/workflows/build_and_test.yaml @@ -0,0 +1,87 @@ +name: Run tests on push / PR +on: + push: + pull_request: +jobs: + build_and_test: + strategy: + fail-fast: false + matrix: + os: ['ubuntu-latest','windows-latest'] + blender_version: ['3.6.7','4.0.2'] + include: + - os: 'macos-latest' + blender_version: 'ignored' + runs-on: ${{matrix.os}} + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.1 + - name: Install bash 4(macOS) + if: runner.os == 'macOS' + run: brew install bash + - name: Install blender (macOS) + if: runner.os == 'macOS' + run: brew install --cask blender + - name: Cache blender + id: cache-blender + if: runner.os != 'macOS' + uses: actions/cache/restore@v3 + with: + path: blender + key: ${{ matrix.os }}-${{ matrix.blender_version}}-blender + - name: Download blender + id: download + if: steps.cache-blender.outputs.cache-hit != 'true' && runner.os != 'macOS' + shell: bash + run: | + declare -A os_suffixes + os_suffixes["ubuntu-latest"]="linux-x64.tar.xz" + os_suffixes["macos-latest"]="macos-x64.dmg" + os_suffixes["windows-latest"]="windows-x64.zip" + export OS_SUFFIX=${os_suffixes["${{matrix.os}}"]} + IFS='.' read -ra BLENDER_SPLIT <<< "${{matrix.blender_version}}" + export BLENDER_MAJOR=${BLENDER_SPLIT[0]}.${BLENDER_SPLIT[1]} + export BLENDER_MINOR=${BLENDER_SPLIT[2]} + export BLENDER_ARCHIVE="blender-${BLENDER_MAJOR}.${BLENDER_MINOR}-${OS_SUFFIX}" + echo Major version: $BLENDER_MAJOR + echo Minor version: $BLENDER_MINOR + echo Archive name: $BLENDER_ARCHIVE + curl -O -L https://download.blender.org/release/Blender${BLENDER_MAJOR}/${BLENDER_ARCHIVE} + echo "BLENDER_ARCHIVE=${BLENDER_ARCHIVE}" >> "$GITHUB_OUTPUT" + - name: Extract blender + if: steps.cache-blender.outputs.cache-hit != 'true' && runner.os != 'macOS' + run: | + import shutil + import os + os.makedirs("blender",exist_ok=True) + shutil.unpack_archive("${{ steps.download.outputs.BLENDER_ARCHIVE }}","blender") + shell: python + - name: Save blender + uses: actions/cache/save@v3 + if: steps.cache-blender.outputs.cache-hit != 'true' && runner.os != 'macOS' + with: + path: blender + key: ${{ matrix.os }}-${{ matrix.blender_version}}-blender + - name: Make addon zip + uses: thedoctor0/zip-release@0.7.5 + with: + type: 'zip' + filename: 'blendercam.zip' + directory: './scripts/addons' + - name: Run tests + shell: bash + run: | + if [ "${{ runner.os }}" != "macOS" ]; then + export BLENDER_BIN_PATH=${PWD}/blender/$(ls -AU blender | head -1) + export PATH=$PATH:${BLENDER_BIN_PATH} + fi + export ADDON_PATH=${PWD}/scripts/addons/blendercam.zip + cd scripts/addons/cam/tests + python install_addon.py ${ADDON_PATH} + python test_suite.py + - uses: actions/upload-artifact@v4 + if: always() + with: + name: blendercam-${{matrix.os}}-${{matrix.blender_version}} + path: ./scripts/addons/blendercam.zip + diff --git a/.github/workflows/create_release.yaml b/.github/workflows/create_release.yaml new file mode 100644 index 00000000..5090a8e3 --- /dev/null +++ b/.github/workflows/create_release.yaml @@ -0,0 +1,61 @@ +name: Run tests on push / PR +on: + workflow_dispatch: + inputs: + version_bump: + description: 'New version:' + required: true + default: 'patch' + type: choice + options: + - overwrite previous tag + - minor + - major + - patch +jobs: + release: + runs-on: "ubuntu-latest" + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + - name: Bump version + shell: python + env: + VERSION_BUMP: ${{ inputs.version_bump }} + run: | + from pathlib import Path + import re + import os + v_file=Path("scripts","addons","cam","version.py") + version_txt=v_file.read_text() + major,minor,patch = re.match(version_txt,".*\((\d+),(\d+),(\d+)\)".groups() + bump = os.getenv("VERSION_BUMP") + if bump == "minor": + minor+=1 + bump = "${{ inputs.logLevel }}" + if version=='patch': + patch+=1 + elif version=='minor': + minor+=1 + patch=0 + elif version=='major': + major+=1 + minor=0 + patch=0 + v_file.write_text(f"__version__={(major,minor,patch)}") + env_file = Path(os.getenv('GITHUB_ENV')) + env_file.write_text("VERSION_TAG")=f"v{major}.{minor}.{patch}" + print(f"New version: v{major}.{minor}.{patch}") + - name: Make addon zip + uses: thedoctor0/zip-release@0.7.5 + with: + type: 'zip' + filename: 'blendercam.zip' + directory: './scripts/addons' + - name: tag release + uses: ncipollo/release-action@v1 + with: + artifacts: "scripts/addons/blendercam.zip" + tag: ${{ env.VERSION_TAG }} + commit: ${ GITHUB_SHA } + diff --git a/scripts/addons/cam/__init__.py b/scripts/addons/cam/__init__.py index 0a7c4097..c36ccff9 100644 --- a/scripts/addons/cam/__init__.py +++ b/scripts/addons/cam/__init__.py @@ -52,18 +52,17 @@ from mathutils import * from shapely import geometry as sgeometry from cam.ui import * - - +from cam.version import __version__ bl_info = { "name": "CAM - gcode generation tools", "author": "Vilem Novak", - "version": (0, 9, 3), - "blender": (2, 80, 0), + "version": __version__, + "blender": (3, 6, 0), "location": "Properties > render", "description": "Generate machining paths for CNC", - "warning": "there is no warranty for the produced gcode by now", - "wiki_url": "https://github.com/vilemduha/blendercam/wiki", + "warning": "", + "doc_url": "https://blendercam.com/", "tracker_url": "", "category": "Scene"} diff --git a/scripts/addons/cam/async_op.py b/scripts/addons/cam/async_op.py index 280ce791..a90c922d 100644 --- a/scripts/addons/cam/async_op.py +++ b/scripts/addons/cam/async_op.py @@ -47,10 +47,10 @@ class AsyncOperatorMixin: def show_progress(self,context,text, n,value_type): if n is not None: - progress_text = f"{text},{n:.2f}{value_type}" + progress_text = f"{text}: {n:.2f}{value_type}" else: progress_text = f"{text}" - bpy.context.workspace.status_text_set(progress_text + " Press ESC to cancel") + bpy.context.workspace.status_text_set(progress_text + " (Press ESC to cancel)") sys.stdout.write(f"Progress: {progress_text}\n") sys.stdout.flush() @@ -72,9 +72,16 @@ class AsyncOperatorMixin: return False def execute(self, context): - self.timer=context.window_manager.event_timer_add(.001, window=context.window) - context.window_manager.modal_handler_add(self) - return {'RUNNING_MODAL'} + if bpy.app.background: + # running in background - don't run as modal, + # otherwise tests all fail + while self.tick(context)==True: + pass + return {'FINISHED'} + else: + self.timer=context.window_manager.event_timer_add(.001, window=context.window) + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} class AsyncTestOperator(bpy.types.Operator,AsyncOperatorMixin): """test async operator""" diff --git a/scripts/addons/cam/gcodepath.py b/scripts/addons/cam/gcodepath.py index fc85b181..09cb4564 100644 --- a/scripts/addons/cam/gcodepath.py +++ b/scripts/addons/cam/gcodepath.py @@ -631,13 +631,13 @@ async def getPath3axis(context, operation): pathSamples = await utils.sortChunks(pathSamples, o) # sort before sampling pathSamples = chunksRefine(pathSamples, o) elif o.strategy == 'PENCIL': - prepareArea(o) + await prepareArea(o) utils.getAmbient(o) pathSamples = getOffsetImageCavities(o, o.offset_image) pathSamples = limitChunks(pathSamples, o) pathSamples = await utils.sortChunks(pathSamples, o) # sort before sampling elif o.strategy == 'CRAZY': - prepareArea(o) + await prepareArea(o) # pathSamples = crazyStrokeImage(o) # this kind of worked and should work: millarea = o.zbuffer_image < o.minz + 0.000001 @@ -649,7 +649,6 @@ async def getPath3axis(context, operation): pathSamples = chunksRefine(pathSamples, o) else: - print("PARALLEL") if o.strategy == 'OUTLINEFILL': utils.getOperationSilhouete(o) @@ -660,7 +659,7 @@ async def getPath3axis(context, operation): # have to be sorted once before, because of the parenting inside of samplechunks if o.strategy in ['BLOCK', 'SPIRAL', 'CIRCLES']: - pathSamples = utils.connectChunksLow(pathSamples, o) + pathSamples = await utils.connectChunksLow(pathSamples, o) # print (minz) @@ -678,7 +677,7 @@ async def getPath3axis(context, operation): print('sorting') chunks = await utils.sortChunks(chunks, o) if o.strategy == 'OUTLINEFILL': - chunks = utils.connectChunksLow(chunks, o) + chunks = await utils.connectChunksLow(chunks, o) if o.movement.ramp: for ch in chunks: ch.rampZigZag(ch.zstart, ch.points[0][2], o) @@ -697,7 +696,7 @@ async def getPath3axis(context, operation): elif o.strategy == 'WATERLINE' and o.optimisation.use_opencamlib: utils.getAmbient(o) chunks = [] - oclGetWaterline(o, chunks) + await oclGetWaterline(o, chunks) chunks = limitChunks(chunks, o) if (o.movement.type == 'CLIMB' and o.movement.spindle_rotation == 'CW') or ( o.movement.type == 'CONVENTIONAL' and o.movement.spindle_rotation == 'CCW'): @@ -709,7 +708,7 @@ async def getPath3axis(context, operation): topdown = True chunks = [] await progress_async('retrieving object slices') - prepareArea(o) + await prepareArea(o) layerstep = 1000000000 if o.use_layers: layerstep = math.floor(o.stepdown / o.slice_detail) @@ -840,10 +839,10 @@ async def getPath3axis(context, operation): strategy.chunksToMesh(chunks, o) elif o.strategy == 'DRILL': - strategy.drill(o) + await strategy.drill(o) elif o.strategy == 'MEDIAL_AXIS': - strategy.medial_axis(o) + await strategy.medial_axis(o) await progress_async(f"Done",time.time() - tw,"s") diff --git a/scripts/addons/cam/image_utils.py b/scripts/addons/cam/image_utils.py index 437a0a27..31d53557 100644 --- a/scripts/addons/cam/image_utils.py +++ b/scripts/addons/cam/image_utils.py @@ -33,7 +33,7 @@ from cam.simple import * from cam import chunk from cam.chunk import * from cam import simulation - +from cam.async_op import progress_async def getCircle(r, z): car = numpy.full(shape=(r*2,r*2),fill_value=-10,dtype=numpy.double) @@ -128,7 +128,7 @@ def imagetonumpy(i): return na -def offsetArea(o, samples): +async def offsetArea(o, samples): """ offsets the whole image with the cutter + skin offsets """ if o.update_offsetimage_tag: minx, miny, minz, maxx, maxy, maxz = o.min.x, o.min.y, o.min.z, o.max.x, o.max.y, o.max.z @@ -155,25 +155,17 @@ def offsetArea(o, samples): for x in range(0, cwidth): # cwidth): text = "Offsetting depth " + str(int(x * 100 / cwidth)) # o.operator.report({"INFO"}, text) - simple.progress('offset ', int(x * 100 / cwidth)) + await progress_async('offset depth image', int(x * 100 / cwidth)) for y in range(0, cwidth): - # TODO:OPTIMIZE THIS - this can run much faster when the areas won't be created each run???? - # tests dont work now if cutterArray[x, y] > -10: - # i+=1 - # progress(i) - # winner numpy.maximum(sourceArray[x: width - cwidth + x, y: height - cwidth + y] + cutterArray[x, y], comparearea, comparearea) - # contest of performance o.offset_image[m: width - cwidth + m, m:height - cwidth + m] = comparearea - # progress('offseting done') - simple.progress('\ntime ' + str(time.time() - t)) + print('\nOffset image time ' + str(time.time() - t)) o.update_offsetimage_tag = False - # progress('doing offsetimage') return o.offset_image @@ -1199,7 +1191,7 @@ def renderSampleImage(o): # return numpy.array([]) -def prepareArea(o): +async def prepareArea(o): # if not o.use_exact: renderSampleImage(o) samples = o.zbuffer_image @@ -1217,5 +1209,5 @@ def prepareArea(o): if o.update_offsetimage_tag: if o.inverse: samples = numpy.maximum(samples, o.min.z - 0.00001) - offsetArea(o, samples) + await offsetArea(o, samples) numpysave(o.offset_image, iname) diff --git a/scripts/addons/cam/opencamlib/oclSample.py b/scripts/addons/cam/opencamlib/oclSample.py index 0f82ca3a..a26f7471 100644 --- a/scripts/addons/cam/opencamlib/oclSample.py +++ b/scripts/addons/cam/opencamlib/oclSample.py @@ -13,9 +13,12 @@ import mathutils import math from cam.simple import activate from cam.exception import * +from cam.async_op import progress_async OCL_SCALE = 1000.0 +_PREVIOUS_OCL_MESH=None + def get_oclSTL(operation): me = None oclSTL = ocl.STLSurf() @@ -37,9 +40,9 @@ def get_oclSTL(operation): return oclSTL -def ocl_sample(operation, chunks): +async def ocl_sample(operation, chunks,use_cached_mesh = False): + global _PREVIOUS_OCL_MESH - oclSTL = get_oclSTL(operation) op_cutter_type = operation.cutter_type op_cutter_diameter = operation.cutter_diameter @@ -48,7 +51,7 @@ def ocl_sample(operation, chunks): if op_cutter_type == "VCARVE": cutter_length = (op_cutter_diameter/math.tan(op_cutter_tip_angle))/2 else: - cutter_length = 10 + cutter_length = 10 cutter = None @@ -70,13 +73,18 @@ def ocl_sample(operation, chunks): 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.points: bdc.appendPoint(ocl.CLPoint(coord[0] * 1000, coord[1] * 1000, op_minz * 1000)) - + await progress_async("OpenCAMLib sampling") bdc.run() cl_points = bdc.getCLPoints() diff --git a/scripts/addons/cam/opencamlib/opencamlib.py b/scripts/addons/cam/opencamlib/opencamlib.py index 674a785a..1ebdf823 100644 --- a/scripts/addons/cam/opencamlib/opencamlib.py +++ b/scripts/addons/cam/opencamlib/opencamlib.py @@ -15,6 +15,7 @@ from cam.collision import BULLET_SCALE from cam import simple from cam.chunk import camPathChunk from cam.simple import * +from cam.async_op import progress_async from shapely import geometry as sgeometry from .oclSample import get_oclSTL @@ -78,25 +79,24 @@ def exportModelsToSTL(operation): file_number += 1 -def oclSamplePoints(operation, points): - samples = ocl_sample(operation, points) +async def oclSamplePoints(operation, points): + samples = await ocl_sample(operation, points) pointSamplesFromOCL(points, samples) -def oclSample(operation, chunks): - samples = ocl_sample(operation, chunks) +async def oclSample(operation, chunks): + samples = await ocl_sample(operation, chunks) chunkPointSamplesFromOCL(chunks, samples) -def oclResampleChunks(operation, chunks_to_resample): +async def oclResampleChunks(operation, chunks_to_resample,use_cached_mesh): tmp_chunks = list() tmp_chunks.append(camPathChunk(inpoints=[])) for chunk, i_start, i_length in chunks_to_resample: for p_index in range(i_start, i_start + i_length): tmp_chunks[0].append(chunk.points[p_index]) - - samples = ocl_sample(operation, tmp_chunks) + samples = await ocl_sample(operation, tmp_chunks,use_cached_mesh=use_cached_mesh) sample_index = 0 for chunk, i_start, i_length in chunks_to_resample: @@ -127,7 +127,7 @@ def oclGetMedialAxis(operation, chunks): waterlineChunksFromOCL(operation, chunks) -def oclGetWaterline(operation, chunks): +async def oclGetWaterline(operation, chunks): layers = oclWaterlineLayerHeights(operation) oclSTL = get_oclSTL(operation) @@ -155,8 +155,8 @@ def oclGetWaterline(operation, chunks): waterline.setSTL(oclSTL) waterline.setCutter(cutter) waterline.setSampling(0.1)#TODO: add sampling setting to UI - for height in layers: - print(str(height) + '\n') + for count,height in enumerate(layers): + await progress_async("Waterline",int((100*count)/len(layers))) waterline.reset() waterline.setZ(height * OCL_SCALE) waterline.run2() diff --git a/scripts/addons/cam/strategy.py b/scripts/addons/cam/strategy.py index a7cafa7e..fe6cae2d 100644 --- a/scripts/addons/cam/strategy.py +++ b/scripts/addons/cam/strategy.py @@ -246,7 +246,7 @@ async def curve(o): chunksToMesh(pathSamples, o) -def proj_curve(s, o): +async def proj_curve(s, o): print('operation: projected curve') pathSamples = [] chunks = [] diff --git a/scripts/addons/cam/tests/install_addon.py b/scripts/addons/cam/tests/install_addon.py new file mode 100644 index 00000000..a79fc676 --- /dev/null +++ b/scripts/addons/cam/tests/install_addon.py @@ -0,0 +1,19 @@ +import tempfile +import sys +import subprocess +import pathlib + +INSTALL_CODE=f""" +import bpy +bpy.ops.preferences.addon_install(filepath='{sys.argv[1]}') +bpy.ops.preferences.addon_enable(module='cam') +bpy.ops.wm.save_userpref() +""" + +with tempfile.TemporaryDirectory() as td: + file=pathlib.Path(td,"install.py") + file.write_text(INSTALL_CODE) + command = f'blender -b -P "{str(file)}"' + subprocess.run(command, shell=True, check=True) + + diff --git a/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal.gcode b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal.gcode new file mode 100644 index 00000000..7184b278 --- /dev/null +++ b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal.gcode @@ -0,0 +1,810 @@ +(Created with grbl post processor 2024/01/11 10:02) +G21 +(G-code generated with BlenderCAM and NC library) +G17G90 +(Tool: D = 3.0 mm type END flutes 2) +S12000M03 +G00 Z2.0 + +G0X0Y0Z2 +X-98Y99 +G1Z-3.1F500 +Y-99.999F1000 +X-96 +Y99 +X-94 +Y-99.999 +X-92 +Y99 +X-90 +Y-99.999 +X-88 +Y99 +X-86 +Y-99.999 +X-84 +Y99 +X-82 +Y-99.999 +X-80 +Y99 +X-78 +Y-99.999 +X-76 +Y99 +X-74 +Y-99.999 +X-72 +Y99 +X-70 +Y-99.999 +X-68 +Y99 +X-66 +Y-99.999 +X-64 +Y99 +X-62 +Y-99.999 +X-60 +Y99 +X-58 +Y-99.999 +X-56 +Y99 +X-54 +Y-99.999 +X-52 +Y99 +X-50 +Y-99.999 +X-48 +Y99 +X-46 +Y-99.999 +X-44 +Y99 +X-42 +Y-99.999 +X-40 +Y99 +X-38 +Y-99.999 +X-36 +Y99 +X-34 +Y-99.999 +X-32 +Y99 +X-30 +Y-99.999 +X-28 +Y99 +X-26 +Y-99.999 +X-24 +Y99 +X-22 +Y-99.999 +X-20 +Y99 +X-18 +Y-99.999 +X-16 +Y99 +X-14 +Y-99.999 +X-12 +Y99 +X-10 +Y-99.999 +X-8 +Y99 +X-6 +Y-99.999 +X-4 +Y99 +X-2 +Y-99.999 +X0 +Y99 +X2 +Y-99.999 +X4 +Y99 +X6 +Y-99.999 +X8 +Y99 +X10 +Y-99.999 +X12 +Y99 +X14 +Y-99.999 +X16 +Y99 +X18 +Y-99.999 +X20 +Y99 +X22 +Y-99.999 +X24 +Y99 +X26 +Y-99.999 +X28 +Y99 +X30 +Y-99.999 +X32 +Y99 +X34 +Y-99.999 +X36 +Y99 +X38 +Y-99.999 +X40 +Y99 +X42 +Y-99.999 +X44 +Y99 +X46 +Y-99.999 +X48 +Y99 +X50 +Y-99.999 +X52 +Y99 +X54 +Y-99.999 +X56 +Y99 +X58 +Y-99.999 +X60 +Y99 +X62 +Y-99.999 +X64 +Y99 +X66 +Y-99.999 +X68 +Y99 +X70 +Y-99.999 +X72 +Y99 +X74 +Y-99.999 +X76 +Y99 +X78 +Y-99.999 +X80 +Y99 +X82 +Y-99.999 +X84 +Y99 +X86 +Y-99.999 +X88 +Y99 +X90 +Y-99.999 +X92 +Y99 +X94 +Y-99.999 +X96 +Y99 +X98 +Y-99.999 +G0Z2 +X-98 +G1Z-6.1F500 +Y99F1000 +X-96 +Y-99.999 +X-94 +Y99 +X-92 +Y-99.999 +X-90 +Y99 +X-88 +Y-99.999 +X-86 +Y99 +X-84 +Y-99.999 +X-82 +Y99 +X-80 +Y-99.999 +X-78 +Y99 +X-76 +Y-99.999 +X-74 +Y99 +X-72 +Y-99.999 +X-70 +Y99 +X-68 +Y-99.999 +X-66 +Y99 +X-64 +Y-99.999 +X-62 +Y99 +X-60 +Y-99.999 +X-58 +Y99 +X-56 +Y-99.999 +X-54 +Y99 +X-52 +Y-99.999 +X-50 +Y99 +X-48 +Y-99.999 +X-46 +Y99 +X-44 +Y-99.999 +X-42 +Y99 +X-40 +Y-99.999 +X-38 +Y99 +X-36 +Y-99.999 +X-34 +Y99 +X-32 +Y-99.999 +X-30 +Y99 +X-28 +Y-99.999 +X-26 +Y99 +X-24 +Y-99.999 +X-22 +Y99 +X-20 +Y-99.999 +X-18 +Y99 +X-16 +Y-99.999 +X-14 +Y99 +X-12 +Y-99.999 +X-10 +Y99 +X-8 +Y-99.999 +X-6 +Y99 +X-4 +Y-99.999 +X-2 +Y99 +X0 +Y-99.999 +X2 +Y99 +X4 +Y-99.999 +X6 +Y99 +X8 +Y-99.999 +X10 +Y99 +X12 +Y-99.999 +X14 +Y99 +X16 +Y-99.999 +X18 +Y99 +X20 +Y-99.999 +X22 +Y99 +X24 +Y-99.999 +X26 +Y99 +X28 +Y-99.999 +X30 +Y99 +X32 +Y-99.999 +X34 +Y99 +X36 +Y-99.999 +X38 +Y99 +X40 +Y-99.999 +X42 +Y99 +X44 +Y-99.999 +X46 +Y99 +X48 +Y-99.999 +X50 +Y99 +X52 +Y-99.999 +X54 +Y99 +X56 +Y-99.999 +X58 +Y99 +X60 +Y-99.999 +X62 +Y99 +X64 +Y-99.999 +X66 +Y99 +X68 +Y-99.999 +X70 +Y99 +X72 +Y-99.999 +X74 +Y99 +X76 +Y-99.999 +X78 +Y99 +X80 +Y-99.999 +X82 +Y99 +X84 +Y-99.999 +X86 +Y99 +X88 +Y-99.999 +X90 +Y99 +X92 +Y-99.999 +X94 +Y99 +X96 +Y-99.999 +X98 +Y99 +G0Z2 +X-98 +G1Z-9.1F500 +Y-99.999F1000 +X-96 +Y99 +X-94 +Y-99.999 +X-92 +Y99 +X-90 +Y-99.999 +X-88 +Y99 +X-86 +Y-99.999 +X-84 +Y99 +X-82 +Y-99.999 +X-80 +Y99 +X-78 +Y-99.999 +X-76 +Y99 +X-74 +Y-99.999 +X-72 +Y99 +X-70 +Y-99.999 +X-68 +Y99 +X-66 +Y-99.999 +X-64 +Y99 +X-62 +Y-99.999 +X-60 +Y99 +X-58 +Y-99.999 +X-56 +Y99 +X-54 +Y-99.999 +X-52 +Y99 +X-50 +Y-99.999 +X-48 +Y99 +X-46 +Y-99.999 +X-44 +Y99 +X-42 +Y-99.999 +X-40 +Y99 +X-38 +Y-99.999 +X-36 +Y99 +X-34 +Y-99.999 +X-32 +Y99 +X-30 +Y-99.999 +X-28 +Y99 +X-26 +Y-99.999 +X-24 +Y99 +X-22 +Y-99.999 +X-20 +Y99 +X-18 +Y-99.999 +X-16 +Y99 +X-14 +Y-99.999 +X-12 +Y99 +X-10 +Y-99.999 +X-8 +Y99 +X-6 +Y-99.999 +X-4 +Y99 +X-2 +Y-99.999 +X0 +Y99 +X2 +Y-99.999 +X4 +Y99 +X6 +Y-99.999 +X8 +Y99 +X10 +Y-99.999 +X12 +Y99 +X14 +Y-99.999 +X16 +Y99 +X18 +Y-99.999 +X20 +Y99 +X22 +Y-99.999 +X24 +Y99 +X26 +Y-99.999 +X28 +Y99 +X30 +Y-99.999 +X32 +Y99 +X34 +Y-99.999 +X36 +Y99 +X38 +Y-99.999 +X40 +Y99 +X42 +Y-99.999 +X44 +Y99 +X46 +Y-99.999 +X48 +Y99 +X50 +Y-99.999 +X52 +Y99 +X54 +Y-99.999 +X56 +Y99 +X58 +Y-99.999 +X60 +Y99 +X62 +Y-99.999 +X64 +Y99 +X66 +Y-99.999 +X68 +Y99 +X70 +Y-99.999 +X72 +Y99 +X74 +Y-99.999 +X76 +Y99 +X78 +Y-99.999 +X80 +Y99 +X82 +Y-99.999 +X84 +Y99 +X86 +Y-99.999 +X88 +Y99 +X90 +Y-99.999 +X92 +Y99 +X94 +Y-99.999 +X96 +Y99 +X98 +Y-99.999 +G0Z2 +X-98 +G1Z-10F500 +Y99F1000 +X-96 +Y-99.999 +X-94 +Y99 +X-92 +Y-99.999 +X-90 +Y99 +X-88 +Y-99.999 +X-86 +Y99 +X-84 +Y-99.999 +X-82 +Y99 +X-80 +Y-99.999 +X-78 +Y99 +X-76 +Y-99.999 +X-74 +Y99 +X-72 +Y-99.999 +X-70 +Y99 +X-68 +Y-99.999 +X-66 +Y99 +X-64 +Y-99.999 +X-62 +Y99 +X-60 +Y-99.999 +X-58 +Y99 +X-56 +Y-99.999 +X-54 +Y99 +X-52 +Y-99.999 +X-50 +Y99 +X-48 +Y-99.999 +X-46 +Y99 +X-44 +Y-99.999 +X-42 +Y99 +X-40 +Y-99.999 +X-38 +Y99 +X-36 +Y-99.999 +X-34 +Y99 +X-32 +Y-99.999 +X-30 +Y99 +X-28 +Y-99.999 +X-26 +Y99 +X-24 +Y-99.999 +X-22 +Y99 +X-20 +Y-99.999 +X-18 +Y99 +X-16 +Y-99.999 +X-14 +Y99 +X-12 +Y-99.999 +X-10 +Y99 +X-8 +Y-99.999 +X-6 +Y99 +X-4 +Y-99.999 +X-2 +Y99 +X0 +Y-99.999 +X2 +Y99 +X4 +Y-99.999 +X6 +Y99 +X8 +Y-99.999 +X10 +Y99 +X12 +Y-99.999 +X14 +Y99 +X16 +Y-99.999 +X18 +Y99 +X20 +Y-99.999 +X22 +Y99 +X24 +Y-99.999 +X26 +Y99 +X28 +Y-99.999 +X30 +Y99 +X32 +Y-99.999 +X34 +Y99 +X36 +Y-99.999 +X38 +Y99 +X40 +Y-99.999 +X42 +Y99 +X44 +Y-99.999 +X46 +Y99 +X48 +Y-99.999 +X50 +Y99 +X52 +Y-99.999 +X54 +Y99 +X56 +Y-99.999 +X58 +Y99 +X60 +Y-99.999 +X62 +Y99 +X64 +Y-99.999 +X66 +Y99 +X68 +Y-99.999 +X70 +Y99 +X72 +Y-99.999 +X74 +Y99 +X76 +Y-99.999 +X78 +Y99 +X80 +Y-99.999 +X82 +Y99 +X84 +Y-99.999 +X86 +Y99 +X88 +Y-99.999 +X90 +Y99 +X92 +Y-99.999 +X94 +Y99 +X96 +Y-99.999 +X98 +Y99 +G0Z2 + diff --git a/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal_Exact.gcode b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal_Exact.gcode new file mode 100644 index 00000000..e1c9227f --- /dev/null +++ b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_Internal_Exact.gcode @@ -0,0 +1,1103 @@ +(Created with grbl post processor 2024/01/11 10:02) +G21 +(G-code generated with BlenderCAM and NC library) +G17G90 +(Tool: D = 3.0 mm type END flutes 2) +S12000M03 +G00 Z2.0 + +G0X0Y0Z2 +X-68Y-6.999 +G1Z-0.319F500 +Y-5.999Z-0.752F1000 +Y-4.999Z-1.341F500 +Y-4.675Z-3.1 +Y6.73F1000 +Y7Z-1.741 +Y8Z-1.001 +G0Z2 +X-66Y18 +G1Z-0.702F500 +Y17.605Z-3.1 +Y-16.597Z-3.1F1000 +Y-16.999Z-0.629 +G0Z2 +X-64Y-23.999 +G1Z-0.147F500 +Y-22.999Z-0.994 +Y-22.635Z-3.1 +Y23.584F1000 +Y24Z-0.49 +G0Z2 +X-62Y29 +G1Z-0.119F500 +Y28.552Z-3.1 +Y-27.61Z-3.1F1000 +Y-27.999Z-0.762 +G0Z2 +X-60Y-31.999 +G1Z-0.83F500 +Y-31.617Z-3.1 +Y32F1000 +G0Z2 +X-58Y36 +G1Z-0.35F500 +Y35.571Z-3.1 +Y-35.564F1000 +Y-35.999Z-0.265 +G0Z2 +X-56Y-38.999 +G1Z-0.302F500 +Y-38.567Z-3.1 +Y38.571Z-3.1F1000 +Y39Z-0.348 +G0Z2 +X-54Y41 +G1Z-3.1F500 +Y-41.552F1000 +Y-41.999Z-0.134 +G0Z2 +X-52Y-43.999 +G1Z-0.528F500 +Y-43.587Z-3.1 +Y43.59Z-3.1F1000 +Y44Z-0.547 +G0Z2 +X-50Y46 +G1Z-1.111F500 +Y45.648Z-3.1 +Y-45.638Z-3.1F1000 +Y-45.999Z-1.025 +G0Z2 +X-48Y-47.999 +G1Z-3.1F500 +Y48F1000 +G0Z2 +X-46Y50 +G1Z-1.027F500 +Y49.639Z-3.1 +Y-49.646Z-3.1F1000 +Y-49.999Z-1.096 +G0Z2 +X-44Y-51.999 +G1Z-0.633F500 +Y-51.597Z-3.1 +Y51.584F1000 +Y52Z-0.491 +G0Z2 +X-42Y54 +G1Z-0.11F500 +Y53.551Z-3.1 +Y-53.563Z-3.1F1000 +Y-53.999Z-0.264 +G0Z2 +X-40Y-54.999 +G1Z-1.139F500 +Y-54.651Z-3.1 +Y54.609F1000 +Y55Z-0.744 +G0Z2 +X-38Y56 +G1Z-3.1F500 +Y-56.56F1000 +Y-56.999Z-0.229 +G0Z2 +X-36Y-57.999 +G1Z-0.545F500 +Y-57.589Z-3.1 +Y57.567Z-3.1F1000 +Y58Z-0.302 +G0Z2 +X-34Y59 +G1Z-0.579F500 +Y58.593Z-3.1 +Y-58.64F1000 +Y-58.999Z-1.043 +G0Z2 +X-32Y-59.999 +G1Z-3.1F500 +Y59.619Z-3.1F1000 +Y60Z-0.844 +G0Z2 +X-30Y61 +G1Z-0.896F500 +Y60.625Z-3.1 +Y-60.999F1000 +X-28Y-61.999 +Y61.615 +Y62Z-0.801 +G0Z2 +X-26Y63 +G1Z-0.581F500 +Y62.593Z-3.1 +Y-62.999Z-3.1F1000 +G0Z2 +X-24Y-63.999 +G1Z-0.725F500 +Y-63.606Z-3.1 +Y63.568Z-3.1F1000 +Y64Z-0.314 +G0Z2 +X-22Y65 +G1Z-0.102F500 +Y64.55Z-3.1 +Y-64.575Z-3.1F1000 +Y-64.999Z-0.392 +G0Z2 +X-20Y-65.999 +G1Z-0.105F500 +Y-65.55Z-3.1 +Y64.647F1000 +Y65Z-1.098 +G0Z2 +X-18Y66 +G1Z-0.326F500 +Y65.569Z-3.1 +Y-65.62F1000 +Y-65.999Z-0.86 +G0Z2 +X-16Y-66.999 +G1Z-0.229F500 +Y-66.56Z-3.1 +Y66F1000 +G0Z2 +X-14Y67 +G1Z-0.339F500 +Y66.57Z-3.1 +Y-66.632Z-3.1F1000 +Y-66.999Z-0.972 +G0Z2 +X-12Y-67.999 +G1Z-0.163F500 +Y-67.555Z-3.1 +Y67F1000 +G0Z2 +X-10Y68 +G1Z-0.137F500 +Y67.553Z-3.1 +Y-67.587F1000 +Y-67.999Z-0.526 +G0Z2 +X-8 +G1Z-1.273F500 +Y-67.667Z-3.1 +Y67.577Z-3.1F1000 +Y68Z-0.416 +G0Z2 +X-6 +G1Z-0.847F500 +Y67.619Z-3.1 +Y-67.999F1000 +G0Z2 +X-4Y-68.999 +G1Z-0.229F500 +Y-68.56Z-3.1 +Y68F1000 +X-2 +Y-68.57Z-3.1 +Y-68.999Z-0.338 +G0Z2 +X0 +G1Z-0.339F500 +Y-68.57Z-3.1 +Y68F1000 +X2 +Y-68.568Z-3.1 +Y-68.999Z-0.312 +G0Z2 +X4 +G1Z-0.244F500 +Y-68.562Z-3.1 +Y68F1000 +X6 +Y-67.643Z-3.1 +Y-67.999Z-1.068 +Y-68.999Z-0.18 +G0Z2 +X8Y-67.999 +G1Z-0.651F500 +Y-67.599Z-3.1 +Y67.635F1000 +Y68Z-0.995 +G0Z2 +X10 +G1Z-0.477F500 +Y67.583Z-3.1 +Y-67.574Z-3.1F1000 +Y-67.999Z-0.381 +G0Z2 +X12 +G1Z-0.218F500 +Y-67.559Z-3.1 +Y67.558Z-3.1F1000 +Y68Z-0.192 +G0Z2 +X14Y67 +G1Z-1.253F500 +Y66.665Z-3.1 +Y-66.59Z-3.1F1000 +Y-66.999Z-0.556 +G0Z2 +X16 +G1Z-0.246F500 +Y-66.562Z-3.1 +Y66.58F1000 +Y67Z-0.442 +G0Z2 +X18Y66 +G1Z-1.128F500 +Y65.65Z-3.1 +Y-65.588Z-3.1F1000 +Y-65.999Z-0.532 +Y-66.999Z-0.103 +G0Z2 +X20Y-65.999 +G1Z-0.192F500 +Y-64.999Z-1.25 +Y-64.664Z-3.1 +Y65.574Z-3.1F1000 +Y66Z-0.379 +G0Z2 +X22Y65 +G1Z-0.645F500 +Y64.599Z-3.1 +Y-64.569F1000 +Y-64.999Z-0.325 +G0Z2 +X24 +G1Z-0.11F500 +Y-63.999Z-0.497F1000 +Y-63.584Z-3.1F500 +Y63.632Z-3.1F1000 +Y64Z-0.967 +Y65Z-0.17 +G0Z2 +X26Y64 +G1Z-0.255F500 +Y63.563Z-3.1 +Y-62.606F1000 +Y-62.999Z-0.723 +Y-63.999Z-0.147 +G0Z2 +X28Y-62.999 +G1Z-0.166F500 +Y-61.999Z-0.928 +Y-61.627Z-3.1 +Y62.567Z-3.1F1000 +Y63Z-0.301 +G0Z2 +X30Y62 +G1Z-0.304F500 +Y61.567Z-3.1 +Y-60.635F1000 +Y-60.999Z-0.998 +Y-61.999Z-0.169 +G0Z2 +X32Y-60.999 +G1Z-0.163F500 +Y-59.999Z-0.929 +Y-59.628Z-3.1 +Y60.565Z-3.1F1000 +Y61Z-0.282 +G0Z2 +X34Y60 +G1Z-0.234F500 +Y59Z-1.233 +Y58.663Z-3.1 +Y-58.603Z-3.1F1000 +Y-58.999Z-0.687 +Y-59.999Z-0.144 +G0Z2 +X36Y-58.999 +G1Z-0.115F500 +Y-57.999Z-0.433F1000 +Y-57.578Z-3.1F500 +Y57.608Z-3.1F1000 +Y58Z-0.74 +Y59Z-0.174 +G0Z2 +X38Y58 +G1Z-0.116F500 +Y57Z-0.438F1000 +Y56.579Z-3.1F500 +Y-56.562Z-3.1F1000 +Y-56.999Z-0.243 +G0Z2 +X40Y-55.999 +G1Z-0.152F500 +Y-54.999Z-0.794 +Y-54.613Z-3.1 +Y54.668F1000 +Y55Z-1.281 +Y56Z-0.241 +G0Z2 +X42Y55 +G1Z-0.13F500 +Y54Z-0.458F1000 +Y53.581Z-3.1F500 +Y-53.563Z-3.1F1000 +Y-53.999Z-0.262 +G0Z2 +X44Y-52.999 +G1Z-0.133F500 +Y-51.999Z-0.53F1000 +Y-51.587Z-3.1F500 +Y51.612Z-3.1F1000 +Y52Z-0.777 +Y53Z-0.185 +G0Z2 +X46Y51 +G1Z-0.237F500 +Y50Z-1.195 +Y49.658Z-3.1 +Y-49.631Z-3.1F1000 +Y-49.999Z-0.964 +Y-50.999Z-0.156 +G0Z2 +X48Y-48.999 +G1Z-0.164F500 +Y-48.555Z-3.1 +Y48.564F1000 +Y49Z-0.262 +G0Z2 +X50Y47 +G1Z-0.23F500 +Y46Z-1.106 +Y45.648Z-3.1 +Y-45.636F1000 +Y-45.999Z-1.003 +Y-46.999Z-0.155 +G0Z2 +X52Y-44.999 +G1Z-0.133F500 +Y-43.999Z-0.492F1000 +Y-43.584Z-3.1F500 +Y43.597F1000 +Y44Z-0.63 +Y45Z-0.171 +G0Z2 +X54Y43 +G1Z-0.124F500 +Y42Z-0.295F1000 +Y41.566Z-3.1F500 +Y-41.557Z-3.1F1000 +Y-41.999Z-0.184 +Y-42.999Z-0.1 +G0Z2 +X56Y-39.999 +G1Z-0.121F500 +Y-38.999Z-0.295F1000 +Y-38.566Z-3.1F500 +Y38.577F1000 +Y39Z-0.408 +Y40Z-0.148 +G0Z2 +X58Y37 +G1Z-0.145F500 +Y36Z-0.363F1000 +Y35.573Z-3.1F500 +Y-35.563F1000 +Y-35.999Z-0.265 +Y-36.999Z-0.12 +G0Z2 +X60Y-33.999 +G1Z-0.1F500 +Y-32.999Z-0.153F1000 +Y-32.554Z-3.1F500 +Y31.614Z-3.1F1000 +Y32Z-0.795 +Y33Z-0.203 +Y34Z-0.118 +G0Z2 +X62Y30 +G1Z-0.126F500 +Y29Z-0.191F1000 +Y28Z-0.676 +Y27.602Z-3.1F500 +Y-28.554Z-3.1F1000 +Y-28.999Z-0.153 +Y-29.999Z-0.109 +G0Z2 +X64Y-24.999 +G1Z-0.123F500 +Y-23.999Z-0.163F1000 +Y-23.555Z-3.1F500 +Y22.618Z-3.1F1000 +Y23Z-0.829 +Y24Z-0.221 +Y25Z-0.138 +G0Z2 +X66Y20 +G1Z-0.105F500 +Y19Z-0.135F1000 +Y18Z-0.169 +Y17Z-0.448 +Y16.58Z-3.1F500 +Y-17.554Z-3.1F1000 +Y-17.999Z-0.151 +Y-18.999Z-0.124 +G0Z2 +X68Y-10.999 +G1Z-0.103F500 +Y-9.999Z-0.12F1000 +Y-6.999Z-0.157 +Y-6.554Z-3.1F500 +Y4.592F1000 +Y5Z-0.57 +Y6Z-0.279 +Y7Z-0.173 +Y8Z-0.15 +Y10Z-0.124 +Y11Z-0.108 +G0Z2 +X-68Y6.73 +G1Z-3.1F500 +Y6.133Z-6.1 +Y-4.123F1000 +Y-4.675Z-3.1 +G0Z2 +X-66Y-16.597 +G1Z-3.1F500 +Y-16.108Z-6.1 +Y17.11F1000 +Y17.605Z-3.1 +G0Z2 +X-64Y23.584 +G1Z-3.1F500 +Y23.106Z-6.1 +Y-22.115Z-6.1F1000 +Y-22.635Z-3.1 +G0Z2 +X-62Y-27.61 +G1Z-3.1F500 +Y-27.111Z-6.1 +Y28.1F1000 +Y28.552Z-3.1 +G0Z2 +X-60Y32 +G1Z-6.1F500 +Y-31.112F1000 +Y-31.617Z-3.1 +X-58Y-35.564 +Y-35.102Z-6.1F500 +Y35.104F1000 +Y35.571Z-3.1 +X-56Y38.571 +Y38.104Z-6.1F500 +Y-38.103Z-6.1F1000 +Y-38.567Z-3.1 +G0Z2 +X-54Y-41.552 +G1Z-3.1F500 +Y-41.1Z-6.1 +Y41F1000 +G0Z2 +X-52Y43.59 +G1Z-3.1F500 +Y43.107Z-6.1 +Y-43.107Z-6.1F1000 +Y-43.587Z-3.1 +G0Z2 +X-50Y-45.638 +G1Z-3.1F500 +Y-45.116Z-6.1 +Y45.118F1000 +Y45.648Z-3.1 +G0Z2 +X-48Y48 +G1Z-6.1F500 +Y-47.999F1000 +G0Z2 +X-46Y-49.646 +G1Z-3.1F500 +Y-49.117Z-6.1 +Y49.116F1000 +Y49.639Z-3.1 +G0Z2 +X-44Y51.584 +G1Z-3.1F500 +Y51.106Z-6.1 +Y-51.108F1000 +Y-51.597Z-3.1 +G0Z2 +X-42Y-53.563 +G1Z-3.1F500 +Y-53.102Z-6.1 +Y53.1F1000 +Y53.551Z-3.1 +X-40Y54.609 +Y54.111Z-6.1F500 +Y-54.118Z-6.1F1000 +Y-54.651Z-3.1 +X-38Y-56.56 +Y-56.102Z-6.1F500 +Y56F1000 +G0Z2 +X-36Y57.567 +G1Z-3.1F500 +Y57.103Z-6.1 +Y-57.107F1000 +Y-57.589Z-3.1 +G0Z2 +X-34Y-58.64 +G1Z-3.1F500 +Y-58.116Z-6.1 +Y58.108F1000 +Y58.593Z-3.1 +G0Z2 +X-32Y59.619 +G1Z-3.1F500 +Y59.113Z-6.1 +Y-59.999F1000 +X-30Y-60.999 +Y60.114 +Y60.625Z-3.1 +X-28Y61.615 +Y61.112Z-6.1F500 +Y-61.999Z-6.1F1000 +X-26Y-62.999 +Y62.108 +Y62.593Z-3.1 +G0Z2 +X-24Y63.568 +G1Z-3.1F500 +Y63.103Z-6.1 +Y-63.11Z-6.1F1000 +Y-63.606Z-3.1 +G0Z2 +X-22Y-64.575 +G1Z-3.1F500 +Y-64.104Z-6.1 +Y64.1Z-6.1F1000 +Y64.55Z-3.1 +G0Z2 +X-20Y64.647 +G1Z-3.1F500 +Y64.118Z-6.1 +Y-65.1F1000 +Y-65.55Z-3.1 +X-18Y-65.62 +Y-65.113Z-6.1F500 +Y65.104F1000 +Y65.569Z-3.1 +G0Z2 +X-16Y66 +G1Z-6.1F500 +Y-66.102F1000 +Y-66.56Z-3.1 +G0Z2 +X-14Y-66.632 +G1Z-3.1F500 +Y-66.115Z-6.1 +Y66.104F1000 +Y66.57Z-3.1 +G0Z2 +X-12Y67 +G1Z-6.1F500 +Y-67.101F1000 +Y-67.555Z-3.1 +G0Z2 +X-10Y-67.587 +G1Z-3.1F500 +Y-67.107Z-6.1 +Y67.101Z-6.1F1000 +Y67.553Z-3.1 +G0Z2 +X-8Y67.577 +G1Z-3.1F500 +Y67.105Z-6.1 +Y-67.121F1000 +Y-67.667Z-3.1 +G0Z2 +X-6Y-67.999 +G1Z-6.1F500 +Y67.113F1000 +Y67.619Z-3.1 +G0Z2 +X-4Y68 +G1Z-6.1F500 +Y-68.102F1000 +Y-68.56Z-3.1 +G0Z2 +X-2Y-68.57 +G1Z-3.1F500 +Y-68.103Z-6.1 +Y68F1000 +X0 +Y-68.103 +Y-68.57Z-3.1 +G0Z2 +X2Y-68.568 +G1Z-3.1F500 +Y-68.103Z-6.1 +Y68F1000 +X4 +Y-68.102 +Y-68.562Z-3.1 +G0Z2 +X6Y-67.643 +G1Z-3.1F500 +Y-67.117Z-6.1 +Y68F1000 +G0Z2 +X8Y67.635 +G1Z-3.1F500 +Y67.116Z-6.1 +Y-67.109F1000 +Y-67.599Z-3.1 +X10Y-67.574 +Y-67.104Z-6.1F500 +Y67.106F1000 +Y67.583Z-3.1 +X12Y67.558 +Y67.102Z-6.1F500 +Y-67.101F1000 +Y-67.559Z-3.1 +G0Z2 +X14Y-66.59 +G1Z-3.1F500 +Y-66.107Z-6.1 +Y66.121F1000 +Y66.665Z-3.1 +G0Z2 +X16Y66.58 +G1Z-3.1F500 +Y66.106Z-6.1 +Y-66.102F1000 +Y-66.562Z-3.1 +X18Y-65.588 +Y-65.107Z-6.1F500 +Y65.118Z-6.1F1000 +Y65.65Z-3.1 +X20Y65.574 +Y65.104Z-6.1F500 +Y-64.121F1000 +Y-64.664Z-3.1 +G0Z2 +X22Y-64.569 +G1Z-3.1F500 +Y-64.103Z-6.1 +Y64.109Z-6.1F1000 +Y64.599Z-3.1 +X24Y63.632 +Y63.115Z-6.1F500 +Y-63.106F1000 +Y-63.584Z-3.1 +X26Y-62.606 +Y-62.11Z-6.1F500 +Y63.102F1000 +Y63.563Z-3.1 +X28Y62.567 +Y62.103Z-6.1F500 +Y-61.114F1000 +Y-61.627Z-3.1 +G0Z2 +X30Y-60.635 +G1Z-3.1F500 +Y-60.115Z-6.1 +Y61.103F1000 +Y61.567Z-3.1 +G0Z2 +X32Y60.565 +G1Z-3.1F500 +Y60.103Z-6.1 +Y-59.114F1000 +Y-59.628Z-3.1 +X34Y-58.603 +Y-58.109Z-6.1F500 +Y58.121F1000 +Y58.663Z-3.1 +G0Z2 +X36Y57.608 +G1Z-3.1F500 +Y57.111Z-6.1 +Y-57.105F1000 +Y-57.578Z-3.1 +G0Z2 +X38Y-56.562 +G1Z-3.1F500 +Y-56.102Z-6.1 +Y56.105F1000 +Y56.579Z-3.1 +X40Y54.668 +Y54.122Z-6.1F500 +Y-54.111F1000 +Y-54.613Z-3.1 +G0Z2 +X42Y-53.563 +G1Z-3.1F500 +Y-53.102Z-6.1 +Y53.106F1000 +Y53.581Z-3.1 +G0Z2 +X44Y51.612 +G1Z-3.1F500 +Y51.111Z-6.1 +Y-51.107F1000 +Y-51.587Z-3.1 +X46Y-49.631 +Y-49.115Z-6.1F500 +Y49.12Z-6.1F1000 +Y49.658Z-3.1 +X48Y48.564 +Y48.103Z-6.1F500 +Y-48.101F1000 +Y-48.555Z-3.1 +X50Y-45.636 +Y-45.115Z-6.1F500 +Y45.118F1000 +Y45.648Z-3.1 +X52Y43.597 +Y43.109Z-6.1F500 +Y-43.106F1000 +Y-43.584Z-3.1 +X54Y-41.557 +Y-41.101Z-6.1F500 +Y41.103F1000 +Y41.566Z-3.1 +X56Y38.577 +Y38.105Z-6.1F500 +Y-38.103F1000 +Y-38.566Z-3.1 +G0Z2 +X58Y-35.563 +G1Z-3.1F500 +Y-35.102Z-6.1 +Y35.104F1000 +Y35.573Z-3.1 +X60Y31.614 +Y31.112Z-6.1F500 +Y-32.101F1000 +Y-32.554Z-3.1 +X62Y-28.554 +Y-28.101Z-6.1F500 +Y27.11F1000 +Y27.602Z-3.1 +G0Z2 +X64Y22.618 +G1Z-3.1F500 +Y22.112Z-6.1 +Y-23.101F1000 +Y-23.555Z-3.1 +G0Z2 +X66Y-17.554 +G1Z-3.1F500 +Y-17.1Z-6.1 +Y16.106F1000 +Y16.58Z-3.1 +G0Z2 +X68Y4.592 +G1Z-3.1F500 +Y4.108Z-6.1 +Y-6.101F1000 +Y-6.554Z-3.1 +G0Z2 +X-68Y-4.123 +G1Z-6.1F500 +Y-3.999Z-6.769 +Y6F1000 +Y6.133Z-6.1 +G0Z2 +X-66Y17.11 +G1Z-6.1F500 +Y17Z-6.769 +Y-15.999F1000 +Y-16.108Z-6.1 +G0Z2 +X-64Y-22.115 +G1Z-6.1F500 +Y-21.999Z-6.769 +Y23F1000 +Y23.106Z-6.1 +G0Z2 +X-62Y28.1 +G1Z-6.1F500 +Y28Z-6.769 +Y-26.999F1000 +Y-27.111Z-6.1 +X-60Y-31.112 +Y-30.999Z-6.769F500 +Y32F1000 +G0Z2 +X-58Y35.104 +G1Z-6.1F500 +Y35Z-6.769 +Y-34.999F1000 +Y-35.102Z-6.1 +X-56Y-38.103 +Y-37.999Z-6.769F500 +Y38F1000 +Y38.104Z-6.1 +G0Z2 +X-54Y41 +G1Z-6.769F500 +Y-40.999F1000 +Y-41.1Z-6.1 +X-52Y-43.107 +Y-42.999Z-6.769F500 +Y43F1000 +Y43.107Z-6.1 +G0Z2 +X-50Y45.118 +G1Z-6.1F500 +Y45Z-6.769 +Y-44.999F1000 +Y-45.116Z-6.1 +G0Z2 +X-48Y-47.999 +G1Z-6.769F500 +Y48F1000 +G0Z2 +X-46Y49.116 +G1Z-6.1F500 +Y49Z-6.769 +Y-48.999F1000 +Y-49.117Z-6.1 +X-44Y-51.108 +Y-50.999Z-6.769F500 +Y51F1000 +Y51.106Z-6.1 +X-42Y53.1 +Y53Z-6.769F500 +Y-52.999F1000 +Y-53.102Z-6.1 +X-40Y-54.118 +Y-53.999Z-6.769F500 +Y54F1000 +Y54.111Z-6.1 +G0Z2 +X-38Y56 +G1Z-6.769F500 +Y-55.999F1000 +Y-56.102Z-6.1 +X-36Y-57.107 +Y-56.999Z-6.769F500 +Y57F1000 +Y57.103Z-6.1 +X-34Y58.108 +Y58Z-6.769F500 +Y-57.999F1000 +Y-58.116Z-6.1 +G0Z2 +X-32Y-59.999 +G1Z-6.769F500 +Y59F1000 +Y59.113Z-6.1 +X-30Y60.114 +Y60Z-6.769F500 +Y-60.999F1000 +X-28Y-61.999 +Y61 +Y61.112Z-6.1 +G0Z2 +X-26Y62.108 +G1Z-6.1F500 +Y62Z-6.769 +Y-62.999F1000 +G0Z2 +X-24Y-63.11 +G1Z-6.1F500 +Y-62.999Z-6.769 +Y63F1000 +Y63.103Z-6.1 +G0Z2 +X-22Y64.1 +G1Z-6.1F500 +Y64Z-6.769 +Y-63.999F1000 +Y-64.104Z-6.1 +G0Z2 +X-20Y-65.1 +G1Z-6.1F500 +Y-64.999Z-6.769 +Y64F1000 +Y64.118Z-6.1 +X-18Y65.104 +Y65Z-6.769F500 +Y-64.999F1000 +Y-65.113Z-6.1 +X-16Y-66.102 +Y-65.999Z-6.769F500 +Y66F1000 +G0Z2 +X-14Y66.104 +G1Z-6.1F500 +Y66Z-6.769 +Y-65.999F1000 +Y-66.115Z-6.1 +X-12Y-67.101 +Y-66.999Z-6.769F500 +Y67F1000 +G0Z2 +X-10Y67.101 +G1Z-6.1F500 +Y67Z-6.769 +Y-66.999F1000 +Y-67.107Z-6.1 +G0Z2 +X-8Y-67.121 +G1Z-6.1F500 +Y-66.999Z-6.769 +Y67F1000 +Y67.105Z-6.1 +X-6Y67.113 +Y67Z-6.769F500 +Y-67.999F1000 +G0Z2 +X-4Y-68.102 +G1Z-6.1F500 +Y-67.999Z-6.769 +Y68F1000 +X-2 +Y-67.999 +Y-68.103Z-6.1 +X0Y-68.103 +Y-67.999Z-6.769F500 +Y68F1000 +X2 +Y-67.999 +Y-68.103Z-6.1 +X4Y-68.102 +Y-67.999Z-6.769F500 +Y68F1000 +X6 +Y-66.999 +Y-67.117Z-6.1 +X8Y-67.109 +Y-66.999Z-6.769F500 +Y67F1000 +Y67.116Z-6.1 +X10Y67.106 +Y67Z-6.769F500 +Y-66.999F1000 +Y-67.104Z-6.1 +X12Y-67.101 +Y-66.999Z-6.769F500 +Y67F1000 +Y67.102Z-6.1 +X14Y66.121 +Y66Z-6.769F500 +Y-65.999F1000 +Y-66.107Z-6.1 +X16Y-66.102 +Y-65.999Z-6.769F500 +Y66F1000 +Y66.106Z-6.1 +X18Y65.118 +Y65Z-6.769F500 +Y-64.999F1000 +Y-65.107Z-6.1 +G0Z2 +X20Y-64.121 +G1Z-6.1F500 +Y-63.999Z-6.769 +Y65F1000 +Y65.104Z-6.1 +X22Y64.109 +Y64Z-6.769F500 +Y-63.999F1000 +Y-64.103Z-6.1 +G0Z2 +X24Y-63.106 +G1Z-6.1F500 +Y-62.999Z-6.769 +Y63F1000 +Y63.115Z-6.1 +X26Y63.102 +Y63Z-6.769F500 +Y-61.999F1000 +Y-62.11Z-6.1 +X28Y-61.114 +Y-60.999Z-6.769F500 +Y62F1000 +Y62.103Z-6.1 +X30Y61.103 +Y61Z-6.769F500 +Y-59.999F1000 +Y-60.115Z-6.1 +X32Y-59.114 +Y-58.999Z-6.769F500 +Y60F1000 +Y60.103Z-6.1 +X34Y58.121 +Y58Z-6.769F500 +Y-57.999F1000 +Y-58.109Z-6.1 +X36Y-57.105 +Y-56.999Z-6.769F500 +Y57F1000 +Y57.111Z-6.1 +X38Y56.105 +Y56Z-6.769F500 +Y-55.999F1000 +Y-56.102Z-6.1 +X40Y-54.111 +Y-53.999Z-6.769F500 +Y54F1000 +Y54.122Z-6.1 +X42Y53.106 +Y53Z-6.769F500 +Y-52.999F1000 +Y-53.102Z-6.1 +X44Y-51.107 +Y-50.999Z-6.769F500 +Y51F1000 +Y51.111Z-6.1 +X46Y49.12 +Y49Z-6.769F500 +Y-48.999F1000 +Y-49.115Z-6.1 +G0Z2 +X48Y-48.101 +G1Z-6.1F500 +Y-47.999Z-6.769 +Y48F1000 +Y48.103Z-6.1 +X50Y45.118 +Y45Z-6.769F500 +Y-44.999F1000 +Y-45.115Z-6.1 +X52Y-43.106 +Y-42.999Z-6.769F500 +Y43F1000 +Y43.109Z-6.1 +X54Y41.103 +Y41Z-6.769F500 +Y-40.999F1000 +Y-41.101Z-6.1 +X56Y-38.103 +Y-37.999Z-6.769F500 +Y38F1000 +Y38.105Z-6.1 +X58Y35.104 +Y35Z-6.769F500 +Y-34.999F1000 +Y-35.102Z-6.1 +X60Y-32.101 +Y-31.999Z-6.769F500 +Y31F1000 +Y31.112Z-6.1 +X62Y27.11 +Y27Z-6.769F500 +Y-27.999F1000 +Y-28.101Z-6.1 +G0Z2 +X64Y-23.101 +G1Z-6.1F500 +Y-22.999Z-6.769 +Y22F1000 +Y22.112Z-6.1 +G0Z2 +X66Y16.106 +G1Z-6.1F500 +Y16Z-6.769 +Y-16.999F1000 +Y-17.1Z-6.1 +G0Z2 +X68Y-6.101 +G1Z-6.1F500 +Y-5.999Z-6.769 +Y4F1000 +Y4.108Z-6.1 +G0Z2 + diff --git a/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel.gcode b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_OCL.gcode similarity index 98% rename from scripts/addons/cam/tests/test_data/parallel/_Op_Parallel.gcode rename to scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_OCL.gcode index 38f7aec3..14afd98a 100644 --- a/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel.gcode +++ b/scripts/addons/cam/tests/test_data/parallel/_Op_Parallel_OCL.gcode @@ -1,4 +1,4 @@ -(Created with grbl post processor 2023/07/06 16:58) +(Created with grbl post processor 2024/01/11 09:36) G21 (G-code generated with BlenderCAM and NC library) G17G90 diff --git a/scripts/addons/cam/tests/test_data/parallel/parallel.blend b/scripts/addons/cam/tests/test_data/parallel/parallel.blend index 4e1d29b2..38efdf88 100644 Binary files a/scripts/addons/cam/tests/test_data/parallel/parallel.blend and b/scripts/addons/cam/tests/test_data/parallel/parallel.blend differ diff --git a/scripts/addons/cam/tests/test_suite.py b/scripts/addons/cam/tests/test_suite.py index fb77f02b..ba3a96f7 100644 --- a/scripts/addons/cam/tests/test_suite.py +++ b/scripts/addons/cam/tests/test_suite.py @@ -64,14 +64,11 @@ class BlenderCAMTest(unittest.TestCase): # Compare the generated and expected gcode for each operation for gcode_file in test_case['gcode_files']: with self.subTest(operation=f"{test_case['subdir_name']}/{gcode_file}"): - try: - generated = self.get_gcode_from_file(gcode_file[1:]) - expected = self.get_gcode_from_file(gcode_file) - self.assertMultiLineEqual(generated, expected, - msg = "\n"+self.get_diff(gcode_file[1:], gcode_file)) - finally: - if os.getenv("CI")!='true': # Cleanup generated file unless on CI, in which case leave it for analysis - os.remove(gcode_file[1:]) + generated = self.get_gcode_from_file(gcode_file[1:]) + expected = self.get_gcode_from_file(gcode_file) + self.assertMultiLineEqual(generated, expected, + msg = "\n"+self.get_diff(gcode_file[1:], gcode_file)) + os.remove(gcode_file[1:]) # cleanup generated file unless test fails if __name__ == '__main__': # Add a test method for each test case to the TestCase class diff --git a/scripts/addons/cam/utils.py b/scripts/addons/cam/utils.py index c3255555..2f3a1d69 100644 --- a/scripts/addons/cam/utils.py +++ b/scripts/addons/cam/utils.py @@ -410,7 +410,7 @@ async def sampleChunks(o, pathSamples, layers): if o.optimisation.use_exact: # prepare collision world if o.optimisation.use_opencamlib: - oclSample(o, pathSamples) + await oclSample(o, pathSamples) cutterdepth = 0 else: if o.update_bullet_collision_tag: @@ -993,7 +993,7 @@ def overlaps(bb1, bb2): # true if bb1 is child of bb2 return True -def connectChunksLow(chunks, o): +async def connectChunksLow(chunks, o): """ connects chunks that are close to each other without lifting, sampling them 'low' """ if not o.movement.stay_low or (o.strategy == 'CARVE' and o.carve_depth > 0): return chunks @@ -1043,7 +1043,7 @@ def connectChunksLow(chunks, o): pos = lastch.points[-1] if o.optimisation.use_opencamlib and o.optimisation.use_exact and o.strategy != 'CUTOUT' and o.strategy != 'POCKET': - oclResampleChunks(o, chunks_to_resample) + await oclResampleChunks(o, chunks_to_resample,use_cached_mesh=True) return connectedchunks @@ -1127,7 +1127,7 @@ async def sortChunks(chunks, o): if o.strategy != 'DRILL' and o.strategy != 'OUTLINEFILL': # THIS SHOULD AVOID ACTUALLY MOST STRATEGIES, THIS SHOULD BE DONE MANUALLY, # BECAUSE SOME STRATEGIES GET SORTED TWICE. - sortedchunks = connectChunksLow(sortedchunks, o) + sortedchunks = await connectChunksLow(sortedchunks, o) return sortedchunks diff --git a/scripts/addons/cam/version.py b/scripts/addons/cam/version.py new file mode 100644 index 00000000..cd1715d3 --- /dev/null +++ b/scripts/addons/cam/version.py @@ -0,0 +1 @@ +__version__=(0,9,3) \ No newline at end of file