Merge pull request #2 from joemarshall/actions

Actions
pull/254/head
Joe Marshall 2024-01-11 15:26:17 +00:00 zatwierdzone przez GitHub
commit 78c50efc46
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 2145 dodań i 62 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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 }

Wyświetl plik

@ -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"}

Wyświetl plik

@ -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"""

Wyświetl plik

@ -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")

Wyświetl plik

@ -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)

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

@ -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 = []

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1 @@
__version__=(0,9,3)