kopia lustrzana https://github.com/vilemduha/blendercam
commit
78c50efc46
|
@ -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
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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"}
|
||||
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
@ -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
|
||||
|
Plik diff jest za duży
Load Diff
|
@ -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
|
Plik binarny nie jest wyświetlany.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__version__=(0,9,3)
|
Ładowanie…
Reference in New Issue