diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..87097b35 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +matrix/debs/* +matrix/build_matrix.py +matrix/Dockerfile diff --git a/.github/workflows/debs.yml b/.github/workflows/debs.yml new file mode 100644 index 00000000..cc16ffac --- /dev/null +++ b/.github/workflows/debs.yml @@ -0,0 +1,47 @@ +name: Debian Packages + +on: + push: + tags: + - '*-release' + +permissions: + contents: read + +jobs: + debs: + name: Build Debian Packages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build Debian Packages + run: make debs + - name: Upload Debian Packages + uses: actions/upload-artifact@v4 + with: + name: packages-debian + path: matrix/debs + + release: + permissions: + contents: write # for actions/create-release + name: Create GitHub Release + needs: [debs] + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Download Debian Packages + uses: actions/download-artifact@v4 + with: + pattern: packages-* + merge-multiple: true + path: ./dist + - name: Create Release + id: create_release + uses: ncipollo/release-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + body: ${{ github.event.head_commit.message }} + artifacts: ./dist/*.deb diff --git a/Makefile b/Makefile index d3d664ff..fe045fe9 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,7 @@ all: clean: scons -C cbang -c scons -c + +# build debian packages in docker images +debs: + python matrix/build_matrix.py diff --git a/README.md b/README.md index 7970385f..3824ea0b 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,13 @@ by C!, can be installed with the following command line: sudo apt-get update sudo apt-get -y install scons build-essential libqt5websockets5-dev \ - libqt5opengl5-dev libnode-dev libglu1-mesa-dev pkgconf git + libqt5opengl5-dev qttools5-dev-tools libnode-dev libglu1-mesa-dev \ + pkgconf git ## Building C! (cbang) Clone the C! git repository, build the software using scons and set the environment variable CBANG_HOME so the CAMotics build system can find it -later. **You must install V8 or ChakraCore before this step.** +later. **You must install V8 before this step.** git clone https://github.com/CauldronDevelopmentLLC/cbang.git scons -C cbang diff --git a/SConstruct b/SConstruct index b70d75ae..64cfb0bb 100644 --- a/SConstruct +++ b/SConstruct @@ -1,4 +1,7 @@ -import os, sys, json +import os +import sys +import json +import subprocess # local cbang if not os.environ.get('CBANG_HOME'): os.environ['CBANG_HOME'] = './cbang' @@ -8,6 +11,20 @@ cbang = os.environ.get('CBANG_HOME') with open('package.json', 'r') as f: pkg_meta = json.load(f) version = pkg_meta['version'] +# Debian Distro Code + +try: + # if we're on debian get the distro code, i.e. `noble`, `trixie` + distro_code = subprocess.check_output( + ['lsb_release', '-cs']).decode().strip().lower() +except BaseException as E: + print(f"Not on Debian or no `apt install lsb-release: `{E}`") + distro_code = None + +# True, except on newer debian with the libnode-dev issue +default_tpl = distro_code not in {'plucky', 'trixie'} + + # Setup env = Environment(ENV = os.environ, TARGET_ARCH = os.environ.get('TARGET_ARCH', 'x86')) @@ -19,10 +36,9 @@ env.CBAddVariables( ('install_prefix', 'Installation directory prefix', '/usr/local/'), BoolVariable('qt_deps', 'Enable Qt package dependencies', True), ('python_version', 'Set python version', '3'), - BoolVariable('with_tpl', 'Enable TPL', True), + BoolVariable('with_tpl', 'Enable TPL', default_tpl), BoolVariable('with_gui', 'Enable graphical user interface', True), - BoolVariable('wrap_glibc', 'Enable GlibC function wrapping', - env['PLATFORM'] == 'posix'), + BoolVariable('wrap_glibc', 'Enable GlibC function wrapping', False) ) conf = env.CBConfigure() @@ -70,14 +86,12 @@ if not env.GetOption('clean'): conf.CBConfig('cbang') env.CBDefine('USING_CBANG') # Using CBANG macro namespace - for lib in 'mariadbclient snappy leveldb yaml re2 sqlite3'.split(): + for lib in 'mariadbclient snappy leveldb yaml sqlite3'.split(): if lib in env['LIBS']: env['LIBS'].remove(lib) # Include path env.AppendUnique(CPPPATH = ['#/src']) - if env['PLATFORM'] != 'win32': env.AppendUnique(CCFLAGS = ['-fPIC']) - # Python have_python = conf.CBConfig('python', False) @@ -176,8 +190,8 @@ if env['with_tpl']: # DXFlib if not have_dxflib: - libDXFlib = SConscript('src/dxflib/SConscript', - variant_dir = 'build/dxflib') + libDXFlib = SConscript( + 'src/dxflib/SConscript', variant_dir = 'build/dxflib') env.Append(LIBS = libDXFlib) @@ -346,7 +360,6 @@ material or breaking tools.''' # Package if 'package' in COMMAND_LINE_TARGETS: - import subprocess # Examples examples = [] @@ -356,6 +369,9 @@ if 'package' in COMMAND_LINE_TARGETS: if isinstance(examples, bytes): examples = examples.decode() examples = list(map(lambda x: [x, x], examples.split())) + + + # Machines machines = [] cmd = 'git ls-files machines/' @@ -377,13 +393,42 @@ if 'package' in COMMAND_LINE_TARGETS: install_files = [] if env.get('qt_deps'): - qt_pkgs = ', libqt5core5a, libqt5gui5, libqt5opengl5, libqt5websockets5' + + # debian distros keep renaming the qt packages + qt_lookup = {'noble': ['libqt5core5t64', # Ubuntu 24.04 + 'libqt5gui5t64', + 'libqt5opengl5t64', + 'libqt5websockets5'], + 'jammy': ['libqt5core5a', # Ubuntu 22.04 + 'libqt5gui5', + 'libqt5opengl5', + 'libqt5websockets5']} + # use exact versions for the other distros + qt_lookup['plucky'] = qt_lookup['noble'] + qt_lookup['trixie'] = qt_lookup['noble'] + qt_lookup['bookworm'] = qt_lookup['jammy'] + qt_lookup['buster'] = qt_lookup['jammy'] + + if distro_code in qt_lookup: + qt_pkgs = qt_lookup[distro_code] + else: + # produce a generic requirements list using the OR requirement, i.e. + # i.e. `['libqt5core5a|libqt5core5t64', ...]` + # note that this logic requires `qt_lookup` values to all have the same + # length and correspond with each other, and if one package is dropped + # a `None` placeholder must be added to the list to keep the correspondence + qt_values = list(qt_lookup.values()) + qt_pkgs = ['|'.join(set(v[i] for v in qt_values).difference({None})) + for i in range(len(qt_values[0]))] + + if env['PLATFORM'] == 'win32': import shutil try: shutil.rmtree('build/win32') - except: pass + except: + pass cmd = [env['QTDIR'] + '\\bin\\windeployqt.exe', '--dir', 'build\\win32', '--no-system-d3d-compiler', '--no-opengl-sw', @@ -397,7 +442,40 @@ if 'package' in COMMAND_LINE_TARGETS: env['VCREDIST'] = name install_files.append('build\\win32\\' + name) - else: qt_pkgs = '' + else: + qt_pkgs = [] + + + if env['with_tpl']: + # this should provide v8 + tpl_pkgs = ['libnode-dev'] + else: + tpl_pkgs = [] + + # SSL packages for various distros + # these also keep changing names + ssl_lookup = {'noble': 'libssl3t64', + 'plucky': 'libssl3t64', + 'jammy': 'libssl3', + 'trixie': 'libssl3t64', + 'bookworm': 'libssl3', + 'buster': 'libssl1.1'} + if distro_code in ssl_lookup: + ssl_pkg = ssl_lookup[distro_code] + else: + # set as an OR of all the unique possible packages + ssl_pkg = '|'.join(set(ssl_lookup.values())) + + # base deps that work across all distros and don't need any logic + deb_depends = ['debconf', 'libc6', 'libglu1', 'libglu1-mesa'] + + # append the platform-dependant packages + deb_depends.append(ssl_pkg) + deb_depends.extend(qt_pkgs) + deb_depends.extend(tpl_pkgs) + + # flatten into a comma delimited string + deb_depends = ','.join(deb_depends) pkg = env.Packager( 'CAMotics', @@ -408,7 +486,7 @@ if 'package' in COMMAND_LINE_TARGETS: license = 'COPYING', bug_url = 'https://github.com/CauldronDevelopmentLLC/CAMotics/issues/', summary = 'Open-Source Simulation & Computer Aided Machining', - description = description, + description = description + '\n\n' + "Package compiled on distro `%s`" % distro_code, prefix = '/usr', icons = ('osx/camotics.icns', 'images/camotics.png'), mime = [['mime.xml', 'camotics.xml']], @@ -428,16 +506,13 @@ if 'package' in COMMAND_LINE_TARGETS: deb_directory = 'debian', deb_section = 'miscellaneous', - deb_depends = - 'debconf | debconf-2.0, libc6, libglu1, ' + - 'libv8-3.14.5 | libv8-dev | libnode-dev, ' + - 'libglu1-mesa, libssl1.1' + qt_pkgs, + deb_depends = deb_depends, deb_priority = 'optional', deb_replaces = 'openscam', rpm_license = 'GPLv2+', rpm_group = 'Applications/Engineering', - rpm_requires = 'expat' + qt_pkgs, + rpm_requires = 'expat' + ','.join(qt_pkgs), rpm_obsoletes = 'openscam', app_id = 'org.camotics.CAMotics', diff --git a/debian/camotics.docs b/debian/camotics.docs new file mode 100644 index 00000000..2fb80d18 --- /dev/null +++ b/debian/camotics.docs @@ -0,0 +1 @@ +usr/share/doc/camotics/README.md diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 45a4fb75..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..8898bde9 --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: camotics +Maintainer: Joseph Coffland +Section: science +Priority: optional +Standards-Version: 4.7.0 +Homepage: https://camotics.org/ +Build-Depends: debhelper-compat (= 13), scons, libcbang0-dev + +Package: camotics +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: 3-axis numerical control machining simulator + CAMotics is an Open-Source software which can simulate 3-axis NC + machining. It is a fast, flexible and user-friendly simulation + software for the DIY and Open-Source community. CAMotics works on + Linux, OS-X and Windows. diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..9239f5b2 --- /dev/null +++ b/debian/rules @@ -0,0 +1,31 @@ +#!/usr/bin/make -f +export DH_VERBOSE = 1 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + +# link to libatomic on armel and mipsel +ifneq (,$(filter $(DEB_HOST_ARCH), armel mipsel)) + export DEB_LDFLAGS_MAINT_APPEND += -Wl,--no-as-needed -latomic -Wl,--as-needed +endif + +include /usr/share/dpkg/default.mk # provides DEB_VERSION + +SCONS_OPTIONS = cycles=0 mode=release sharedlib=1 -j8 werror=0 clang=1 + +%: + dh $@ + +override_dh_auto_clean: + scons -c + find . -name __pycache__|xargs rm -rf + rm -rf .sconf_temp config.log + rm -rf .sconsign.dblite + +override_dh_auto_build: + scons $(SCONS_OPTIONS) --jobs=$(NUMJOBS) --no-cache + +override_dh_usrlocal: + true + +override_dh_auto_install: + PREFIX=/usr scons prefix=debian/camotics/usr $(SCONS_OPTIONS) install diff --git a/matrix/Dockerfile b/matrix/Dockerfile new file mode 100644 index 00000000..762c1e47 --- /dev/null +++ b/matrix/Dockerfile @@ -0,0 +1,77 @@ +# a debian based image, i.e. Ubuntu +# arg set to scratch so it will fail immediately if the build arg is not set +ARG IMAGE="scratch" +FROM ${IMAGE} AS base + +# never ask questions in an apt-get install +ENV DEBIAN_FRONTEND=noninteractive + +########################################### +FROM base AS build + +# required apt packages which may be slightly different +# on different flavors of debian +ARG DEPS="" + +RUN apt-get update && \ + apt-get install -y $DEPS + +# use /root for checkouts +WORKDIR /root + +############################################ +# clone and build cbang +RUN git clone --depth=1 https://github.com/CauldronDevelopmentLLC/cbang.git +RUN cd cbang && \ + git checkout d4dd5f52b0d5ee499ec5683f5930b01fdb24884b +# `v8` is provided by libnode-dev +RUN scons -C cbang v8_compress_pointers=false +# assign the environment variable for cbang +ENV CBANG_HOME=/root/cbang + +################################################# +# copy the current checkout of camotics into the working directory +# note that this requires that the docker build context is the root of +# the camotics repo i.e. `docker build -f matrix/Dockerfile .` +COPY . CAMotics + +# set our working directory to the camotics checkout +WORKDIR /root/CAMotics + +# build the executable for camotics +RUN scons + +# package the deb +RUN scons package + +################################# +# test the debian in an image without the build dependencies +# to make sure that we listed the install dependencies correctly +FROM base AS test + +# copy our built package +COPY --from=build /root/CAMotics/camotics*.deb . + +# if the deb is not installing cleanly this debug info is helpful: +# RUN apt-get update && apt-get install aptitude -y && \ +# apt show camotics && aptitude why-not camotics || true + +# this should resolve the missing dependencies if we listed them correctly +# if we listed them incorrectly it will remove camotics +RUN apt-get update && apt install --no-install-recommends -y ./*.deb + +# this simple smoke test shouldn't crash +RUN camotics --version + +# now that we've passed the smoke test rename the deb +# apply the distro information to the deb, i.e. `ubuntu-20.04` +COPY ./matrix/rename.py . +# TODO : should this be in the `debian/control` info? +RUN apt-get install python3 lsb-release -y && python3 rename.py + +######################### +# copy the deb into a scratch image so we can eject it in the build command +FROM scratch + +# copy renamed binary from test stage as our output +COPY --from=test camotics*.deb . diff --git a/matrix/build_matrix.py b/matrix/build_matrix.py new file mode 100644 index 00000000..32e8c591 --- /dev/null +++ b/matrix/build_matrix.py @@ -0,0 +1,75 @@ +import os +import subprocess + +# directory of this script +pwd = os.path.abspath(os.path.expanduser(os.path.dirname(__file__))) +# directory of camotics root +root = os.path.abspath(os.path.join(pwd, "..")) +# location of dockerfile +dockerfile = os.path.join(pwd, "Dockerfile") + +# where to save generated `.deb` packages +results = os.path.join(pwd, "debs") +os.makedirs(results, exist_ok=True) + + +# the packages required to build CAMotics on Debian. +build_deps = { + "build-essential", + "ca-certificates", + "fakeroot", + "git", + "libglu1-mesa-dev", + "libnode-dev", + "libqt5opengl5-dev", + "libqt5websockets5-dev", + "ninja-build", + "pkgconf", + "python3", + "python3-six", + "python3-setuptools", + "qttools5-dev-tools", + "lsb-release", + "scons", + "sudo", +} + +# keyed as docker image : build deps +images = { + "ubuntu:25.04": build_deps, # plucky : TODO : cbang can't find v8.h despite installing libnode-dev + "ubuntu:24.04": build_deps, # noble + "ubuntu:22.04": build_deps, # jammy + "debian:trixie": build_deps, # : TODO : same issue as plucky + "debian:bookworm": build_deps, + "debian:bullseye": build_deps, +} + +# debugging: test with just one image +# k = "debian:trixie" +# images = {k: images[k]} + +if __name__ == "__main__": + for image, deps in images.items(): + # build the dockerfile with fully specified paths + command = [ + "docker", + "build", + "--progress", + "plain", + "--build-arg", + f"IMAGE={image}", + "--build-arg", + f"DEPS={' '.join(deps)}", + "--output", + results, + "-f", + dockerfile, + root, + ] + + print(f"attempting to build: `{image}`") + print(f"calling with: `{' '.join(command)}`") + + # to accept partial results or not change between: + # `subprocess.call` <-> `subprocess.check_call` + subprocess.check_call(command) diff --git a/matrix/rename.py b/matrix/rename.py new file mode 100644 index 00000000..5f34062a --- /dev/null +++ b/matrix/rename.py @@ -0,0 +1,46 @@ +import os +import subprocess + +cwd = os.path.abspath(os.path.expanduser(os.path.dirname(__file__))) + + +def distro_string(): + """ + Produce a label for the current flavor and version of debian + that looks like `ubuntu-22.04` or `debian-12.0`. + + There is probably a "debianic" way to do this, but I don't know it. + And we need the deb files to be named something different so they + don't overwrite each other when we build them. + + Returns + ------- + distro + The distribution name and version, e.g. `ubuntu-22.04` + """ + # i.e. `ubuntu` + distrib = subprocess.check_output(["lsb_release", "-is"]).decode().lower().strip() + # i.e. `22.04` + # if you wanted this to be like `noble` or `jessie` switch the `-rs` to `-cs` + version = subprocess.check_output(["lsb_release", "-rs"]).decode().lower().strip() + # i.e. `trixie`, `plucky`, etc + code = subprocess.check_output(["lsb_release", "-cs"]).decode().lower().strip() + + # the version may be `n/a` + result = "-".join( + c for c in [distrib, version, code] if len(c) > 0 and "/" not in c + ) + + return result + + +if __name__ == "__main__": + # get the first deb in this directory + name = next(n for n in os.listdir(cwd) if n.endswith(".deb")) + + distro = distro_string() + + if distro not in name: + name_new = f"{name[:-4]}_{distro}.deb" + os.rename(os.path.join(cwd, name), os.path.join(cwd, name_new)) + print(f"renaming `{name}` -> `{name_new}`") diff --git a/scripts/build b/scripts/build old mode 100755 new mode 100644 diff --git a/src/cairo/SConscript b/src/cairo/SConscript index f6966622..4c7886fd 100644 --- a/src/cairo/SConscript +++ b/src/cairo/SConscript @@ -1,21 +1,22 @@ Import('*') env = env.Clone() -if env['compiler_mode'] == 'gnu': - env.AppendUnique(CCFLAGS = ['-Wno-enum-conversion']) +if not env.GetOption('clean'): + if env['compiler_mode'] == 'gnu': + env.AppendUnique(CCFLAGS = ['-Wno-enum-conversion']) -# Ignore warnings -import re -flags = env.subst('${CCFLAGS}') -flags = re.sub(r'-W((all)|(error))(=[^\s$]+)?(\s|$)', '', flags) -env.Replace(CCFLAGS = flags) + # Ignore warnings + import re + flags = env.subst('${CCFLAGS}') + flags = re.sub(r'-W((all)|(error))(=[^\s$]+)?(\s|$)', '', flags) + env.Replace(CCFLAGS = flags) -# Configure -env.AppendUnique(CPPDEFINES = [ - 'CAIRO_NO_MUTEX', 'HAVE_INTTYPES_H', 'CAIRO_HAS_IMAGE_SURFACE']) -env.Append(CPPPATH = ['#/src/cairo']) + # Configure + env.AppendUnique(CPPDEFINES = [ + 'CAIRO_NO_MUTEX', 'HAVE_INTTYPES_H', 'CAIRO_HAS_IMAGE_SURFACE']) + env.Append(CPPPATH = ['#/src/cairo']) # Bulid library diff --git a/src/camotics/contour/TriangleSurface.cpp b/src/camotics/contour/TriangleSurface.cpp index 2cfc3f1f..8b4fb818 100644 --- a/src/camotics/contour/TriangleSurface.cpp +++ b/src/camotics/contour/TriangleSurface.cpp @@ -188,10 +188,9 @@ void TriangleSurface::read(const JSON::Value &value) { if (value.hasList("vertices")) { vertices.clear(); bounds = Rectangle3D(); - auto &l = value.get("vertices"); - for (unsigned i = 0; i < l->size(); i++) { - vertices.push_back(l->getNumber(i)); + for (auto &vert: *value.get("vertices")) { + vertices.push_back(vert->getNumber()); unsigned n = vertices.size(); if (n % 3 == 0) diff --git a/src/camotics/machine/MachineModel.cpp b/src/camotics/machine/MachineModel.cpp index 3857f280..c7fb1ed4 100644 --- a/src/camotics/machine/MachineModel.cpp +++ b/src/camotics/machine/MachineModel.cpp @@ -40,8 +40,8 @@ void MachineModel::read(const JSON::Value &value) { workpiece.read(value.getList("workpiece")); auto &parts = value.getDict("parts"); - for (unsigned i = 0; i < parts.size(); i++) - add(new MachinePart(parts.keyAt(i), parts.get(i))); + for (auto e: parts.entries()) + add(new MachinePart(e.key(), e.value())); } diff --git a/src/camotics/machine/MachinePart.cpp b/src/camotics/machine/MachinePart.cpp index 80176fe6..29da4177 100644 --- a/src/camotics/machine/MachinePart.cpp +++ b/src/camotics/machine/MachinePart.cpp @@ -30,17 +30,17 @@ MachinePart::MachinePart(const string &name, const JSON::ValuePtr &config) : void MachinePart::read(const JSON::Value &value) { - color.read(value.getList("color")); - init.read(value.getList("init")); - home.read(value.getList("home")); - min.read(value.getList("min")); - max.read(value.getList("max")); + color .read(value.getList("color")); + init .read(value.getList("init")); + home .read(value.getList("home")); + min .read(value.getList("min")); + max .read(value.getList("max")); movement.read(value.getList("movement")); if (value.hasList("lines")) { auto &lines = value.getList("lines"); - for (unsigned i = 0; i < lines.size(); i++) - this->lines.push_back(lines.getNumber(i)); + for (auto &line: lines) + this->lines.push_back(line->getNumber()); } auto &vertices = value.getList("mesh"); diff --git a/src/camotics/project/Files.cpp b/src/camotics/project/Files.cpp index 14587edc..b271ebeb 100644 --- a/src/camotics/project/Files.cpp +++ b/src/camotics/project/Files.cpp @@ -43,8 +43,8 @@ string Files::getRelativePath(unsigned i) const { SmartPointer Files::find(const string &_path) const { string path = SystemUtilities::absolute(directory, _path); - for (unsigned i = 0; i < size(); i++) - if (path == files[i]->getPath()) return files[i]; + for (auto &file: files) + if (path == file->getPath()) return file; return 0; } @@ -56,16 +56,16 @@ void Files::add(const string &path) { void Files::read(const JSON::Value &value) { - for (unsigned i = 0; i < value.size(); i++) - add(SystemUtilities::absolute(directory, value.getString(i))); + for (auto v: value) + add(SystemUtilities::absolute(directory, v->getString())); } void Files::write(JSON::Sink &sink) const { sink.beginList(); - for (unsigned i = 0; i < files.size(); i++) - sink.append(get(i)->getRelativePath(directory)); + for (auto &file: files) + sink.append(file->getRelativePath(directory)); sink.endList(); } diff --git a/src/camotics/qt/BBCtrlAPI.cpp b/src/camotics/qt/BBCtrlAPI.cpp index 31dd3bc9..bc323a92 100644 --- a/src/camotics/qt/BBCtrlAPI.cpp +++ b/src/camotics/qt/BBCtrlAPI.cpp @@ -165,9 +165,9 @@ void BBCtrlAPI::onTextMessageReceived(const QString &message) { bool updatePosition = false; - for (unsigned i = 0; i < json->size(); i++) { - string key = json->keyAt(i); - vars.insert(key, json->get(key)); + for (auto e: json->entries()) { + auto &key = e.key(); + vars.insert(key, e.value()); if (key == "xp" || key == "yp" || key == "zp" || key == "offset_x" || key == "offset_y" || key == "offset_z") diff --git a/src/gcode/ToolPath.cpp b/src/gcode/ToolPath.cpp index 2e244755..ed375f0d 100644 --- a/src/gcode/ToolPath.cpp +++ b/src/gcode/ToolPath.cpp @@ -59,15 +59,15 @@ int ToolPath::find(double time) const {return find(time, 0, size());} void ToolPath::read(const JSON::Value &value) { GCode::Axes start; GCode::MoveType type = GCode::MoveType::MOVE_RAPID; - int line = 0; SmartPointer filename; - int tool = 1; - double feed = 0; + int line = 0; + int tool = 1; + double feed = 0; double speed = 0; - double time = 0; + double time = 0; - for (unsigned i = 0; i < value.size(); i++) { - auto &dict = value.getDict(i); + for (auto v: value) { + auto &dict = v->getDict(); GCode::Axes end; for (int j = 0; j < 9; j++) @@ -82,9 +82,9 @@ void ToolPath::read(const JSON::Value &value) { filename = new string(_filename); } - line = dict.getNumber("line", line); - tool = dict.getNumber("tool", tool); - feed = dict.getNumber("feed", feed); + line = dict.getNumber("line", line); + tool = dict.getNumber("tool", tool); + feed = dict.getNumber("feed", feed); speed = dict.getNumber("speed", speed); double delta = dict.getNumber("time", 0); diff --git a/src/gcode/ToolTable.cpp b/src/gcode/ToolTable.cpp index 5985db41..51984b74 100644 --- a/src/gcode/ToolTable.cpp +++ b/src/gcode/ToolTable.cpp @@ -78,12 +78,9 @@ void ToolTable::add(const Tool &tool) { void ToolTable::read(const JSON::Value &value) { clear(); - for (unsigned i = 0; i < value.size(); i++) { - string key = value.keyAt(i); - unsigned number = String::parseU32(key); - Tool tool(number); - - tool.read(value.getDict(i)); + for (auto e: value.entries()) { + Tool tool(String::parseU32(e.key())); + tool.read(e.value()->getDict()); set(tool); } } diff --git a/src/gcode/plan/PlannerConfig.cpp b/src/gcode/plan/PlannerConfig.cpp index 4165c7fa..58dd3584 100644 --- a/src/gcode/plan/PlannerConfig.cpp +++ b/src/gcode/plan/PlannerConfig.cpp @@ -85,8 +85,8 @@ void PlannerConfig::read(const JSON::Value &value) { if (value.hasDict("overrides")) { auto &dict = value.getDict("overrides"); - for (unsigned i = 0; i < dict.size(); i++) - overrides[Code::parse(dict.keyAt(i))] = dict.getString(i); + for (auto e: dict.entries()) + overrides[Code::parse(e.key())] = e.value()->getString(); } }