├── .chglog ├── CHANGELOG.tpl.md └── config.yml ├── .github └── workflows │ ├── deploy-linux-appimage.yml │ ├── deploy-windows.yml │ └── sonarcloud.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENCE.txt ├── README.md ├── ci ├── buildappimage.sh ├── buildsonarcloud.sh └── deploywindows.sh ├── cmake ├── FindGcov.cmake ├── FindLcov.cmake └── Findcodecov.cmake ├── doc ├── Bulge2Arc2.png ├── Capture.PNG ├── configuration.png ├── logo.png ├── pocket.gif ├── screen.png └── simulation.gif ├── reference ├── 11812-Article Text-33790-1-10-20150414.pdf ├── ApproximatingNURBScurvesbyarcsplines_GMP2000.pdf ├── Optimal_Single_Biarc_Fitting_and_its_Applications.pdf └── bs.pdf ├── resource ├── CMakeLists.txt ├── dxfplotter.desktop ├── dxfplotter.png ├── icons │ ├── application-exit.svg │ ├── configure.svg │ ├── document-export.svg │ ├── document-open.svg │ ├── document-save-as.svg │ ├── document-save.svg │ ├── edit-copy.svg │ ├── go-down.svg │ ├── go-up.svg │ ├── layer-lower.svg │ ├── layer-raise.svg │ ├── layer-visible-off.svg │ ├── layer-visible-on.svg │ ├── list-add.svg │ ├── list-remove.svg │ ├── path-inset.svg │ ├── path-outset.svg │ ├── playback-pause.svg │ ├── playback-start.svg │ ├── pocket-shape.svg │ ├── resizecol.svg │ ├── set-origin.svg │ ├── show-path-outline.svg │ ├── simulate.svg │ ├── transform-rotate.svg │ └── zoom-in.svg └── resource.qrc ├── sonar-project.properties ├── src ├── CMakeLists.txt ├── common │ ├── CMakeLists.txt │ ├── aggregable.h │ ├── enum.h │ ├── exception.h │ └── function.h ├── config │ ├── CMakeLists.txt │ ├── config.cpp │ ├── config.h.in │ ├── config_gen.py │ ├── group.h │ ├── list.h │ ├── node.cpp │ ├── node.h │ ├── property.h │ └── utils.h ├── exporter │ ├── CMakeLists.txt │ ├── dxfplot │ │ ├── CMakeLists.txt │ │ ├── exporter.cpp │ │ └── exporter.h │ ├── gcode │ │ ├── CMakeLists.txt │ │ ├── exporter.cpp │ │ ├── exporter.h │ │ ├── metadata.cpp │ │ ├── metadata.h │ │ ├── postprocessor.cpp │ │ └── postprocessor.h │ └── renderer │ │ ├── CMakeLists.txt │ │ ├── passesiterator.cpp │ │ ├── passesiterator.h │ │ ├── renderer.cpp │ │ └── renderer.h ├── geometry │ ├── CMakeLists.txt │ ├── arc.cpp │ ├── arc.h │ ├── bezier.cpp │ ├── bezier.h │ ├── biarc.cpp │ ├── biarc.h │ ├── bulge.cpp │ ├── bulge.h │ ├── cavcutils.h │ ├── circle.cpp │ ├── circle.h │ ├── cubicspline.cpp │ ├── cubicspline.h │ ├── filter │ │ ├── CMakeLists.txt │ │ ├── assembler.cpp │ │ ├── assembler.h │ │ ├── cleaner.cpp │ │ ├── cleaner.h │ │ ├── removeexactduplicate.cpp │ │ ├── removeexactduplicate.h │ │ ├── sorter.cpp │ │ └── sorter.h │ ├── line.cpp │ ├── line.h │ ├── pocketer.cpp │ ├── pocketer.h │ ├── polyline.cpp │ ├── polyline.h │ ├── quadraticspline.cpp │ ├── quadraticspline.h │ ├── rect.cpp │ ├── rect.h │ ├── spline.cpp │ ├── spline.h │ └── utils.h ├── importer │ ├── CMakeLists.txt │ ├── dxf │ │ ├── CMakeLists.txt │ │ ├── entityimporter.cpp │ │ ├── entityimporter.h │ │ ├── importer.cpp │ │ ├── importer.h │ │ ├── interface.cpp │ │ ├── interface.h │ │ ├── layer.cpp │ │ ├── layer.h │ │ └── utils.h │ └── dxfplot │ │ ├── CMakeLists.txt │ │ ├── importer.cpp │ │ └── importer.h ├── main.cpp ├── model │ ├── CMakeLists.txt │ ├── application.cpp │ ├── application.h │ ├── document.cpp │ ├── document.h │ ├── documentmodelobserver.h │ ├── layer.cpp │ ├── layer.h │ ├── offsettedpath.cpp │ ├── offsettedpath.h │ ├── path.cpp │ ├── path.h │ ├── pathgroupsettings.cpp │ ├── pathgroupsettings.h │ ├── pathsettings.cpp │ ├── pathsettings.h │ ├── renderable.cpp │ ├── renderable.h │ ├── simulation.cpp │ ├── simulation.h │ ├── task.cpp │ └── task.h ├── serializer │ ├── CMakeLists.txt │ ├── access.h │ ├── bulge.h │ ├── layer.h │ ├── offsettedpath.h │ ├── path.h │ ├── pathsettings.h │ ├── polyline.h │ ├── qvector2d.h │ ├── renderable.h │ └── task.h └── view │ ├── CMakeLists.txt │ ├── dialogs │ ├── CMakeLists.txt │ ├── mirror.cpp │ ├── mirror.h │ ├── setorigin.cpp │ ├── setorigin.h │ ├── settings │ │ ├── CMakeLists.txt │ │ ├── entry.h │ │ ├── group.h │ │ ├── list.cpp │ │ ├── list.h │ │ ├── settings.cpp │ │ ├── settings.h │ │ ├── treemodel.cpp │ │ └── treemodel.h │ ├── transform.cpp │ └── transform.h │ ├── info.cpp │ ├── info.h │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── profile.cpp │ ├── profile.h │ ├── simulation │ ├── CMakeLists.txt │ ├── internal │ │ ├── CMakeLists.txt │ │ ├── scene.cpp │ │ ├── scene.h │ │ ├── tool.cpp │ │ ├── tool.h │ │ ├── toolpath.cpp │ │ ├── toolpath.h │ │ ├── viewport.cpp │ │ └── viewport.h │ ├── simulation.cpp │ └── simulation.h │ ├── task │ ├── CMakeLists.txt │ ├── layertreemodel.cpp │ ├── layertreemodel.h │ ├── path.cpp │ ├── path.h │ ├── pathlistmodel.cpp │ ├── pathlistmodel.h │ ├── task.cpp │ └── task.h │ ├── transform.h │ └── view2d │ ├── CMakeLists.txt │ ├── basicpathitem.cpp │ ├── basicpathitem.h │ ├── bulgepainter.cpp │ ├── bulgepainter.h │ ├── offsettedpolylinepathitem.cpp │ ├── offsettedpolylinepathitem.h │ ├── pointpathitem.cpp │ ├── pointpathitem.h │ ├── polylinepathitem.cpp │ ├── polylinepathitem.h │ ├── rubberband.cpp │ ├── rubberband.h │ ├── viewport.cpp │ └── viewport.h ├── template ├── CMakeLists.txt ├── config.xml └── uic │ ├── CMakeLists.txt │ ├── dialogs │ ├── CMakeLists.txt │ ├── mirror.ui │ ├── setorigin.ui │ ├── settings │ │ ├── CMakeLists.txt │ │ ├── group.ui │ │ ├── list.ui │ │ └── settings.ui │ └── transform.ui │ ├── info.ui │ ├── mainwindow.ui │ ├── path.ui │ ├── profile.ui │ ├── simulation │ ├── CMakeLists.txt │ └── simulation.ui │ └── task.ui ├── test ├── CMakeLists.txt ├── a.out ├── arc.cpp ├── assembler.cpp ├── bulge.cpp ├── dxfplotexporter.cpp ├── dxfplotimporter.cpp ├── exporterfixture.cpp ├── exporterfixture.h ├── gcodeexporter.cpp ├── main.cpp ├── path.cpp ├── pathsettings.cpp ├── pocketer.cpp ├── polyline.cpp ├── polylineutils.cpp ├── polylineutils.h ├── serializer.cpp ├── simulation.cpp ├── spline.cpp ├── task.cpp ├── testarc.cpp ├── testbezier.cpp ├── testexport.cpp └── verticalspeed.cpp └── thirdparty ├── CMakeLists.txt └── libdxfrw ├── CMakeLists.txt ├── drw_base.cpp ├── drw_base.h ├── drw_classes.cpp ├── drw_classes.h ├── drw_entities.cpp ├── drw_entities.h ├── drw_header.cpp ├── drw_header.h ├── drw_interface.h ├── drw_objects.cpp ├── drw_objects.h ├── intern ├── drw_cptable932.h ├── drw_cptable936.h ├── drw_cptable949.h ├── drw_cptable950.h ├── drw_cptables.h ├── drw_dbg.cpp ├── drw_dbg.h ├── drw_textcodec.cpp ├── drw_textcodec.h ├── dwgbuffer.cpp ├── dwgbuffer.h ├── dwgreader.cpp ├── dwgreader.h ├── dwgreader15.cpp ├── dwgreader15.h ├── dwgreader18.cpp ├── dwgreader18.h ├── dwgreader21.cpp ├── dwgreader21.h ├── dwgreader24.cpp ├── dwgreader24.h ├── dwgreader27.cpp ├── dwgreader27.h ├── dwgutil.cpp ├── dwgutil.h ├── dxfreader.cpp ├── dxfreader.h ├── dxfwriter.cpp ├── dxfwriter.h ├── rscodec.cpp └── rscodec.h ├── libdwgr.cpp ├── libdwgr.h ├── libdxfrw.cpp ├── libdxfrw.h └── main_doc.h /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | {{ range .Versions }} 2 | 3 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} 4 | 5 | > {{ datetime "2006-01-02" .Tag.Date }} 6 | 7 | {{ range .CommitGroups -}} 8 | ### {{ .Title }} 9 | 10 | {{ range .Commits -}} 11 | * {{ .Subject }} 12 | {{ end }} 13 | {{ end -}} 14 | 15 | {{- if .NoteGroups -}} 16 | {{ range .NoteGroups -}} 17 | ### {{ .Title }} 18 | 19 | {{ range .Notes }} 20 | {{ .Body }} 21 | {{ end }} 22 | {{ end -}} 23 | {{ end -}} 24 | {{ end -}} -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/panzergame/dxfplotter 6 | options: 7 | commits: 8 | # filters: 9 | # Type: 10 | # - feat 11 | # - fix 12 | # - perf 13 | # - refactor 14 | commit_groups: 15 | # title_maps: 16 | # feat: Features 17 | # fix: Bug Fixes 18 | # perf: Performance Improvements 19 | # refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)\\:\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Subject 25 | notes: 26 | keywords: 27 | - BREAKING CHANGE -------------------------------------------------------------------------------- /.github/workflows/deploy-linux-appimage.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | with: 15 | submodules: true 16 | - name: Install package 17 | run: | 18 | sudo apt-get update 19 | sudo apt-get -y install qtbase5-dev qt3d5-dev libqt5svg5-dev freeglut3-dev libfuse2 20 | - name: Build and test 21 | run: ci/buildappimage.sh 22 | - name: Create Release 23 | uses: softprops/action-gh-release@v1 24 | with: 25 | files: "dxfplotter*.AppImage" 26 | -------------------------------------------------------------------------------- /.github/workflows/deploy-windows.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - name: Cache Qt 13 | id: cache-qt 14 | uses: actions/cache@v1 # not v2! 15 | with: 16 | path: ../Qt 17 | key: ${{ runner.os }}-QtCache 18 | 19 | - name: Install Qt 20 | uses: jurplel/install-qt-action@v2 21 | with: 22 | cached: ${{ steps.cache-qt.outputs.cache-hit }} 23 | - uses: lukka/get-cmake@latest 24 | - name: Add msbuild to PATH 25 | uses: microsoft/setup-msbuild@v1.1 26 | - name: Install jinja2 27 | shell: bash 28 | run: python -m pip install jinja2 29 | - name: Install zip 30 | shell: bash 31 | run: choco install -y zip 32 | - name: Checkout 33 | uses: actions/checkout@v2 34 | with: 35 | submodules: true 36 | - name: CMake 37 | shell: bash 38 | run: | 39 | mkdir build 40 | cd build 41 | cmake -DBUILD_TESTING=OFF .. 42 | - name: Build 43 | run: msbuild build\dxfplotter.sln /property:Configuration=Release 44 | - name: Deploy Qt 45 | shell: bash 46 | run: ci/deploywindows.sh 47 | - name: Create Release 48 | uses: softprops/action-gh-release@v1 49 | with: 50 | files: "dxfplotter*.zip" 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | push: 4 | branches: 5 | - "**" 6 | 7 | jobs: 8 | static_analysis: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | with: 14 | submodules: true 15 | - name: Install package 16 | run: | 17 | sudo apt-get update 18 | sudo apt-get -y install qtbase5-dev qt3d5-dev libqt5svg5-dev freeglut3-dev lcov 19 | - name: Install build wrapper 20 | run: | 21 | wget http://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip 22 | unzip build-wrapper-linux-x86.zip 23 | - name: Install sonar scanner 24 | run: | 25 | wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip 26 | unzip sonar-scanner-cli-4.6.2.2472-linux.zip 27 | - name: Build and scan 28 | run: ci/buildsonarcloud.sh 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 32 | 33 | 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.kdev4 2 | build/ 3 | data/ 4 | .cache/ 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/nanoflann"] 2 | path = thirdparty/nanoflann 3 | url = https://github.com/jlblancoc/nanoflann.git 4 | [submodule "thirdparty/cavaliercontours"] 5 | path = thirdparty/cavaliercontours 6 | url = https://github.com/jbuckmccready/CavalierContours.git 7 | [submodule "thirdparty/cereal"] 8 | path = thirdparty/cereal 9 | url = https://github.com/USCiLab/cereal.git 10 | [submodule "thirdparty/yaml-cpp"] 11 | path = thirdparty/yaml-cpp 12 | url = https://github.com/jbeder/yaml-cpp.git 13 | [submodule "thirdparty/fmt"] 14 | path = thirdparty/fmt 15 | url = https://github.com/fmtlib/fmt.git 16 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WliliITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /ci/buildappimage.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | # building in temporary directory to keep system clean 7 | # use RAM disk if possible (as in: not building on CI system like Travis, and RAM disk is available) 8 | if [ "$CI" == "" ] && [ -d /dev/shm ]; then 9 | TEMP_BASE=/dev/shm 10 | else 11 | TEMP_BASE=/tmp 12 | fi 13 | 14 | BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" appimage-build-XXXXXX) 15 | 16 | # make sure to clean up build dir, even if errors occur 17 | cleanup () { 18 | if [ -d "$BUILD_DIR" ]; then 19 | rm -rf "$BUILD_DIR" 20 | fi 21 | } 22 | trap cleanup EXIT 23 | 24 | # store repo root as variable 25 | REPO_ROOT=$(readlink -f $(dirname $(dirname $0))) 26 | OLD_CWD=$(readlink -f .) 27 | 28 | # generate release name 29 | COMMIT=$(git rev-parse --short HEAD) 30 | TAG=$(git describe --tags) 31 | RELEASE_NAME="dxfplotter-$TAG-$COMMIT-x86_64-linux" 32 | 33 | # switch to build dir 34 | pushd "$BUILD_DIR" 35 | 36 | # configure build files with CMake 37 | # we need to explicitly set the install prefix, as CMake's default is /usr/local for some reason... 38 | cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=OFF 39 | 40 | # build project and install files into AppDir 41 | make -j$(nproc) 42 | make install DESTDIR=AppDir 43 | 44 | # now, build AppImage using linuxdeployqt 45 | wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage 46 | 47 | # make them executable 48 | chmod +x linuxdeploy*.AppImage 49 | 50 | # linuxdeployqt seems to need desktop and icon files to be placed at the root of AppDir 51 | cp AppDir/usr/share/icons/hicolor/256x256/apps/dxfplotter.png AppDir/usr/share/applications/dxfplotter.desktop AppDir 52 | 53 | # generate the AppImage 54 | # use -unsupported-allow-new-glibc for newest linux distribution 55 | ./linuxdeployqt-continuous-x86_64.AppImage AppDir/usr/bin/dxfplotter -appimage -extra-plugins=iconengines,platformthemes/libqgtk3.so,renderers/libopenglrenderer.so -unsupported-allow-new-glibc 56 | 57 | # move built AppImage back into original CWD 58 | mv dxfplotter*.AppImage "$OLD_CWD"/"$RELEASE_NAME".AppImage 59 | -------------------------------------------------------------------------------- /ci/buildsonarcloud.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | # building in temporary directory to keep system clean 7 | # use RAM disk if possible (as in: not building on CI system like Travis, and RAM disk is available) 8 | if [ "$CI" == "" ] && [ -d /dev/shm ]; then 9 | TEMP_BASE=/dev/shm 10 | else 11 | TEMP_BASE=/tmp 12 | fi 13 | 14 | BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" analyse-sonarcloud-XXXXXX) 15 | 16 | # make sure to clean up build dir, even if errors occur 17 | cleanup () { 18 | if [ -d "$BUILD_DIR" ]; then 19 | rm -rf "$BUILD_DIR" 20 | fi 21 | } 22 | trap cleanup EXIT 23 | 24 | # store repo root as variable 25 | REPO_ROOT=$(readlink -f $(dirname $(dirname $0))) 26 | OLD_CWD=$(readlink -f .) 27 | 28 | # switch to build dir 29 | pushd "$BUILD_DIR" 30 | 31 | # configure build files with CMake 32 | # we need to explicitly set the install prefix, as CMake's default is /usr/local for some reason... 33 | cmake "$REPO_ROOT" -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON 34 | 35 | # Wraps the compilation with the Build Wrapper to generate configuration (used 36 | # later by the SonarQube Scanner) into the "bw-output" folder 37 | "$REPO_ROOT"/build-wrapper-linux-x86/build-wrapper-linux-x86-64 \ 38 | --out-dir bw-output cmake \ 39 | --build . 40 | # Test project 41 | ctest -VV 42 | 43 | # Generate coverage report 44 | make gcov 45 | 46 | # Scan project 47 | "$REPO_ROOT"/sonar-scanner-4.6.2.2472-linux/bin/sonar-scanner -Dsonar.host.url=https://sonarcloud.io -Dproject.settings="$REPO_ROOT"/sonar-project.properties -Dsonar.projectBaseDir="$REPO_ROOT" -Dsonar.cfamily.gcov.reportsPath="$BUILD_DIR" 48 | 49 | 50 | -------------------------------------------------------------------------------- /ci/deploywindows.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | # generate release name 7 | COMMIT=$(git rev-parse --short HEAD) 8 | TAG=$(git describe --tags) 9 | RELEASE_NAME="dxfplotter-$TAG-$COMMIT-x86_64-windows" 10 | 11 | BUILD_DIR="build" 12 | BINARY_NAME="dxfplotter.exe" 13 | BINARY_PATH="${BUILD_DIR}/Release/${BINARY_NAME}" 14 | 15 | DEPLOY_DIR="${RELEASE_NAME}" 16 | mkdir $DEPLOY_DIR 17 | cp $BINARY_PATH $DEPLOY_DIR 18 | 19 | windeployqt --release --dir $DEPLOY_DIR "${DEPLOY_DIR}/${BINARY_NAME}" 20 | 21 | zip -r "${RELEASE_NAME}.zip" $RELEASE_NAME 22 | -------------------------------------------------------------------------------- /doc/Bulge2Arc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/Bulge2Arc2.png -------------------------------------------------------------------------------- /doc/Capture.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/Capture.PNG -------------------------------------------------------------------------------- /doc/configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/configuration.png -------------------------------------------------------------------------------- /doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/logo.png -------------------------------------------------------------------------------- /doc/pocket.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/pocket.gif -------------------------------------------------------------------------------- /doc/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/screen.png -------------------------------------------------------------------------------- /doc/simulation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/doc/simulation.gif -------------------------------------------------------------------------------- /reference/11812-Article Text-33790-1-10-20150414.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/reference/11812-Article Text-33790-1-10-20150414.pdf -------------------------------------------------------------------------------- /reference/ApproximatingNURBScurvesbyarcsplines_GMP2000.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/reference/ApproximatingNURBScurvesbyarcsplines_GMP2000.pdf -------------------------------------------------------------------------------- /reference/Optimal_Single_Biarc_Fitting_and_its_Applications.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/reference/Optimal_Single_Biarc_Fitting_and_its_Applications.pdf -------------------------------------------------------------------------------- /reference/bs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/reference/bs.pdf -------------------------------------------------------------------------------- /resource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | qt5_add_resources(SOURCES resource.qrc) 2 | 3 | add_library(resource ${SOURCES}) 4 | 5 | install(FILES dxfplotter.png DESTINATION share/icons/hicolor/256x256/apps/) 6 | install(FILES dxfplotter.desktop DESTINATION share/applications/) 7 | -------------------------------------------------------------------------------- /resource/dxfplotter.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Categories=Utility; 3 | Type=Application 4 | Icon=dxfplotter 5 | Name=dxfplotter 6 | Exec=dxfplotter 7 | 8 | -------------------------------------------------------------------------------- /resource/dxfplotter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/resource/dxfplotter.png -------------------------------------------------------------------------------- /resource/icons/application-exit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /resource/icons/configure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/document-export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /resource/icons/document-open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/document-save-as.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/document-save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/edit-copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /resource/icons/go-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /resource/icons/go-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /resource/icons/layer-lower.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /resource/icons/layer-raise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /resource/icons/layer-visible-off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/layer-visible-on.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/list-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/list-remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/path-inset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /resource/icons/path-outset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /resource/icons/playback-pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resource/icons/playback-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resource/icons/pocket-shape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 17 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /resource/icons/resizecol.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/set-origin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 20 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /resource/icons/show-path-outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /resource/icons/simulate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/transform-rotate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/icons/zoom-in.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /resource/resource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dxfplotter.png 5 | 6 | 7 | icons/application-exit.svg 8 | icons/configure.svg 9 | icons/document-export.svg 10 | icons/document-open.svg 11 | icons/document-save-as.svg 12 | icons/document-save.svg 13 | icons/edit-copy.svg 14 | icons/go-down.svg 15 | icons/go-up.svg 16 | icons/layer-lower.svg 17 | icons/layer-raise.svg 18 | icons/layer-visible-off.svg 19 | icons/layer-visible-on.svg 20 | icons/list-add.svg 21 | icons/list-remove.svg 22 | icons/path-inset.svg 23 | icons/path-outset.svg 24 | icons/playback-pause.svg 25 | icons/playback-start.svg 26 | icons/pocket-shape.svg 27 | icons/resizecol.svg 28 | icons/set-origin.svg 29 | icons/show-path-outline.svg 30 | icons/simulate.svg 31 | icons/transform-rotate.svg 32 | icons/zoom-in.svg 33 | 34 | 35 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.organization=panzergame 2 | sonar.projectKey=dxfplotter 3 | sonar.sources=src 4 | sonar.exclusions=thirdparty/**/* 5 | sonar.cfamily.build-wrapper-output=bw-output 6 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(common) 2 | add_subdirectory(config) 3 | add_subdirectory(exporter) 4 | add_subdirectory(geometry) 5 | add_subdirectory(importer) 6 | add_subdirectory(model) 7 | add_subdirectory(serializer) 8 | add_subdirectory(view) 9 | -------------------------------------------------------------------------------- /src/common/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/src/common/CMakeLists.txt -------------------------------------------------------------------------------- /src/common/aggregable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace common 9 | { 10 | 11 | template 12 | class Aggregable 13 | { 14 | public: 15 | using UPtr = std::unique_ptr; 16 | 17 | using List = std::vector; 18 | using ListPtr = std::vector; 19 | using ListCPtr = std::vector; 20 | using ListUPtr = std::vector; 21 | 22 | template 23 | using Array = std::array; 24 | template 25 | using ArrayPtr = std::array; 26 | 27 | using SetPtr = std::set; 28 | 29 | using Pair = Array<2>; 30 | using PairPtr = ArrayPtr<2>; 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/common/enum.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace common::enumerate 6 | { 7 | 8 | template 9 | inline std::initializer_list All(); 10 | 11 | template 12 | inline std::string toString(const EnumType &value); 13 | 14 | template 15 | inline EnumType fromString(const std::string &value); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/common/exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace common 7 | { 8 | 9 | class FileCouldNotOpenException : public std::exception 10 | { 11 | }; 12 | 13 | class GCodeFormatException : public std::runtime_error 14 | { 15 | private: 16 | template 17 | static std::string errorMessage(const std::string &format, const char *error, Args&& ... args) 18 | { 19 | std::ostringstream stream; 20 | stream << "Formatting error, format \"" << format << "\" with arguments"; 21 | 22 | ((stream << ' ' << args), ...); 23 | stream << ": " << error; 24 | 25 | return stream.str(); 26 | } 27 | 28 | public: 29 | template 30 | explicit GCodeFormatException(const std::string &format, const char *error, Args&& ... args) 31 | :std::runtime_error(errorMessage(format, error, std::forward(args)...)) 32 | { 33 | } 34 | }; 35 | 36 | class ImportCouldNotFindToolConfigException : public std::exception 37 | { 38 | }; 39 | 40 | class ImportCouldNotFindProfileConfigException : public std::exception 41 | { 42 | }; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/common/function.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace common 4 | { 5 | 6 | template 7 | struct MemberFunctionTraits; 8 | 9 | template 10 | struct MemberFunctionTraits<_Return (_Object::*)(Args ...)> 11 | { 12 | using Object = _Object; 13 | using Return = _Return; 14 | }; 15 | 16 | template 17 | struct MemberFunctionTraits<_Return (_Object::*)(Args ...) const> 18 | { 19 | using Object = _Object; 20 | using Return = _Return; 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set_property(SOURCE config.h PROPERTY SKIP_AUTOGEN ON) 2 | 3 | set(SRC 4 | config.cpp 5 | node.cpp 6 | 7 | config.h 8 | group.h 9 | list.h 10 | node.h 11 | property.h 12 | ) 13 | 14 | add_library(config ${SRC}) 15 | add_dependencies(config generate-config) 16 | 17 | add_custom_command( 18 | OUTPUT config.h 19 | COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/config_gen.py ${TEMPLATE_DIR}/config.xml ${CMAKE_CURRENT_SOURCE_DIR} config.h.in config.h 20 | DEPENDS config.h.in ${TEMPLATE_DIR}/config.xml config_gen.py 21 | ) 22 | 23 | add_custom_target(generate-config DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/config.h) 24 | -------------------------------------------------------------------------------- /src/config/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace config 8 | { 9 | 10 | Config::Config(const std::string &filePath) 11 | :m_filePath(filePath) 12 | { 13 | try { 14 | m_yamlRoot = YAML::LoadFile(filePath); 15 | } 16 | catch (const YAML::BadFile&) { 17 | qInfo() << "Initializing configuration from defaults"; 18 | } 19 | 20 | // Instantiation of root group 21 | m_root = Root(m_yamlRoot); 22 | } 23 | 24 | Config::Config(const Config &other) 25 | :m_filePath(other.m_filePath), 26 | m_yamlRoot(Clone(other.m_yamlRoot)), 27 | m_root(m_yamlRoot) 28 | { 29 | } 30 | 31 | Config::~Config() 32 | { 33 | save(); 34 | } 35 | 36 | Root &Config::root() 37 | { 38 | return m_root; 39 | } 40 | 41 | const Root &Config::root() const 42 | { 43 | return m_root; 44 | } 45 | 46 | void Config::save() const 47 | { 48 | std::ofstream outStream(m_filePath); 49 | outStream << m_yamlRoot; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/config/group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace config 8 | { 9 | 10 | /** @brief A configuration group. 11 | */ 12 | template 13 | class Group : public Node 14 | { 15 | protected: 16 | using Children = std::tuple; 17 | 18 | const Children& children() const 19 | { 20 | return m_children; 21 | } 22 | 23 | Children& children() 24 | { 25 | return m_children; 26 | } 27 | 28 | void setChildren(const Children& children) 29 | { 30 | m_children = children; 31 | } 32 | 33 | private: 34 | Children m_children; 35 | 36 | public: 37 | explicit Group(const std::string& name, const std::string &description) 38 | :Node(name, description) 39 | { 40 | } 41 | 42 | Group() = default; 43 | 44 | template 45 | void visitChildren(Visitor &&visitor) 46 | { 47 | std::apply([&visitor](auto&&... arg) {((visitor(arg)), ...);}, m_children); 48 | } 49 | 50 | template 51 | void visitChildren(Visitor &&visitor) const 52 | { 53 | std::apply([&visitor](auto&&... arg) {((visitor(arg)), ...);}, m_children); 54 | } 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/config/node.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace config 5 | { 6 | 7 | Node::Node(const std::string &name, const std::string &description) 8 | :m_name(name), 9 | m_description(description) 10 | { 11 | } 12 | 13 | const std::string &Node::name() const 14 | { 15 | return m_name; 16 | } 17 | 18 | const std::string &Node::description() const 19 | { 20 | return m_description; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/config/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace config 8 | { 9 | 10 | class Node 11 | { 12 | private: 13 | std::string m_name; 14 | std::string m_description; 15 | 16 | public: 17 | explicit Node(const std::string &name, const std::string &description); 18 | Node() = default; 19 | 20 | const std::string &name() const; 21 | const std::string &description() const; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/config/property.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace config 8 | { 9 | 10 | template 11 | class Property : public Node 12 | { 13 | private: 14 | YAML::Node m_yamlNode; 15 | 16 | public: 17 | explicit Property(const std::string& name, const std::string &description, const ValueType &defaultValue, YAML::Node yamlNode) 18 | :Node(name, description), 19 | m_yamlNode(yamlNode) 20 | { 21 | // Assign default value if node isn't defined 22 | if (!m_yamlNode.IsDefined()) { 23 | *this = defaultValue; 24 | } 25 | } 26 | 27 | Property() = default; 28 | 29 | operator ValueType() const 30 | { 31 | return fromSerializable(m_yamlNode); 32 | } 33 | 34 | Property &operator=(const ValueType &value) 35 | { 36 | m_yamlNode = toSerializable(value); 37 | return *this; 38 | } 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/config/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace config 8 | { 9 | 10 | template 11 | inline std::enable_if_t, Type> toSerializable(const Type &value) 12 | { 13 | return value; 14 | } 15 | 16 | template 17 | inline std::enable_if_t, std::string> toSerializable(const EnumType& value) 18 | { 19 | return common::enumerate::toString(value); 20 | } 21 | 22 | template 23 | inline Type fromSerializable(const YAML::Node &node) 24 | { 25 | if constexpr(std::is_enum_v) { 26 | return common::enumerate::fromString(node.as()); 27 | } 28 | else { 29 | return node.as(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/exporter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(dxfplot) 2 | add_subdirectory(gcode) 3 | add_subdirectory(renderer) 4 | -------------------------------------------------------------------------------- /src/exporter/dxfplot/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | exporter.cpp 3 | 4 | exporter.h 5 | ) 6 | 7 | add_library(exporter-dxfplot ${SRC}) 8 | add_dependencies(exporter-dxfplot generate-config) 9 | add_coverage(exporter-dxfplot) 10 | -------------------------------------------------------------------------------- /src/exporter/dxfplot/exporter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace exporter::dxfplot 8 | { 9 | 10 | void Exporter::operator()(const model::Document& document, std::ostream &output) const 11 | { 12 | Archive archive(output); 13 | save(archive, document); 14 | } 15 | 16 | void Exporter::save(Archive &archive, const model::Document& document) const 17 | { 18 | archive(cereal::make_nvp("task", document.task())); 19 | archive(cereal::make_nvp("profile_name", document.profileConfig().name())); 20 | archive(cereal::make_nvp("tool_name", document.toolConfig().name())); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/exporter/dxfplot/exporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace exporter::dxfplot 10 | { 11 | 12 | class Exporter 13 | { 14 | public: 15 | explicit Exporter() = default; 16 | 17 | void operator()(const model::Document& document, std::ostream &output) const; 18 | 19 | private: 20 | using Archive = cereal::JSONOutputArchive; 21 | 22 | void save(Archive &archive, const model::Document& document) const; 23 | }; 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/exporter/gcode/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | exporter.cpp 3 | metadata.cpp 4 | postprocessor.cpp 5 | 6 | exporter.h 7 | metadata.h 8 | postprocessor.h 9 | ) 10 | 11 | add_library(exporter-gcode ${SRC}) 12 | add_dependencies(exporter-gcode generate-config) 13 | add_coverage(exporter-gcode) 14 | -------------------------------------------------------------------------------- /src/exporter/gcode/exporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace exporter::gcode 10 | { 11 | 12 | class PathPostProcessor; 13 | 14 | class Exporter 15 | { 16 | public: 17 | enum Options 18 | { 19 | None = 0, 20 | ExportConfig = (1 << 0), 21 | ExportMetadata = (1 << 1) 22 | }; 23 | 24 | private: 25 | const config::Tools::Tool &m_tool; 26 | const config::Profiles::Profile &m_profile; 27 | const Options m_options; 28 | 29 | public: 30 | explicit Exporter(const config::Tools::Tool& tool, const config::Profiles::Profile& profile, Options options = None); 31 | ~Exporter() = default; 32 | 33 | void operator()(const model::Document& document, std::ostream &output) const; 34 | }; 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/exporter/gcode/metadata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace exporter::gcode 13 | { 14 | 15 | std::string Metadata::fastPlaneMoveGCode(const QVector2D &to) const 16 | { 17 | std::ostringstream output; 18 | PostProcessor postprocessor(m_gcode, output); 19 | postprocessor.fastPlaneMove(to); 20 | return output.str(); 21 | } 22 | 23 | std::string Metadata::fastDepthMoveGCode(float to) const 24 | { 25 | std::ostringstream output; 26 | PostProcessor postprocessor(m_gcode, output); 27 | postprocessor.retractDepth(to); 28 | return output.str(); 29 | } 30 | 31 | QJsonArray Metadata::boundingRectGcodes() const 32 | { 33 | std::initializer_list gcodes{ 34 | fastDepthMoveGCode(m_retractDepth), 35 | fastPlaneMoveGCode(m_boundingRect.bottomLeft()), 36 | fastPlaneMoveGCode(m_boundingRect.bottomRight()), 37 | fastPlaneMoveGCode(m_boundingRect.topRight()), 38 | fastPlaneMoveGCode(m_boundingRect.topLeft()), 39 | fastPlaneMoveGCode(m_boundingRect.bottomLeft()), 40 | fastPlaneMoveGCode(QVector2D(0.0f, 0.0f)), 41 | fastDepthMoveGCode(0.0f) 42 | }; 43 | 44 | QJsonArray jsonGcodes; 45 | for (const std::string &gcode : gcodes) { 46 | jsonGcodes.push_back(QString::fromStdString(gcode)); 47 | } 48 | 49 | return jsonGcodes; 50 | } 51 | 52 | QJsonDocument Metadata::toJson() const 53 | { 54 | QJsonObject root; 55 | root["bounding_rect_gcodes"] = boundingRectGcodes(); 56 | 57 | QJsonDocument document(root); 58 | return document; 59 | } 60 | 61 | Metadata::Metadata(const model::Document& document, const config::Profiles::Profile::Gcode& gcode, float retractDepth) 62 | :m_boundingRect(document.task().visibleBoundingRect()), 63 | m_gcode(gcode), 64 | m_retractDepth((retractDepth)) 65 | { 66 | } 67 | 68 | std::string Metadata::toComment() const 69 | { 70 | const QJsonDocument& jsonDocument = toJson(); 71 | 72 | return "; metadata_json = " + jsonDocument.toJson(QJsonDocument::Compact).toStdString() + "\n"; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/exporter/gcode/metadata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace model 9 | { 10 | 11 | class Document; 12 | 13 | } 14 | 15 | class QJsonObject; 16 | 17 | namespace exporter::gcode 18 | { 19 | 20 | class Metadata 21 | { 22 | private: 23 | const geometry::Rect m_boundingRect; 24 | const config::Profiles::Profile::Gcode& m_gcode; 25 | const float m_retractDepth; 26 | 27 | std::string fastPlaneMoveGCode(const QVector2D &to) const; 28 | std::string fastDepthMoveGCode(float to) const; 29 | QJsonArray boundingRectGcodes() const; 30 | QJsonDocument toJson() const; 31 | 32 | public: 33 | explicit Metadata(const model::Document& document, const config::Profiles::Profile::Gcode& gcode, float retractDepth); 34 | 35 | std::string toComment() const; 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/exporter/gcode/postprocessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace exporter::gcode 11 | { 12 | 13 | class PostProcessor 14 | { 15 | private: 16 | std::ostream &m_stream; 17 | 18 | protected: 19 | const config::Profiles::Profile::Gcode& m_gcode; 20 | 21 | /** Print a command to stream with a format and a list of named arguments 22 | * @param format A fmt valid format string. 23 | * @param args List of named arguments 24 | */ 25 | template 26 | void print(const std::string &format, Args&& ...args) 27 | { 28 | try { 29 | m_stream << fmt::format(format, std::forward(args)...) << "\n"; 30 | } 31 | catch (const fmt::format_error &exception) { 32 | throw common::GCodeFormatException(format, exception.what(), fmt::to_string(args.name)...); 33 | } 34 | } 35 | 36 | public: 37 | void preCut(float intensity); 38 | void postCut(); 39 | void planeLinearMove(const QVector2D &to, float feedRate); 40 | void depthLinearMove(float depth, float feedRate); 41 | void cwArcMove(const QVector2D &relativeCenter, const QVector2D &to, float feedRate); 42 | void ccwArcMove(const QVector2D &relativeCenter, const QVector2D &to, float feedRate); 43 | void fastPlaneMove(const QVector2D &to); 44 | void retractDepth(float depth); 45 | void processBulge(const geometry::Bulge &bulge, float planeFeedRate); 46 | void processLine(const geometry::Bulge &bulge, float planeFeedRate); 47 | void processArc(const geometry::Bulge &bulge, float planeFeedRate); 48 | 49 | explicit PostProcessor(const config::Profiles::Profile::Gcode& gcode, std::ostream &stream); 50 | }; 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/exporter/renderer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | passesiterator.cpp 3 | renderer.cpp 4 | 5 | passesiterator.h 6 | renderer.h 7 | ) 8 | 9 | add_library(exporter-renderer ${SRC}) 10 | add_dependencies(exporter-renderer generate-config) 11 | add_coverage(exporter-renderer) 12 | -------------------------------------------------------------------------------- /src/exporter/renderer/passesiterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool PassesIterator::needPolylineInverse() const 4 | { 5 | return (!m_closed || m_cuttingBackward); 6 | } 7 | 8 | const geometry::Polyline &PassesIterator::polylineForward() const 9 | { 10 | return m_cuttingBackward ? m_polylineInverse : m_polyline; 11 | } 12 | 13 | const geometry::Polyline &PassesIterator::polylineBackward() const 14 | { 15 | return m_cuttingBackward ? m_polyline : m_polylineInverse; 16 | } 17 | 18 | PassesIterator::PassesIterator(const geometry::Polyline &polyline, geometry::CuttingDirection direction) 19 | :m_closed(polyline.isClosed()), 20 | m_cuttingBackward(direction == geometry::CuttingDirection::BACKWARD), 21 | m_polyline(polyline), 22 | m_polylineInverse(needPolylineInverse() ? m_polyline.inverse() : geometry::Polyline()) 23 | { 24 | } 25 | 26 | const geometry::Polyline &PassesIterator::operator*() const 27 | { 28 | if (m_closed || m_odd) { 29 | return polylineForward(); 30 | } 31 | return polylineBackward(); 32 | } 33 | 34 | PassesIterator &PassesIterator::operator++() 35 | { 36 | m_odd = !m_odd; 37 | 38 | return *this; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/exporter/renderer/passesiterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Return next polyline to convert 6 | class PassesIterator 7 | { 8 | private: 9 | bool m_odd = true; 10 | const bool m_closed; 11 | const bool m_cuttingBackward; 12 | const geometry::Polyline& m_polyline; 13 | const geometry::Polyline m_polylineInverse; 14 | 15 | bool needPolylineInverse() const; 16 | const geometry::Polyline &polylineForward() const; 17 | const geometry::Polyline &polylineBackward() const; 18 | 19 | public: 20 | explicit PassesIterator(const geometry::Polyline &polyline, geometry::CuttingDirection direction); 21 | 22 | const geometry::Polyline &operator*() const; 23 | PassesIterator &operator++(); 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/exporter/renderer/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/geometry/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(filter) 2 | 3 | set(SRC 4 | arc.cpp 5 | bezier.cpp 6 | biarc.cpp 7 | bulge.cpp 8 | circle.cpp 9 | cubicspline.cpp 10 | line.cpp 11 | pocketer.cpp 12 | polyline.cpp 13 | quadraticspline.cpp 14 | rect.cpp 15 | spline.cpp 16 | 17 | arc.h 18 | bezier.h 19 | biarc.h 20 | bulge.h 21 | circle.h 22 | cubicspline.h 23 | line.h 24 | polyline.h 25 | quadraticspline.h 26 | spline.h 27 | rect.h 28 | utils.h 29 | ) 30 | 31 | add_library(geometry ${SRC}) 32 | add_coverage(geometry) 33 | -------------------------------------------------------------------------------- /src/geometry/arc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace geometry 5 | { 6 | 7 | Arc::Arc(const Circle &circle, const QVector2D &start, const QVector2D &end, 8 | float starAngle, float endAngle) 9 | :Circle(circle), 10 | m_start(start), 11 | m_end(end), 12 | m_startAngle(starAngle), 13 | m_endAngle(endAngle) 14 | { 15 | if (orientation() == Orientation::CCW) { 16 | m_endAngle = EnsureEndGreater(m_startAngle, m_endAngle); 17 | assert(m_startAngle <= m_endAngle); 18 | } 19 | else { 20 | m_startAngle = EnsureEndGreater(m_endAngle, m_startAngle); 21 | assert(m_endAngle <= m_startAngle); 22 | } 23 | 24 | m_spanAngle = m_endAngle - m_startAngle; 25 | } 26 | 27 | const QVector2D &Arc::start() const 28 | { 29 | return m_start; 30 | } 31 | 32 | const QVector2D &Arc::end() const 33 | { 34 | return m_end; 35 | } 36 | 37 | float Arc::startAngle() const 38 | { 39 | return m_startAngle; 40 | } 41 | 42 | float Arc::endAngle() const 43 | { 44 | return m_endAngle; 45 | } 46 | 47 | float Arc::spanAngle() const 48 | { 49 | return m_spanAngle; 50 | } 51 | 52 | float Arc::length() const 53 | { 54 | return std::abs(m_spanAngle) * radius(); 55 | } 56 | 57 | QVector2D Arc::pointAtAngle(float angle) const 58 | { 59 | const QVector2D relativeNormalizedPoint(std::cos(angle), std::sin(angle)); 60 | const QVector2D point = (center() + relativeNormalizedPoint * radius()); 61 | return point; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/geometry/arc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry 6 | { 7 | 8 | /** Arcs are considered as angle clamped circles 9 | */ 10 | class Arc : public Circle 11 | { 12 | private: 13 | QVector2D m_start; 14 | QVector2D m_end; 15 | float m_startAngle; 16 | float m_endAngle; 17 | float m_spanAngle; 18 | 19 | public: 20 | explicit Arc(const Circle &circle, const QVector2D &start, const QVector2D &end, 21 | float starAngle, float endAngle); 22 | 23 | const QVector2D &start() const; 24 | const QVector2D &end() const; 25 | float startAngle() const; 26 | float endAngle() const; 27 | float spanAngle() const; 28 | 29 | float length() const; 30 | 31 | QVector2D pointAtAngle(float angle) const; 32 | 33 | template 34 | void approximateToLinesVisit(float maxError, Visitor &&visitor) const 35 | { 36 | // Calculate the angle step to not exceed allowed error (distance from line to arc). 37 | const float angleStep = std::fmax(std::acos(1.0f - maxError) * 2.0f, maxError); 38 | 39 | if (orientation() == geometry::Orientation::CCW) { 40 | for (float angle = m_startAngle + angleStep, end = m_endAngle; angle < end; angle += angleStep) { 41 | visitor(pointAtAngle(angle)); 42 | } 43 | } 44 | else { 45 | for (float angle = m_startAngle - angleStep, end = m_endAngle; angle > end; angle -= angleStep) { 46 | visitor(pointAtAngle(angle)); 47 | } 48 | } 49 | 50 | visitor(m_end); 51 | } 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/geometry/bezier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace geometry 12 | { 13 | 14 | class Bezier : public common::Aggregable 15 | { 16 | private: 17 | using Complex = std::complex; 18 | using InflexionPoints = std::array; 19 | 20 | QVector2D m_point1; 21 | QVector2D m_point2; 22 | QVector2D m_control1; 23 | QVector2D m_control2; 24 | 25 | static bool isRealInflexionPoint(const Bezier::Complex &point); 26 | 27 | InflexionPoints inflexions() const; 28 | QVector2D derivativeAt(float t) const; 29 | 30 | QVector2D findNearestPointWithTangent(const QVector2D &point, const QVector2D& tangent, float maxError) const; 31 | 32 | public: 33 | explicit Bezier(const QVector2D &p1, const QVector2D &c1, 34 | const QVector2D &c2, const QVector2D &p2); 35 | Bezier() = default; 36 | 37 | const QVector2D &point1() const; 38 | const QVector2D &point2() const; 39 | const QVector2D &control1() const; 40 | const QVector2D &control2() const; 41 | 42 | QVector2D at(float t) const; 43 | 44 | float approximateLength() const; 45 | 46 | Pair split(float t) const; 47 | Pair splitHalf() const; 48 | /// Split bezier keeping only convex shape. 49 | List splitToConvex() const; 50 | 51 | std::optional toBiarc() const; 52 | Polyline toLine() const; 53 | 54 | bool isPoint() const; 55 | 56 | float maxError(const Biarc &biarc) const; 57 | }; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/geometry/biarc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace geometry 9 | { 10 | 11 | Orientation Biarc::orientation() const 12 | { 13 | const float det = (m_middle.x() - m_point1.x()) * (m_middle.y() + m_point1.y()) + 14 | (m_point2.x() - m_middle.x()) * (m_point2.y() + m_middle.y()) + 15 | (m_point1.x() - m_point2.x()) * (m_point1.y() + m_point2.y()); 16 | 17 | return (det < 0.0f) ? Orientation::CW : Orientation::CCW; 18 | } 19 | 20 | Biarc::Biarc(const QVector2D& point1, const QVector2D& middle, const QVector2D& point2, 21 | const QVector2D& tangent1, const QVector2D& tangent2) 22 | :m_point1(point1), 23 | m_point2(point2), 24 | m_middle(middle), 25 | m_tangent1(tangent1), 26 | m_tangent2(tangent2), 27 | m_line1(middle - point1), 28 | m_line2(middle - point2) 29 | { 30 | } 31 | 32 | const QVector2D &Biarc::middle() const 33 | { 34 | return m_middle; 35 | } 36 | 37 | QVector2D Biarc::tangentAtMiddle() const 38 | { 39 | // Rotate line by PI/2 40 | const QVector2D normalizedLine1 = m_line1.normalized(); 41 | const QVector2D perpendicularLine1 = PerpendicularLine(normalizedLine1); 42 | 43 | // Tangent at middle is the reflect of tangent at start by perpendicular line start to end. 44 | return ReflectLine(m_tangent1.normalized(), perpendicularLine1); 45 | } 46 | 47 | float Biarc::approximateLength() const 48 | { 49 | return (m_point1 - m_middle).length() + (m_point2 - m_middle).length(); 50 | } 51 | 52 | Polyline Biarc::toLinePolyline() const 53 | { 54 | const Bulge bulge(m_point1, m_point2, 0.0f); 55 | return Polyline({bulge}); 56 | } 57 | 58 | Polyline Biarc::toPolyline() const 59 | { 60 | /* Angle from end to start line with arc tangent at start point is double of 61 | * bulge tangent angle. 62 | */ 63 | 64 | // Half angle from tangent1 to line1 65 | const float thetab1 = (LineAngle(m_line1) - LineAngle(m_tangent1)) / 2.0f; 66 | // Half angle from line2 to tangent2 67 | const float thetab2 = (LineAngle(m_tangent2) - LineAngle(m_line2)) / 2.0f; 68 | 69 | const Bulge b1(m_point1, m_middle, std::tan(thetab1)); 70 | const Bulge b2(m_middle, m_point2, std::tan(thetab2)); 71 | 72 | return Polyline({b1, b2}); 73 | } 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/geometry/biarc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace geometry 11 | { 12 | 13 | class Biarc : public common::Aggregable 14 | { 15 | private: 16 | QVector2D m_point1; 17 | QVector2D m_point2; 18 | /// Intersection point of the arcs 19 | QVector2D m_middle; 20 | /// Tangent at point1 21 | QVector2D m_tangent1; 22 | /// Tangent at point1 23 | QVector2D m_tangent2; 24 | /// Line from point1 to middle 25 | QVector2D m_line1; 26 | /// Line from point2 to middle 27 | QVector2D m_line2; 28 | 29 | Orientation orientation() const; 30 | 31 | public: 32 | explicit Biarc(const QVector2D &point1, const QVector2D &middle, const QVector2D &point2, 33 | const QVector2D &tangent1, const QVector2D &tangent2); 34 | 35 | const QVector2D &middle() const; 36 | QVector2D tangentAtMiddle() const; 37 | 38 | float approximateLength() const; 39 | 40 | Polyline toLinePolyline() const; 41 | Polyline toPolyline() const; 42 | }; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/geometry/bulge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace geometry 19 | { 20 | 21 | class Bulge : public common::Aggregable 22 | { 23 | friend serializer::Access; 24 | 25 | private: 26 | QVector2D m_start; 27 | QVector2D m_end; 28 | 29 | float m_tangent; 30 | 31 | float arcRadius() const; 32 | QVector2D relativeArcCenter() const; 33 | Point2DList arcBoundingPoints() const; 34 | 35 | public: 36 | /** Define a bulge 37 | * @param start Starting point of the bulge 38 | * @param end Ending point of the bulge 39 | * @param tangent Tangent of a thourth of the arc angle. 40 | * Negative tangent means the arc goes clockwise from start to end, 41 | * otherwise anti clockwise from start to end. 42 | */ 43 | explicit Bulge(const QVector2D &start, const QVector2D &end, float tangent); 44 | explicit Bulge(const cavc::PlineVertex &v1, const cavc::PlineVertex &v2); 45 | explicit Bulge() = default; 46 | 47 | const QVector2D &start() const; 48 | QVector2D &start(); 49 | const QVector2D &end() const; 50 | QVector2D &end(); 51 | float tangent() const; 52 | float &tangent(); 53 | 54 | float length() const; 55 | 56 | Rect boundingRect() const; 57 | 58 | /// Change direction 59 | void invert(); 60 | /// Transform to line, means tangent is 0. 61 | void linify(); 62 | 63 | // Extend bulge start point 64 | Bulge extendStart(const QVector2D &start) const; 65 | // Extend bulge end point 66 | Bulge extendEnd(const QVector2D &end) const; 67 | 68 | bool isLine() const; 69 | bool isArc() const; 70 | Orientation orientation() const; 71 | 72 | Circle toCircle() const; 73 | Arc toArc() const; 74 | Line toLine() const; 75 | 76 | void transform(const QTransform &matrix); 77 | 78 | bool operator==(const Bulge& other) const; 79 | 80 | bool equalsInversed(const Bulge& other) const; 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/geometry/cavcutils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace cavc::utils 6 | { 7 | 8 | // absolute threshold to be used for comparing reals generally 9 | template <> constexpr double realThreshold() { return 1e-12; } 10 | 11 | // absolute threshold to be used for reals in common geometric computation (e.g. to check for 12 | // singularities) 13 | template <> constexpr double realPrecision() { return 1e-9; } 14 | 15 | // absolute threshold to be used for joining slices together at end points 16 | template <> constexpr double sliceJoinThreshold() { return 1e-8; } 17 | 18 | // absolute threshold to be used for pruning invalid slices for offset 19 | template <> constexpr double offsetThreshold() { return 1e-8; } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/geometry/circle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace geometry 4 | { 5 | 6 | Circle::Circle(const QVector2D ¢er, float radius, Orientation orientation) 7 | :m_center(center), 8 | m_radius(radius), 9 | m_orientation(orientation) 10 | { 11 | } 12 | 13 | const QVector2D &Circle::center() const 14 | { 15 | return m_center; 16 | } 17 | 18 | float Circle::radius() const 19 | { 20 | return m_radius; 21 | } 22 | 23 | Orientation Circle::orientation() const 24 | { 25 | return m_orientation; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/geometry/circle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry 6 | { 7 | 8 | class Circle 9 | { 10 | private: 11 | QVector2D m_center; 12 | float m_radius; 13 | Orientation m_orientation; 14 | 15 | public: 16 | explicit Circle(const QVector2D ¢er, float radius, Orientation orientation); 17 | 18 | const QVector2D ¢er() const; 19 | float radius() const; 20 | Orientation orientation() const; 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/geometry/cubicspline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry 6 | { 7 | 8 | class CubicSpline : public Spline 9 | { 10 | private: 11 | Point2DList convertClosedToCubicBezierPoints() const; 12 | Point2DList convertOpenedToCubicBezierPoints() const; 13 | 14 | Bezier::List pointsToBeziers(const Point2DList &bezierPoints) const; 15 | 16 | public: 17 | explicit CubicSpline(Point2DList &&points, bool closed); 18 | 19 | Bezier::List toBeziers() const; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/geometry/filter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | assembler.cpp 3 | cleaner.cpp 4 | removeexactduplicate.cpp 5 | sorter.cpp 6 | 7 | assembler.h 8 | cleaner.h 9 | removeexactduplicate.h 10 | sorter.h 11 | ) 12 | 13 | add_library(geometry-filter ${SRC}) 14 | add_coverage(geometry-filter) 15 | -------------------------------------------------------------------------------- /src/geometry/filter/cleaner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry::filter 6 | { 7 | 8 | /** @brief Clean polyline via merging of small bulges. 9 | */ 10 | class Cleaner 11 | { 12 | private: 13 | Polyline::List m_polylines; 14 | 15 | public: 16 | explicit Cleaner(Polyline::List &&polylines, float minimumPolylineLength, float minimumArcLength); 17 | 18 | Polyline::List &&polylines(); 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/geometry/filter/removeexactduplicate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry::filter 6 | { 7 | 8 | /** @brief Remove exact duplicate of polylines 9 | */ 10 | class RemoveExactDuplicate 11 | { 12 | private: 13 | Polyline::List m_polylines; 14 | 15 | struct UndirectedPolyline : common::Aggregable 16 | { 17 | QVector2D start; 18 | QVector2D end; 19 | 20 | enum class Direction 21 | { 22 | Normal, 23 | Opposite 24 | } direction; 25 | int index; 26 | const Polyline *polyline; 27 | 28 | UndirectedPolyline() = default; 29 | explicit UndirectedPolyline(const QVector2D &start, const QVector2D &end, const Polyline &polyline, int index, Direction direction); 30 | 31 | bool operator<(const UndirectedPolyline &other) const; 32 | bool operator==(const UndirectedPolyline &other) const; 33 | }; 34 | 35 | using PolylineMaskList = std::vector; 36 | 37 | UndirectedPolyline::List buildPolylinesMap(const Polyline::List& polylines) const; 38 | PolylineMaskList buildPolylineMaskWithoutDuplicate(const UndirectedPolyline::List polylineMap, int nbPolylines) const; 39 | void filterPolylines(Polyline::List &&polylines, PolylineMaskList polylineMask); 40 | 41 | public: 42 | explicit RemoveExactDuplicate(Polyline::List &&polylines); 43 | 44 | Polyline::List &&polylines(); 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/geometry/filter/sorter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace geometry::filter 4 | { 5 | 6 | Sorter::Sorter(Polyline::List &&polylines) 7 | :m_polylines(polylines.size()) 8 | { 9 | struct PolylineLength 10 | { 11 | Polyline *polyline; 12 | float length; 13 | 14 | PolylineLength() = default; 15 | 16 | explicit PolylineLength(Polyline &polyline) 17 | :polyline(&polyline), 18 | length(polyline.length()) 19 | { 20 | } 21 | 22 | bool operator<(const PolylineLength& other) const 23 | { 24 | return length < other.length; 25 | } 26 | }; 27 | 28 | std::vector polylinesLength(polylines.size()); 29 | std::transform(polylines.begin(), polylines.end(), polylinesLength.begin(), 30 | [](Polyline& polyline){ return PolylineLength(polyline); }); 31 | 32 | std::sort(polylinesLength.begin(), polylinesLength.end()); 33 | 34 | std::transform(polylinesLength.begin(), polylinesLength.end(), m_polylines.begin(), 35 | [](PolylineLength& polylineLength){ return std::move(*polylineLength.polyline); }); 36 | } 37 | 38 | Polyline::List &&Sorter::polylines() 39 | { 40 | return std::move(m_polylines); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/geometry/filter/sorter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry::filter 6 | { 7 | 8 | /** @brief Sort polyline by length. 9 | */ 10 | class Sorter 11 | { 12 | private: 13 | Polyline::List m_polylines; 14 | 15 | public: 16 | explicit Sorter(Polyline::List &&polylines); 17 | 18 | Polyline::List &&polylines(); 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/geometry/line.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace geometry 4 | { 5 | 6 | Line::Line(const QVector2D &start, const QVector2D &end) 7 | :m_start(start), 8 | m_end(end) 9 | { 10 | } 11 | 12 | const QVector2D &Line::start() const 13 | { 14 | return m_start; 15 | } 16 | 17 | const QVector2D &Line::end() const 18 | { 19 | return m_end; 20 | } 21 | 22 | bool Line::lengthNonZero() const 23 | { 24 | return (m_start != m_end); 25 | } 26 | 27 | float Line::length() const 28 | { 29 | return m_start.distanceToPoint(m_end); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/geometry/line.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry 6 | { 7 | 8 | class Line 9 | { 10 | private: 11 | QVector2D m_start; 12 | QVector2D m_end; 13 | 14 | public: 15 | explicit Line(const QVector2D &start, const QVector2D& end); 16 | 17 | const QVector2D &start() const; 18 | const QVector2D &end() const; 19 | 20 | bool lengthNonZero() const; 21 | float length() const; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/geometry/pocketer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace geometry 8 | { 9 | 10 | class Pocketer 11 | { 12 | private: 13 | const Polyline& m_border; 14 | const Orientation m_borderOrientation; 15 | const Polyline::ListCPtr &m_islands; 16 | const float m_margin; 17 | const float m_minimumPolylineLength; 18 | cavc::ParallelOffsetIslands m_offseter; 19 | 20 | Polyline::List m_polylines; 21 | Polyline::List m_ccwPolylines; 22 | Polyline::List m_cwPolylines; 23 | 24 | static bool isCapable(const Polyline &polyline); 25 | bool isBorderAndInslandsCapable() const; 26 | static cavc::OffsetLoop polylineToLoop(const Polyline& polyline, Orientation expectedOrientation); 27 | static cavc::OffsetLoop polylineToLoop(const Polyline& polyline, bool inverse); 28 | static Polyline loopToPolyline(const cavc::OffsetLoop &loop); 29 | static Polyline::List loopsToPolylines(const std::vector> &loops); 30 | static bool canContinueOffsetting(const cavc::OffsetLoopSet &loopSet); 31 | void pruneSingularities(std::vector> &loops) const; 32 | cavc::OffsetLoopSet baseLoopSet() const; 33 | 34 | cavc::OffsetLoopSet computeNextLoopSet(const cavc::OffsetLoopSet &loopSet); 35 | void appendLoopSetPolylines(const cavc::OffsetLoopSet &loopSet); 36 | void appendPolylines(const Polyline::List &polylines, bool inverse); 37 | void ensurePolylinesOrientationSameAsBorder(); 38 | 39 | public: 40 | explicit Pocketer(const Polyline &border, const Polyline::ListCPtr &islands, float margin, float minimumPolylineLength); 41 | 42 | Orientation borderOrientation() const; 43 | Polyline::List &&polylines(); 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/geometry/polyline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace geometry 13 | { 14 | 15 | class Polyline : public common::Aggregable 16 | { 17 | friend serializer::Access; 18 | friend class Pocketer; 19 | 20 | private: 21 | Bulge::List m_bulges; 22 | 23 | explicit Polyline(const cavc::Polyline &polyline); 24 | cavc::Polyline toCavc() const; 25 | cavc::Polyline toCavc(Orientation expectedOrientation) const; 26 | cavc::Polyline toCavc(bool inverse) const; 27 | 28 | public: 29 | explicit Polyline() = default; 30 | explicit Polyline(Bulge::List &&bulges); 31 | 32 | const QVector2D &start() const; 33 | QVector2D &start(); 34 | const QVector2D &end() const; 35 | QVector2D &end(); 36 | 37 | bool isClosed() const; 38 | bool isPoint() const; 39 | bool isLine() const; 40 | 41 | float length() const; 42 | 43 | Orientation orientation() const; 44 | 45 | Rect boundingRect() const; 46 | 47 | Polyline &invert(); 48 | Polyline inverse() const; 49 | 50 | Polyline& operator+=(const Polyline &other); 51 | 52 | template 53 | void forEachBulge(Functor &&functor) const 54 | { 55 | for (const Bulge &bulge : m_bulges) { 56 | functor(bulge); 57 | } 58 | } 59 | 60 | template 61 | void transformBulge(Functor &&functor) 62 | { 63 | for (Bulge &bulge : m_bulges) { 64 | functor(bulge); 65 | } 66 | } 67 | 68 | Polyline::List offsetted(float margin) const; 69 | 70 | void transform(const QTransform &matrix); 71 | 72 | bool operator==(const Polyline &other) const; 73 | 74 | bool equals(const Polyline &other, bool inverse) const; 75 | }; 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/geometry/quadraticspline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace geometry 6 | { 7 | 8 | class QuadraticSpline : public Spline 9 | { 10 | private: 11 | Point2DList convertClosedToQuadraticBezierPoints() const; 12 | Point2DList convertOpenedToQuadraticBezierPoints() const; 13 | 14 | Bezier::List pointsToBeziers(const Point2DList &bezierPoints) const; 15 | 16 | public: 17 | explicit QuadraticSpline(Point2DList &&points, bool closed); 18 | 19 | Bezier::List toBeziers() const; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/geometry/rect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace geometry 4 | { 5 | 6 | QVector2D minVect(const QVector2D &v1, const QVector2D &v2) 7 | { 8 | return {std::min(v1.x(), v2.x()), std::min(v1.y(), v2.y())}; 9 | } 10 | 11 | QVector2D maxVect(const QVector2D &v1, const QVector2D &v2) 12 | { 13 | return {std::max(v1.x(), v2.x()), std::max(v1.y(), v2.y())}; 14 | } 15 | 16 | Rect::Rect(const QVector2D &v) 17 | :m_min(v), 18 | m_max(v) 19 | { 20 | } 21 | 22 | Rect::Rect(const QVector2D &v1, const QVector2D& v2) 23 | :m_min(minVect(v1, v2)), 24 | m_max(maxVect(v1, v2)) 25 | { 26 | } 27 | 28 | const QVector2D &Rect::min() const 29 | { 30 | return m_min; 31 | } 32 | 33 | const QVector2D &Rect::max() const 34 | { 35 | return m_max; 36 | } 37 | 38 | QVector2D Rect::bottomLeft() const 39 | { 40 | return m_min; 41 | } 42 | 43 | QVector2D Rect::topLeft() const 44 | { 45 | return QVector2D(m_min.x(), m_max.y()); 46 | } 47 | QVector2D Rect::topRight() const 48 | { 49 | return m_max; 50 | } 51 | QVector2D Rect::bottomRight() const 52 | { 53 | return QVector2D(m_max.x(), m_min.y()); 54 | } 55 | 56 | QRectF Rect::toQt() const 57 | { 58 | const QPointF topLeft(m_min.x(), m_max.y()); 59 | const QPointF bottomRight(m_max.x(), m_min.y()); 60 | 61 | return QRectF(topLeft, bottomRight); 62 | } 63 | 64 | Rect Rect::operator|(const Rect& other) const 65 | { 66 | return Rect(minVect(min(), other.min()), maxVect(max(), other.max())); 67 | } 68 | 69 | Rect &Rect::operator|=(const Rect& other) 70 | { 71 | m_min = minVect(min(), other.min()); 72 | m_max = maxVect(max(), other.max()); 73 | return *this; 74 | } 75 | 76 | Rect Rect::operator+(const QVector2D &v) 77 | { 78 | Rect extendedRect; 79 | extendedRect.m_min = minVect(m_min, v); 80 | extendedRect.m_max = maxVect(m_max, v); 81 | 82 | return extendedRect; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/geometry/rect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace geometry 7 | { 8 | 9 | class Rect 10 | { 11 | private: 12 | QVector2D m_min; 13 | QVector2D m_max; 14 | 15 | public: 16 | Rect() = default; 17 | explicit Rect(const QVector2D &v); 18 | explicit Rect(const QVector2D &v1, const QVector2D& v2); 19 | 20 | const QVector2D &min() const; 21 | const QVector2D &max() const; 22 | 23 | QVector2D bottomLeft() const; 24 | QVector2D topLeft() const; 25 | QVector2D topRight() const; 26 | QVector2D bottomRight() const; 27 | 28 | QRectF toQt() const; 29 | 30 | Rect operator|(const Rect& other) const; 31 | Rect &operator|=(const Rect& other); 32 | Rect operator+(const QVector2D &v); 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/geometry/spline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace geometry 4 | { 5 | 6 | const Point2DList& Spline::controlPoints() const 7 | { 8 | return m_controlPoints; 9 | } 10 | 11 | bool Spline::closed() const 12 | { 13 | return m_closed; 14 | } 15 | 16 | Spline::Spline(Point2DList &&points, bool closed) 17 | :m_controlPoints(points), 18 | m_closed(closed) 19 | { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/geometry/spline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace geometry 7 | { 8 | 9 | class Spline 10 | { 11 | private: 12 | Point2DList m_controlPoints; 13 | bool m_closed; 14 | 15 | protected: 16 | const Point2DList& controlPoints() const; 17 | bool closed() const; 18 | 19 | public: 20 | explicit Spline(Point2DList &&points, bool closed); 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/importer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(dxf) 2 | add_subdirectory(dxfplot) 3 | -------------------------------------------------------------------------------- /src/importer/dxf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | entityimporter.cpp 3 | importer.cpp 4 | interface.cpp 5 | layer.cpp 6 | 7 | entityimporter.h 8 | importer.h 9 | interface.h 10 | utils.h 11 | layer.h 12 | ) 13 | 14 | add_library(importer-dxf ${SRC}) 15 | -------------------------------------------------------------------------------- /src/importer/dxf/entityimporter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace importer::dxf 4 | { 5 | 6 | BaseEntityImporter::BaseEntityImporter(Layer& layer, const Settings& settings) 7 | :m_layer(layer), 8 | m_settings(settings) 9 | { 10 | } 11 | 12 | void BaseEntityImporter::addPolyline(const geometry::Polyline& polyline) 13 | { 14 | m_layer.addPolyline(polyline); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/importer/dxf/importer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace importer::dxf 9 | { 10 | 11 | void Importer::addLayer(const DRW_Layer &layer) 12 | { 13 | if (layer.plotF) { 14 | const std::string &name = layer.name; 15 | m_nameToLayers.emplace(name, Layer(name)); 16 | } 17 | } 18 | 19 | Importer::Importer(const std::string& filename, float splineToArcPrecision, float minimumSplineLength, float minimumArcLength) 20 | :m_entityImporterSettings({splineToArcPrecision, minimumSplineLength, minimumArcLength}), 21 | m_ignoreEntities(false) 22 | { 23 | Interface interface(*this); 24 | 25 | dxfRW rw(filename.c_str()); 26 | if (!rw.read(&interface, false)) { 27 | throw common::FileCouldNotOpenException(); 28 | } 29 | } 30 | 31 | Layer::List Importer::layers() const 32 | { 33 | Layer::List layers(m_nameToLayers.size()); 34 | std::transform(m_nameToLayers.begin(), m_nameToLayers.end(), layers.begin(), 35 | [](const auto& pair){ return pair.second; }); 36 | 37 | return layers; 38 | } 39 | 40 | void Importer::startBlock() 41 | { 42 | m_ignoreEntities = true; 43 | } 44 | 45 | void Importer::endBlock() 46 | { 47 | m_ignoreEntities = false; 48 | } 49 | 50 | template <> 51 | void Importer::processEntity(const DRW_Layer &layer) 52 | { 53 | addLayer(layer); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/importer/dxf/importer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace importer::dxf 15 | { 16 | 17 | class Importer 18 | { 19 | private: 20 | const BaseEntityImporter::Settings m_entityImporterSettings; 21 | 22 | std::unordered_map m_nameToLayers; 23 | bool m_ignoreEntities; 24 | 25 | void addLayer(const DRW_Layer &layer); 26 | 27 | public: 28 | explicit Importer(const std::string &filename, float splineToArcPrecision, float minimumSplineLength, float minimumArcLength); 29 | 30 | Layer::List layers() const; 31 | 32 | template 33 | void processEntity(const Entity &entity) 34 | { 35 | if (!m_ignoreEntities) { 36 | auto it = m_nameToLayers.find(entity.layer); 37 | if (it != m_nameToLayers.end()) { 38 | Layer &layer = it->second; 39 | 40 | EntityImporter entityImporter(layer, m_entityImporterSettings); 41 | entityImporter(entity); 42 | } 43 | } 44 | } 45 | 46 | void startBlock(); 47 | void endBlock(); 48 | }; 49 | 50 | template <> 51 | void Importer::processEntity(const DRW_Layer &layer); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/importer/dxf/layer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace importer::dxf 4 | { 5 | 6 | Layer::Layer(const std::string& name) 7 | :m_name(name) 8 | { 9 | } 10 | 11 | void Layer::addPolyline(const geometry::Polyline& polyline) 12 | { 13 | m_polylines.push_back(polyline); 14 | } 15 | 16 | geometry::Polyline::List &&Layer::polylines() 17 | { 18 | return std::move(m_polylines); 19 | } 20 | 21 | const std::string& Layer::name() const 22 | { 23 | return m_name; 24 | } 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/importer/dxf/layer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace importer::dxf 8 | { 9 | 10 | class Layer : public common::Aggregable 11 | { 12 | private: 13 | geometry::Polyline::List m_polylines; 14 | std::string m_name; 15 | 16 | public: 17 | Layer() = default; 18 | 19 | explicit Layer(const std::string& name); 20 | 21 | void addPolyline(const geometry::Polyline& polyline); 22 | 23 | geometry::Polyline::List &&polylines(); 24 | 25 | const std::string& name() const; 26 | }; 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/importer/dxf/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace importer::dxf 8 | { 9 | 10 | inline QVector2D toVector2D(const DRW_Coord &coord) 11 | { 12 | return QVector2D(coord.x, coord.y); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/importer/dxfplot/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | importer.cpp 3 | 4 | importer.h 5 | ) 6 | 7 | add_library(importer-dxfplot ${SRC}) 8 | -------------------------------------------------------------------------------- /src/importer/dxfplot/importer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace importer::dxfplot 13 | { 14 | 15 | Importer::Importer(const config::Tools &tools, const config::Profiles &profiles) 16 | :m_tools(tools), 17 | m_profiles(profiles) 18 | { 19 | } 20 | 21 | model::Document::UPtr Importer::operator()(const std::string &fileName) const 22 | { 23 | std::ifstream input(fileName); 24 | 25 | return (*this)(input); 26 | } 27 | 28 | model::Document::UPtr Importer::operator()(std::istream& input) const 29 | { 30 | Archive archive(input); 31 | 32 | model::Task::UPtr task = std::make_unique(); 33 | archive(cereal::make_nvp("task", *task)); 34 | 35 | std::string profileName; 36 | archive(cereal::make_nvp("profile_name", profileName)); 37 | 38 | std::string toolName; 39 | archive(cereal::make_nvp("tool_name", toolName)); 40 | 41 | const config::Tools::Tool *tool = m_tools.get(toolName); 42 | const config::Profiles::Profile *profile = m_profiles.get(profileName); 43 | 44 | if (!tool) { 45 | throw common::ImportCouldNotFindToolConfigException(); 46 | } 47 | if (!profile) { 48 | throw common::ImportCouldNotFindProfileConfigException(); 49 | } 50 | 51 | return std::make_unique(std::move(task), *tool, *profile); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/importer/dxfplot/importer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include // TODO 8 | 9 | namespace importer::dxfplot 10 | { 11 | 12 | class Importer 13 | { 14 | private: 15 | using Archive = cereal::JSONInputArchive; 16 | 17 | const config::Tools &m_tools; 18 | const config::Profiles &m_profiles; 19 | 20 | public: 21 | explicit Importer(const config::Tools &tools, const config::Profiles &profiles); 22 | 23 | model::Document::UPtr operator()(const std::string &fileName) const; 24 | model::Document::UPtr operator()(std::istream& input) const; 25 | }; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/model/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | application.cpp 3 | document.cpp 4 | layer.cpp 5 | offsettedpath.cpp 6 | path.cpp 7 | pathsettings.cpp 8 | pathgroupsettings.cpp 9 | renderable.cpp 10 | simulation.cpp 11 | task.cpp 12 | 13 | application.h 14 | document.h 15 | layer.h 16 | path.h 17 | offsettedpath.h 18 | pathsettings.h 19 | pathgroupsettings.h 20 | renderable.h 21 | simulation.h 22 | task.h 23 | documentmodelobserver.h 24 | ) 25 | 26 | add_library(model ${SRC}) 27 | add_dependencies(model generate-config) 28 | add_coverage(model) 29 | -------------------------------------------------------------------------------- /src/model/document.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace model 4 | { 5 | 6 | Document::Document(Task::UPtr&& task, const config::Tools::Tool &toolConfig, const config::Profiles::Profile &profileConfig) 7 | :m_task(std::move(task)), 8 | m_toolConfig(&toolConfig), 9 | m_profileConfig(&profileConfig) 10 | { 11 | 12 | } 13 | 14 | Task &Document::task() 15 | { 16 | return *m_task; 17 | } 18 | 19 | const Task &Document::task() const 20 | { 21 | return *m_task; 22 | } 23 | 24 | const config::Tools::Tool &Document::toolConfig() const 25 | { 26 | return *m_toolConfig; 27 | } 28 | 29 | const config::Profiles::Profile &Document::profileConfig() const 30 | { 31 | return *m_profileConfig; 32 | } 33 | 34 | void Document::setToolConfig(const config::Tools::Tool &tool) 35 | { 36 | m_toolConfig = &tool; 37 | emit toolConfigChanged(tool); 38 | } 39 | 40 | void Document::setProfileConfig(const config::Profiles::Profile &profile) 41 | { 42 | m_profileConfig = &profile; 43 | emit profileConfigChanged(profile); 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/model/document.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace model 7 | { 8 | 9 | class Document : public QObject, public common::Aggregable 10 | { 11 | Q_OBJECT; 12 | 13 | private: 14 | Task::UPtr m_task; 15 | const config::Tools::Tool *m_toolConfig; 16 | const config::Profiles::Profile *m_profileConfig; 17 | 18 | public: 19 | explicit Document(Task::UPtr&& task, const config::Tools::Tool &toolConfig, const config::Profiles::Profile &profileConfig); 20 | Document() = default; 21 | 22 | Task& task(); 23 | const Task& task() const; 24 | 25 | const config::Tools::Tool &toolConfig() const; 26 | const config::Profiles::Profile &profileConfig() const; 27 | void setToolConfig(const config::Tools::Tool &tool); 28 | void setProfileConfig(const config::Profiles::Profile &profile); 29 | 30 | Q_SIGNALS: 31 | void toolConfigChanged(const config::Tools::Tool &tool); 32 | void profileConfigChanged(const config::Profiles::Profile &profile); 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/model/documentmodelobserver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace model 8 | { 9 | 10 | class Document; 11 | 12 | /** @brief A observer on Document changes 13 | * e.g when a file is opened the document is changed and this observers is notified. 14 | * Function @ref documentChanged is called at every changes 15 | */ 16 | template 17 | class DocumentModelObserver : public QtBaseObject 18 | { 19 | private: 20 | /// Current document. 21 | Document *m_document; 22 | 23 | /** Function called when the document in the application had changed, 24 | * m_document is ensured to be valid before. 25 | * Before the first call to this function, m_document is inaccesible. 26 | */ 27 | virtual void documentChanged() = 0; 28 | 29 | protected: 30 | Document *document() const 31 | { 32 | return m_document; 33 | } 34 | 35 | Task &task() 36 | { 37 | assert(m_document); 38 | return m_document->task(); 39 | } 40 | 41 | private Q_SLOTS: 42 | void internalDocumentChanged(Document *newDocument) 43 | { 44 | m_document = newDocument; 45 | assert(m_document); 46 | documentChanged(); 47 | } 48 | 49 | public: 50 | explicit DocumentModelObserver(Application &app) 51 | :m_document(nullptr) 52 | { 53 | QObject::connect(&app, &Application::documentChanged, this, &DocumentModelObserver::internalDocumentChanged); 54 | } 55 | 56 | }; 57 | 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/model/layer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace model 4 | { 5 | 6 | void Layer::assignSelfToChildren() 7 | { 8 | for (Path::UPtr &child : m_children) { 9 | child->setLayer(*this); 10 | } 11 | } 12 | 13 | Layer::Layer(const std::string &name, Path::ListUPtr &&children) 14 | :Renderable(name), 15 | m_children(std::move(children)) 16 | { 17 | assignSelfToChildren(); 18 | } 19 | 20 | int Layer::childrenCount() const 21 | { 22 | return m_children.size(); 23 | } 24 | 25 | 26 | Path& Layer::childrenAt(int index) 27 | { 28 | assert(0 <= index && index < childrenCount()); 29 | return *m_children[index]; 30 | } 31 | 32 | const Path& Layer::childrenAt(int index) const 33 | { 34 | assert(0 <= index && index < childrenCount()); 35 | return *m_children[index]; 36 | } 37 | 38 | int Layer::childIndexFor(const Path& child) const 39 | { 40 | const Path::ListUPtr::const_iterator it = std::find_if(m_children.cbegin(), m_children.cend(), [&child](const Path::UPtr &ptr){ return ptr.get() == &child; }); 41 | 42 | if (it == m_children.cend()) { 43 | return -1; 44 | } 45 | 46 | return std::distance(m_children.cbegin(), it); 47 | } 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/model/layer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace model 8 | { 9 | 10 | class Layer : public Renderable, public common::Aggregable 11 | { 12 | Q_OBJECT; 13 | 14 | friend serializer::Access; 15 | 16 | private: 17 | Path::ListUPtr m_children; 18 | 19 | void assignSelfToChildren(); 20 | 21 | public: 22 | explicit Layer(const std::string &name, Path::ListUPtr &&children); 23 | explicit Layer() = default; 24 | 25 | int childrenCount() const; 26 | Path& childrenAt(int index); 27 | const Path& childrenAt(int index) const; 28 | int childIndexFor(const Path& child) const; 29 | 30 | template 31 | void forEachChild(Functor &&functor) 32 | { 33 | for (Path::UPtr &child : m_children) { 34 | functor(*child); 35 | } 36 | } 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/model/offsettedpath.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace model 4 | { 5 | 6 | OffsettedPath::OffsettedPath(geometry::Polyline::List &&offsettedPolylines, Direction direction) 7 | :m_polylines(offsettedPolylines), 8 | m_direction(direction) 9 | { 10 | } 11 | 12 | const geometry::Polyline::List &OffsettedPath::polylines() const 13 | { 14 | return m_polylines; 15 | } 16 | 17 | geometry::CuttingDirection OffsettedPath::cuttingDirection() const 18 | { 19 | static const geometry::CuttingDirection offsetDirectionToCuttingDirection[] = { 20 | geometry::CuttingDirection::FORWARD, // OffsettedPath::Direction::LEFT 21 | geometry::CuttingDirection::BACKWARD // OffsettedPath::Direction::RIGHT 22 | }; 23 | 24 | return offsetDirectionToCuttingDirection[static_cast(m_direction)]; 25 | } 26 | 27 | void OffsettedPath::transform(const QTransform &matrix) 28 | { 29 | for (geometry::Polyline &polyline : m_polylines) { 30 | polyline.transform(matrix); 31 | } 32 | 33 | emit polylinesTransformed(); 34 | } 35 | 36 | geometry::Rect OffsettedPath::boundingRect() const 37 | { 38 | geometry::Polyline::List::const_iterator it = m_polylines.begin(); 39 | const geometry::Rect firstBoundingRest = (it++)->boundingRect(); 40 | 41 | return std::transform_reduce(it, m_polylines.end(), firstBoundingRest, std::bit_or(), 42 | [](const geometry::Polyline& polyline){ 43 | return polyline.boundingRect(); 44 | }); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/model/offsettedpath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace model 13 | { 14 | 15 | class Layer; 16 | 17 | class OffsettedPath : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | friend serializer::Access; 22 | 23 | public: 24 | enum class Direction 25 | { 26 | LEFT = 0, 27 | RIGHT 28 | }; 29 | 30 | private: 31 | geometry::Polyline::List m_polylines; 32 | Direction m_direction; 33 | 34 | public: 35 | explicit OffsettedPath(geometry::Polyline::List &&offsettedPolylines, Direction direction); 36 | explicit OffsettedPath() = default; 37 | 38 | const geometry::Polyline::List &polylines() const; 39 | geometry::CuttingDirection cuttingDirection() const; 40 | 41 | void transform(const QTransform &matrix); 42 | 43 | geometry::Rect boundingRect() const; 44 | 45 | Q_SIGNALS: 46 | void polylinesTransformed(); 47 | }; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/model/path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | namespace model 16 | { 17 | 18 | class Layer; 19 | 20 | class Path : public Renderable, public common::Aggregable 21 | { 22 | Q_OBJECT; 23 | 24 | friend serializer::Access; 25 | 26 | private: 27 | geometry::Polyline m_basePolyline; 28 | std::unique_ptr m_offsettedPath; 29 | PathSettings m_settings; 30 | Layer *m_layer; 31 | bool m_globallyVisible; 32 | 33 | void updateGlobalVisibility(); 34 | 35 | public: 36 | explicit Path(geometry::Polyline &&basePolyline, const std::string &name, const PathSettings& settings); 37 | explicit Path() = default; 38 | 39 | static ListUPtr FromPolylines(geometry::Polyline::List &&polylines, const PathSettings &settings, const std::string &layerName); 40 | 41 | Layer &layer(); 42 | const Layer &layer() const; 43 | void setLayer(Layer &layer); 44 | 45 | const geometry::Polyline &basePolyline() const; 46 | geometry::Polyline::List finalPolylines() const; 47 | 48 | model::OffsettedPath *offsettedPath() const; 49 | void offset(float margin, float minimumPolylineLength, float minimumArcLength); 50 | void resetOffset(); 51 | void pocket(const Path::ListCPtr &islands, float scaledRadius, float minimumPolylineLength, float minimumArcLength); 52 | 53 | void transform(const QTransform &matrix); 54 | 55 | geometry::Rect boundingRect() const; 56 | 57 | bool isPoint() const; 58 | 59 | const PathSettings &settings() const; 60 | PathSettings &settings(); 61 | 62 | geometry::CuttingDirection cuttingDirection() const; 63 | 64 | bool globallyVisible() const; 65 | 66 | Q_SIGNALS: 67 | void globalVisibilityChanged(bool globallyVisible); 68 | void offsettedPathChanged(); 69 | void basePolylineTransformed(); 70 | }; 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/model/pathgroupsettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include // TODO 4 | 5 | namespace model 6 | { 7 | 8 | PathGroupSettings::PathGroupSettings(const Task &task) 9 | :m_task(task) 10 | { 11 | } 12 | 13 | std::optional PathGroupSettings::planeFeedRate() const 14 | { 15 | return valueIfAllEqual(&PathSettings::planeFeedRate); 16 | } 17 | 18 | void PathGroupSettings::setPlaneFeedRate(float planeFeedRate) 19 | { 20 | setValue(&PathSettings::setPlaneFeedRate, planeFeedRate); 21 | } 22 | 23 | std::optional PathGroupSettings::depthFeedRate() const 24 | { 25 | return valueIfAllEqual(&PathSettings::depthFeedRate); 26 | } 27 | 28 | void PathGroupSettings::setDepthFeedRate(float depthFeedRate) 29 | { 30 | setValue(&PathSettings::setDepthFeedRate, depthFeedRate); 31 | } 32 | 33 | std::optional PathGroupSettings::intensity() const 34 | { 35 | return valueIfAllEqual(&PathSettings::intensity); 36 | } 37 | 38 | void PathGroupSettings::setIntensity(float intensity) 39 | { 40 | setValue(&PathSettings::setIntensity, intensity); 41 | } 42 | 43 | std::optional PathGroupSettings::depth() const 44 | { 45 | return valueIfAllEqual(&PathSettings::depth); 46 | } 47 | 48 | void PathGroupSettings::setDepth(float depth) 49 | { 50 | setValue(&PathSettings::setDepth, depth); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/model/pathgroupsettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace model 12 | { 13 | 14 | class PathGroupSettings : public QObject 15 | { 16 | Q_OBJECT; 17 | 18 | private: 19 | const model::Task &m_task; 20 | 21 | /** Return value of a path settings property if all path have 22 | * the same value for the given property. 23 | * 24 | * @tparam T The returned value type 25 | * @tparam Getter The member function used to acces the poperty. 26 | */ 27 | template ::Return> 28 | std::optional valueIfAllEqual(Getter &&getter) const 29 | { 30 | // Reference value of last path to compare with. 31 | Return lastValue; 32 | bool firstValue = true; 33 | bool allEqual = true; 34 | 35 | m_task.forEachSelectedPath([&lastValue, &firstValue, &allEqual, &getter](const model::Path &path){ 36 | const Return &value = (path.settings().*getter)(); 37 | if (!firstValue && lastValue != value) { 38 | allEqual = false; 39 | } 40 | firstValue = false; 41 | lastValue = value; 42 | }); 43 | 44 | if (allEqual) { 45 | return std::make_optional(lastValue); 46 | } 47 | return std::nullopt; 48 | } 49 | 50 | template 51 | void setValue(Setter &&setter, T value) 52 | { 53 | m_task.forEachSelectedPath([value, &setter](model::Path &path){ 54 | (path.settings().*(std::forward(setter)))(value); 55 | }); 56 | } 57 | 58 | public: 59 | explicit PathGroupSettings(const Task &task); 60 | 61 | std::optional planeFeedRate() const; 62 | void setPlaneFeedRate(float planeFeedRate); 63 | 64 | std::optional depthFeedRate() const; 65 | void setDepthFeedRate(float depthFeedRate); 66 | 67 | std::optional intensity() const; 68 | void setIntensity(float intensity); 69 | 70 | std::optional depth() const; 71 | void setDepth(float depth); 72 | }; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/model/pathsettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace model 4 | { 5 | 6 | PathSettings::PathSettings(float planeFeedRate, float depthFeedRate, float intensity, float depth) 7 | :m_planeFeedRate(planeFeedRate), 8 | m_depthFeedRate(depthFeedRate), 9 | m_intensity(intensity), 10 | m_depth(depth) 11 | { 12 | } 13 | 14 | float PathSettings::planeFeedRate() const 15 | { 16 | return m_planeFeedRate; 17 | } 18 | 19 | void PathSettings::setPlaneFeedRate(float planeFeedRate) 20 | { 21 | m_planeFeedRate = planeFeedRate; 22 | } 23 | 24 | float PathSettings::depthFeedRate() const 25 | { 26 | return m_depthFeedRate; 27 | } 28 | 29 | void PathSettings::setDepthFeedRate(float depthFeedRate) 30 | { 31 | m_depthFeedRate = depthFeedRate; 32 | } 33 | 34 | float PathSettings::intensity() const 35 | { 36 | return m_intensity; 37 | } 38 | 39 | void PathSettings::setIntensity(float intensity) 40 | { 41 | m_intensity = intensity; 42 | } 43 | 44 | float PathSettings::depth() const 45 | { 46 | return m_depth; 47 | } 48 | 49 | void PathSettings::setDepth(float depth) 50 | { 51 | m_depth = depth; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/model/pathsettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace model 6 | { 7 | 8 | class PathSettings 9 | { 10 | friend serializer::Access; 11 | 12 | private: 13 | float m_planeFeedRate; 14 | float m_depthFeedRate; 15 | float m_intensity; 16 | float m_depth; 17 | 18 | public: 19 | explicit PathSettings() = default; 20 | explicit PathSettings(float planeFeedRate, float depthFeedRate, float intensity, float depth); 21 | 22 | float planeFeedRate() const; 23 | void setPlaneFeedRate(float planeFeedRate); 24 | 25 | float depthFeedRate() const; 26 | void setDepthFeedRate(float depthFeedRate); 27 | 28 | float intensity() const; 29 | void setIntensity(float intensity); 30 | 31 | float depth() const; 32 | void setDepth(float depth); 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/model/renderable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace model 4 | { 5 | 6 | Renderable::Renderable(const std::string &name) 7 | :m_name(name), 8 | m_selected(false), 9 | m_visible(true) 10 | { 11 | } 12 | 13 | const std::string &Renderable::name() const 14 | { 15 | return m_name; 16 | } 17 | 18 | bool Renderable::visible() const 19 | { 20 | return m_visible; 21 | } 22 | 23 | void Renderable::setVisible(bool visible) 24 | { 25 | if (m_visible != visible) { 26 | m_visible = visible; 27 | 28 | emit visibilityChanged(m_visible); 29 | } 30 | } 31 | 32 | void Renderable::toggleVisible() 33 | { 34 | setVisible(!m_visible); 35 | } 36 | 37 | bool Renderable::selected() const 38 | { 39 | return m_selected; 40 | } 41 | 42 | void Renderable::setSelected(bool selected) 43 | { 44 | if (m_selected != selected) { 45 | m_selected = selected; 46 | 47 | emit selectedChanged(m_selected); 48 | } 49 | } 50 | 51 | void Renderable::toggleSelect() 52 | { 53 | setSelected(!m_selected); 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/model/renderable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace model 14 | { 15 | 16 | class Renderable : public QObject 17 | { 18 | Q_OBJECT; 19 | 20 | friend serializer::Access; 21 | 22 | private: 23 | std::string m_name; 24 | 25 | struct { 26 | bool m_selected : 1; 27 | bool m_visible : 1; 28 | }; 29 | 30 | public: 31 | explicit Renderable(const std::string &name); 32 | explicit Renderable() = default; 33 | 34 | const std::string &name() const; 35 | 36 | bool visible() const; 37 | void setVisible(bool visible); 38 | void toggleVisible(); 39 | 40 | bool selected() const; 41 | void setSelected(bool selected); 42 | void deselect(); 43 | void toggleSelect(); 44 | 45 | Q_SIGNALS: 46 | void selectedChanged(bool selected); 47 | void visibilityChanged(bool visible); 48 | }; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/serializer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/serializer/access.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace serializer 6 | { 7 | 8 | template 9 | struct Access; 10 | 11 | } 12 | 13 | namespace cereal 14 | { 15 | 16 | template 17 | auto save(Archive &archive, const Entity &entity, std::uint32_t const version) -> decltype(serializer::Access().save(archive, entity, version), void()) 18 | { 19 | serializer::Access access; 20 | access.save(archive, entity, version); 21 | } 22 | 23 | template 24 | auto load(Archive &archive, Entity &entity, std::uint32_t const version) -> decltype(serializer::Access().load(archive, entity, version), void()) 25 | { 26 | serializer::Access access; 27 | access.load(archive, entity, version); 28 | } 29 | 30 | template 31 | auto serialize(Archive &archive, Entity &entity, std::uint32_t const version) -> decltype(serializer::Access().serialize(archive, entity, version), void()) 32 | { 33 | serializer::Access access; 34 | access.serialize(archive, entity, version); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/serializer/bulge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace serializer 11 | { 12 | 13 | template<> 14 | struct Access 15 | { 16 | template 17 | void serialize(Archive &archive, geometry::Bulge &bulge, [[maybe_unused]] std::uint32_t const version) const 18 | { 19 | archive(cereal::make_nvp("start", bulge.start())); 20 | archive(cereal::make_nvp("end", bulge.end())); 21 | archive(cereal::make_nvp("tangent", bulge.tangent())); 22 | } 23 | }; 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/serializer/layer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace serializer 11 | { 12 | 13 | template<> 14 | struct Access 15 | { 16 | template 17 | void save(Archive &archive, const model::Layer &layer, [[maybe_unused]] std::uint32_t const version) const 18 | { 19 | archive(cereal::make_nvp("renderable", cereal::base_class(&layer))); 20 | archive(cereal::make_nvp("children", layer.m_children)); 21 | } 22 | 23 | template 24 | void load(Archive &archive, model::Layer &layer, [[maybe_unused]] std::uint32_t const version) 25 | { 26 | archive(cereal::make_nvp("renderable", cereal::base_class(&layer))); 27 | archive(cereal::make_nvp("children", layer.m_children)); 28 | 29 | layer.assignSelfToChildren(); 30 | } 31 | }; 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/serializer/offsettedpath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace serializer 11 | { 12 | 13 | template<> 14 | struct Access 15 | { 16 | template 17 | void serialize(Archive &archive, model::OffsettedPath &offsettedPath, [[maybe_unused]] std::uint32_t const version) const 18 | { 19 | archive(cereal::make_nvp("polylines", offsettedPath.m_polylines)); 20 | archive(cereal::make_nvp("direction", offsettedPath.m_direction)); 21 | } 22 | }; 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/serializer/path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace serializer 13 | { 14 | 15 | template<> 16 | struct Access 17 | { 18 | template 19 | void serialize(Archive &archive, model::Path &path, [[maybe_unused]] std::uint32_t const version) const 20 | { 21 | archive(cereal::make_nvp("renderable", cereal::base_class(&path))); 22 | archive(cereal::make_nvp("base_polyline", path.m_basePolyline)); 23 | archive(cereal::make_nvp("offsetted_path", path.m_offsettedPath)); 24 | archive(cereal::make_nvp("settings", path.m_settings)); 25 | } 26 | }; 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/serializer/pathsettings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace serializer 11 | { 12 | 13 | template<> 14 | struct Access 15 | { 16 | template 17 | void serialize(Archive &archive, model::PathSettings &pathSettings, [[maybe_unused]] std::uint32_t const version) const 18 | { 19 | archive(cereal::make_nvp("plane_feed_rate", pathSettings.m_planeFeedRate)); 20 | archive(cereal::make_nvp("depth_feed_rate", pathSettings.m_depthFeedRate)); 21 | archive(cereal::make_nvp("intensity", pathSettings.m_intensity)); 22 | archive(cereal::make_nvp("depth", pathSettings.m_depth)); 23 | } 24 | }; 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/serializer/polyline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace serializer 11 | { 12 | 13 | template<> 14 | struct Access 15 | { 16 | template 17 | void serialize(Archive &archive, geometry::Polyline &polyline, [[maybe_unused]] std::uint32_t const version) const 18 | { 19 | archive(cereal::make_nvp("bulges", polyline.m_bulges)); 20 | } 21 | }; 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/serializer/qvector2d.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace serializer 10 | { 11 | 12 | template<> 13 | struct Access 14 | { 15 | template 16 | void save(Archive &archive, const QVector2D &point, [[maybe_unused]] std::uint32_t const version) const 17 | { 18 | archive(cereal::make_nvp("x", point.x())); 19 | archive(cereal::make_nvp("y", point.y())); 20 | } 21 | 22 | template 23 | void load(Archive &archive, QVector2D &point, [[maybe_unused]] std::uint32_t const version) const 24 | { 25 | float x; 26 | archive(cereal::make_nvp("x", x)); 27 | float y; 28 | archive(cereal::make_nvp("y", y)); 29 | 30 | point.setX(x); 31 | point.setY(y); 32 | } 33 | }; 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/serializer/renderable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace serializer 10 | { 11 | 12 | template<> 13 | struct Access 14 | { 15 | template 16 | void save(Archive &archive, const model::Renderable &renderable, [[maybe_unused]] std::uint32_t const version) const 17 | { 18 | archive(cereal::make_nvp("name", renderable.m_name)); 19 | 20 | const bool visible = renderable.m_visible; 21 | archive(cereal::make_nvp("visible", visible)); 22 | } 23 | 24 | template 25 | void load(Archive &archive, model::Renderable &renderable, [[maybe_unused]] std::uint32_t const version) const 26 | { 27 | archive(cereal::make_nvp("name", renderable.m_name)); 28 | 29 | bool visible; 30 | archive(cereal::make_nvp("visible", visible)); 31 | renderable.m_visible = visible; 32 | } 33 | }; 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/view/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(dialogs) 2 | add_subdirectory(task) 3 | add_subdirectory(view2d) 4 | add_subdirectory(simulation) 5 | 6 | set(SRC 7 | info.cpp 8 | mainwindow.cpp 9 | profile.cpp 10 | 11 | info.h 12 | mainwindow.h 13 | profile.h 14 | ) 15 | 16 | add_library(view ${SRC}) 17 | add_dependencies(view generate-config uic) 18 | 19 | -------------------------------------------------------------------------------- /src/view/dialogs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(settings) 2 | 3 | set(SRC 4 | mirror.cpp 5 | transform.cpp 6 | setorigin.cpp 7 | 8 | mirror.h 9 | transform.h 10 | setorigin.h 11 | ) 12 | 13 | add_library(view-dialogs ${SRC}) 14 | add_dependencies(view-dialogs uic-dialogs) 15 | 16 | -------------------------------------------------------------------------------- /src/view/dialogs/mirror.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | namespace view::dialogs 5 | { 6 | 7 | Mirror::Mirror() 8 | { 9 | setupUi(this); 10 | } 11 | 12 | const QTransform &Mirror::matrix() const 13 | { 14 | return m_matrix; 15 | } 16 | 17 | void Mirror::accept() 18 | { 19 | QDialog::accept(); 20 | 21 | const float scaleX = mirrorX->isChecked() ? -1.0f : 1.0f; 22 | const float scaleY = mirrorY->isChecked() ? -1.0f : 1.0f; 23 | m_matrix.scale(scaleX, scaleY); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/view/dialogs/mirror.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | 8 | namespace view::dialogs 9 | { 10 | 11 | class Mirror : public QDialog, private Ui::Mirror 12 | { 13 | private: 14 | QTransform m_matrix; 15 | 16 | public: 17 | explicit Mirror(); 18 | 19 | const QTransform &matrix() const; 20 | 21 | void accept() override; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/view/dialogs/setorigin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | namespace view::dialogs 5 | { 6 | 7 | void SetOrigin::setupButtonGroup() 8 | { 9 | m_buttonGroup.addButton(topLeftCheckBox, static_cast(Corner::TopLeft)); 10 | m_buttonGroup.addButton(bottomLeftCheckBox, static_cast(Corner::BottomLeft)); 11 | m_buttonGroup.addButton(topRightCheckBox, static_cast(Corner::TopRight)); 12 | m_buttonGroup.addButton(bottomRightCheckBox, static_cast(Corner::BottomRight)); 13 | } 14 | 15 | QVector2D SetOrigin::boundingRectCornerPosition(Corner corner) const 16 | { 17 | switch (corner) { 18 | case Corner::TopLeft: 19 | return m_selectionBoundingRect.topLeft(); 20 | case Corner::BottomLeft: 21 | return m_selectionBoundingRect.bottomLeft(); 22 | case Corner::TopRight: 23 | return m_selectionBoundingRect.topRight(); 24 | case Corner::BottomRight: 25 | default: 26 | return m_selectionBoundingRect.bottomRight(); 27 | } 28 | } 29 | 30 | SetOrigin::SetOrigin(const geometry::Rect &selectionBoundingRect) 31 | :m_selectionBoundingRect(selectionBoundingRect) 32 | { 33 | setupUi(this); 34 | 35 | setupButtonGroup(); 36 | } 37 | 38 | const QTransform &SetOrigin::matrix() const 39 | { 40 | return m_matrix; 41 | } 42 | 43 | void SetOrigin::accept() 44 | { 45 | QDialog::accept(); 46 | 47 | const int buttonId = m_buttonGroup.checkedId(); 48 | const Corner corner = static_cast(buttonId); 49 | const QVector2D offset = boundingRectCornerPosition(corner); 50 | 51 | m_matrix.translate(-offset.x(), -offset.y()); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/view/dialogs/setorigin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace view::dialogs 11 | { 12 | 13 | class SetOrigin : public QDialog, private Ui::SetOrigin 14 | { 15 | private: 16 | const geometry::Rect &m_selectionBoundingRect; 17 | QTransform m_matrix; 18 | 19 | QButtonGroup m_buttonGroup; 20 | 21 | enum class Corner { 22 | BottomLeft = 0, 23 | TopLeft, 24 | BottomRight, 25 | TopRight 26 | }; 27 | 28 | void setupButtonGroup(); 29 | QVector2D boundingRectCornerPosition(Corner corner) const; 30 | 31 | public: 32 | explicit SetOrigin(const geometry::Rect &selectionBoundingRect); 33 | 34 | const QTransform &matrix() const; 35 | 36 | void accept() override; 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/view/dialogs/settings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | list.cpp 3 | settings.cpp 4 | treemodel.cpp 5 | 6 | entry.h 7 | group.h 8 | list.h 9 | settings.h 10 | treemodel.h 11 | ) 12 | 13 | add_library(view-dialogs-settings ${SRC}) 14 | add_dependencies(view-dialogs-settings generate-config uic-dialogs-settings) 15 | -------------------------------------------------------------------------------- /src/view/dialogs/settings/group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace view::settings 10 | { 11 | 12 | class Group : public QGroupBox, private Ui::Group 13 | { 14 | private: 15 | /// Node visitor populating form layout with properties if any 16 | class PropertyVisitor 17 | { 18 | private: 19 | Group &m_parent; 20 | 21 | public: 22 | explicit PropertyVisitor(Group &parent) 23 | :m_parent(parent) 24 | { 25 | } 26 | 27 | template 28 | void operator()(config::Property &property) 29 | { 30 | Entry *entry = new Entry(property, &m_parent); 31 | 32 | m_parent.formLayout->addRow(QString::fromStdString(property.name()), entry); 33 | } 34 | 35 | template 36 | void operator()(Node &) 37 | { 38 | } 39 | }; 40 | 41 | public: 42 | template 43 | explicit Group(Node &node) 44 | { 45 | setupUi(this); 46 | 47 | setTitle(QString::fromStdString(node.name())); 48 | // Populate properties 49 | node.visitChildren(PropertyVisitor(*this)); 50 | } 51 | }; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/view/dialogs/settings/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace view::settings 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/view/dialogs/settings/list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace view::settings 9 | { 10 | 11 | class List : public QGroupBox, private Ui::List 12 | { 13 | public: 14 | template 15 | explicit List(Node &node) 16 | { 17 | setupUi(this); 18 | 19 | setTitle(QString::fromStdString(node.name())); 20 | } 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/view/dialogs/settings/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace view::settings 12 | { 13 | 14 | class TreeModel; 15 | 16 | class Settings : public QDialog, private Ui::Settings 17 | { 18 | private: 19 | class NodeVisitor; 20 | 21 | void setupUi(); 22 | 23 | // Modified config 24 | config::Config &m_newConfig; 25 | std::unique_ptr m_model; 26 | 27 | public: 28 | explicit Settings(config::Config &newConfig); 29 | ~Settings(); 30 | 31 | protected Q_SLOTS: 32 | void currentChanged(const QModelIndex &index, const QModelIndex &previous); 33 | void addItem(const QModelIndex &index); 34 | void removeItem(const QModelIndex &index); 35 | void copyItem(const QModelIndex &index); 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/view/dialogs/transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | namespace view::dialogs 5 | { 6 | 7 | Transform::Transform() 8 | { 9 | setupUi(this); 10 | } 11 | 12 | const QTransform &Transform::matrix() const 13 | { 14 | return m_matrix; 15 | } 16 | 17 | void Transform::accept() 18 | { 19 | QDialog::accept(); 20 | 21 | m_matrix.translate(offsetXSpinBox->value(), offsetYSpinBox->value()); 22 | m_matrix.rotate(angleSpinBox->value()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/view/dialogs/transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | 8 | namespace view::dialogs 9 | { 10 | 11 | class Transform : public QDialog, private Ui::Transform 12 | { 13 | private: 14 | QTransform m_matrix; 15 | 16 | public: 17 | explicit Transform(); 18 | 19 | const QTransform &matrix() const; 20 | 21 | void accept() override; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/view/info.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace view 6 | { 7 | 8 | void Info::showTimedMessage(const QString &content) 9 | { 10 | message->setText(content); 11 | stackedWidget->setCurrentWidget(messagePage); 12 | 13 | constexpr int showMessageDelay = 2000; 14 | m_timer.start(showMessageDelay); 15 | } 16 | 17 | Info::Info(const view2d::Viewport &viewport, const model::Application &app) 18 | { 19 | setupUi(this); 20 | 21 | connect(&viewport, &view2d::Viewport::cursorMoved, this, &Info::cursorMoved); 22 | connect(&app, &model::Application::fileSaved, this, &Info::fileSaved); 23 | connect(&m_timer, &QTimer::timeout, this, &Info::hideMessage); 24 | } 25 | 26 | void Info::cursorMoved(const QPointF &position) 27 | { 28 | cursorX->setText(QString::number(position.x())); 29 | cursorY->setText(QString::number(position.y())); 30 | } 31 | 32 | void Info::fileSaved(const QString &fileName) 33 | { 34 | showTimedMessage(QString("Saved %1").arg(fileName)); 35 | } 36 | 37 | void Info::hideMessage() 38 | { 39 | stackedWidget->setCurrentWidget(cursorPage); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/view/info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace model 9 | { 10 | 11 | class Application; 12 | 13 | } 14 | 15 | namespace view 16 | { 17 | 18 | namespace view2d 19 | { 20 | 21 | class Viewport; 22 | 23 | } 24 | 25 | class Info : public QWidget, private Ui::Info 26 | { 27 | private: 28 | QTimer m_timer; 29 | 30 | void showTimedMessage(const QString &content); 31 | 32 | public: 33 | explicit Info(const view2d::Viewport &viewport, const model::Application &app); 34 | 35 | protected Q_SLOTS: 36 | void cursorMoved(const QPointF &position); 37 | void fileSaved(const QString &fileName); 38 | void hideMessage(); 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/view/mainwindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | class QComboBox; 11 | 12 | 13 | namespace view 14 | { 15 | 16 | namespace simulation 17 | { 18 | 19 | class Simulation; 20 | 21 | } 22 | 23 | class MainWindow : public QMainWindow, private Ui::MainWindow 24 | { 25 | private: 26 | model::Application &m_app; 27 | 28 | simulation::Simulation *m_simulation; 29 | 30 | QActionGroup m_openedDocumentActions; 31 | 32 | QWidget *setupLeftPanel(); 33 | QWidget *setupCenterPanel(); 34 | void setupToolBar(); 35 | void setupUi(); 36 | void setupMenuActions(); 37 | void setupOpenedDocumentActions(); 38 | 39 | void setDocumentToolsEnabled(bool enabled); 40 | 41 | QString defaultFileName(const QString &extension) const; 42 | 43 | public: 44 | explicit MainWindow(model::Application &app); 45 | 46 | protected Q_SLOTS: 47 | void openFile(); 48 | void saveFile(); 49 | void saveAsFile(); 50 | void exportFile(); 51 | void exportAsFile(); 52 | void openSettings(); 53 | void transformSelection(); 54 | void mirrorSelection(); 55 | void setSelectionOrigin(); 56 | void documentChanged(model::Document *newDocument); 57 | void displayError(const QString &message); 58 | 59 | signals: 60 | void simulate(); 61 | }; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/view/profile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | namespace view 7 | { 8 | 9 | void Profile::updateAllComboBoxesItems() 10 | { 11 | updateComboBoxItems(m_app.config().root().tools(), toolComboBox); 12 | updateComboBoxItems(m_app.config().root().profiles(), profileComboBox); 13 | } 14 | 15 | Profile::Profile(model::Application& app) 16 | :DocumentModelObserver(app), 17 | m_app(app), 18 | m_outsideToolChangeBlocked(false), 19 | m_outsideProfileChangeBlocked(false) 20 | { 21 | setupUi(this); 22 | 23 | updateAllComboBoxesItems(); 24 | 25 | connect(&app, &model::Application::configChanged, this, &Profile::configChanged); 26 | connect(toolComboBox, &QComboBox::currentTextChanged, this, &Profile::currentToolTextChanged); 27 | connect(profileComboBox, &QComboBox::currentTextChanged, this, &Profile::currentProfileTextChanged); 28 | } 29 | 30 | void Profile::documentChanged() 31 | { 32 | connect(document(), &model::Document::toolConfigChanged, this, &Profile::toolConfigChanged); 33 | connect(document(), &model::Document::profileConfigChanged, this, &Profile::profileConfigChanged); 34 | 35 | toolComboBox->setCurrentText(QString::fromStdString(document()->toolConfig().name())); 36 | profileComboBox->setCurrentText(QString::fromStdString(document()->profileConfig().name())); // TODO updateTextFromProfileConfig 37 | } 38 | 39 | void Profile::configChanged([[maybe_unused]] const config::Config &config) 40 | { 41 | updateAllComboBoxesItems(); 42 | } 43 | 44 | void Profile::toolConfigChanged(const config::Tools::Tool& tool) 45 | { 46 | if (!m_outsideToolChangeBlocked) { 47 | toolComboBox->setCurrentText(QString::fromStdString(tool.name())); 48 | } 49 | } 50 | 51 | void Profile::currentToolTextChanged(const QString& toolName) 52 | { 53 | m_outsideToolChangeBlocked = true; 54 | 55 | m_app.selectTool(toolName); 56 | 57 | m_outsideToolChangeBlocked = false; 58 | } 59 | 60 | void Profile::profileConfigChanged(const config::Profiles::Profile& profile) 61 | { 62 | if (!m_outsideProfileChangeBlocked) { 63 | profileComboBox->setCurrentText(QString::fromStdString(profile.name())); 64 | } 65 | } 66 | 67 | void Profile::currentProfileTextChanged(const QString& profileName) 68 | { 69 | m_outsideProfileChangeBlocked = true; 70 | 71 | m_app.selectProfile(profileName); 72 | 73 | m_outsideProfileChangeBlocked = false; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/view/profile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | 8 | namespace view 9 | { 10 | 11 | class Profile : public model::DocumentModelObserver, public Ui::Profile 12 | { 13 | private: 14 | model::Application &m_app; 15 | 16 | bool m_outsideToolChangeBlocked; 17 | bool m_outsideProfileChangeBlocked; 18 | 19 | template 20 | void updateComboBoxItems(const ConfigList &list, QComboBox *comboBox) 21 | { 22 | // Keep current item selected. 23 | const QString ¤tItemName = comboBox->currentText(); 24 | 25 | comboBox->clear(); 26 | 27 | list.visitChildren([comboBox](const auto &item){ 28 | const QString name = QString::fromStdString(item.name()); 29 | comboBox->addItem(name, name); 30 | }); 31 | 32 | // Try to restore selected tool name 33 | comboBox->setCurrentText(currentItemName); 34 | } 35 | 36 | void updateAllComboBoxesItems(); 37 | 38 | public: 39 | explicit Profile(model::Application &app); 40 | 41 | protected: 42 | void documentChanged() override; 43 | 44 | public Q_SLOTS: 45 | void configChanged(const config::Config &config); 46 | void toolConfigChanged(const config::Tools::Tool &tool); 47 | void currentToolTextChanged(const QString &toolName); 48 | void profileConfigChanged(const config::Profiles::Profile &profile); 49 | void currentProfileTextChanged(const QString &profileName); 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/view/simulation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(internal) 2 | 3 | set(SRC 4 | simulation.cpp 5 | 6 | simulation.h 7 | ) 8 | 9 | add_library(view-simulation ${SRC}) 10 | add_dependencies(view-simulation generate-config uic) 11 | -------------------------------------------------------------------------------- /src/view/simulation/internal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | scene.cpp 3 | toolpath.cpp 4 | tool.cpp 5 | viewport.cpp 6 | 7 | scene.h 8 | toolpath.h 9 | tool.h 10 | viewport.h 11 | ) 12 | 13 | add_library(view-simulation-internal ${SRC}) 14 | -------------------------------------------------------------------------------- /src/view/simulation/internal/scene.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace view::simulation::internal 6 | { 7 | 8 | Scene::Scene(const model::Simulation& simulation) 9 | :m_tool(this, simulation.toolRadius(), 1.0f), 10 | m_toolPath(this, simulation.approximatedToolPathToLines(0.01)) 11 | { 12 | } 13 | 14 | void Scene::setToolPosition(const model::Simulation::ToolPathPoint3D& position) 15 | { 16 | m_tool.setPosition(position); 17 | } 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/view/simulation/internal/scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace view::simulation::internal 7 | { 8 | 9 | class Scene : public Qt3DCore::QEntity 10 | { 11 | private: 12 | Tool m_tool; 13 | ToolPath m_toolPath; 14 | 15 | public: 16 | explicit Scene(const model::Simulation& simulation); 17 | 18 | void setToolPosition(const model::Simulation::ToolPathPoint3D& position); 19 | }; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/view/simulation/internal/tool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace view::simulation::internal 6 | { 7 | 8 | Tool::Tool(Qt3DCore::QEntity *parent, float radius, float height) 9 | :Qt3DCore::QEntity(parent), 10 | m_transform(new Qt3DCore::QTransform(this)), 11 | m_material(new Qt3DExtras::QGoochMaterial(this)), 12 | m_halfHeight(0.0f, 0.0f, height / 2.0f) 13 | { 14 | Qt3DExtras::QCylinderMesh *mesh = new Qt3DExtras::QCylinderMesh(this); 15 | mesh->setRadius(radius); 16 | mesh->setLength(height); 17 | 18 | m_transform->setRotationX(90); 19 | m_transform->setTranslation(m_halfHeight); 20 | 21 | addComponent(m_transform); 22 | addComponent(mesh); 23 | addComponent(m_material); 24 | } 25 | 26 | void Tool::setPosition(const model::Simulation::ToolPathPoint3D& position) 27 | { 28 | m_transform->setTranslation(position.position + m_halfHeight); 29 | 30 | static const QColor colorsByMoveType[] = { 31 | {240, 248, 255}, 32 | {105, 105, 105} 33 | }; 34 | 35 | const QColor &colorForCurrentMoveType = colorsByMoveType[static_cast(position.moveType)]; 36 | m_material->setDiffuse(colorForCurrentMoveType); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/view/simulation/internal/tool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace view::simulation::internal 10 | { 11 | 12 | class Tool : public Qt3DCore::QEntity 13 | { 14 | private: 15 | Qt3DCore::QTransform *m_transform; 16 | Qt3DExtras::QGoochMaterial *m_material; 17 | const QVector3D m_halfHeight; 18 | 19 | public: 20 | explicit Tool(Qt3DCore::QEntity *parent, float radius, float height); 21 | 22 | void setPosition(const model::Simulation::ToolPathPoint3D& position); 23 | }; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/view/simulation/internal/toolpath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace view::simulation::internal 8 | { 9 | 10 | struct PackedVector3D; 11 | 12 | class ToolPath : public Qt3DCore::QEntity 13 | { 14 | private: 15 | double m_boundingBox[6]; 16 | 17 | std::unique_ptr m_packedPoints; 18 | std::unique_ptr m_colors; 19 | std::unique_ptr m_indices; 20 | 21 | void createPolylineFromPoints(const model::Simulation::ToolPathPoint3D::List &points); 22 | 23 | public: 24 | ToolPath() = default; 25 | explicit ToolPath(Qt3DCore::QEntity *parent, const model::Simulation::ToolPathPoint3D::List &points); 26 | ~ToolPath(); 27 | 28 | const double (&boundingBox() const)[6]; 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/view/simulation/internal/viewport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace view::simulation::internal 13 | { 14 | 15 | void Viewport::mousePressEvent(QMouseEvent *e) 16 | { 17 | if (e->buttons() & Qt::MiddleButton) { 18 | m_lastMousePos = e->pos(); 19 | } 20 | } 21 | 22 | void Viewport::mouseMoveEvent(QMouseEvent *e) 23 | { 24 | if (e->buttons() & Qt::MiddleButton) { 25 | const QPoint delta = computeMouseDelta(e->pos()); 26 | 27 | const bool shiftCenter = e->modifiers() & Qt::ShiftModifier; 28 | if (shiftCenter) { 29 | const bool slowMotion = e->modifiers() & Qt::ControlModifier; 30 | const float factor = slowMotion ? 0.001f : 0.01f; 31 | const QVector3D translation(-delta.x() * factor, delta.y() * factor, 0.0f); 32 | camera()->translate(translation); 33 | } 34 | else { 35 | camera()->panAboutViewCenter(-delta.x()); 36 | camera()->tiltAboutViewCenter(delta.y()); 37 | } 38 | } 39 | } 40 | 41 | void Viewport::wheelEvent(QWheelEvent *e) 42 | { 43 | const QPoint numPixels = e->pixelDelta(); 44 | 45 | const bool slowMotion = e->modifiers() & Qt::ControlModifier; 46 | const float factor = slowMotion ? 0.001f : 0.1f; 47 | 48 | const QVector3D translation(0.0f, 0.0f, numPixels.y() * factor); 49 | camera()->translate(translation, Qt3DRender::QCamera::DontTranslateViewCenter); 50 | } 51 | 52 | QPoint Viewport::computeMouseDelta(const QPoint &pos) 53 | { 54 | const QPoint delta = pos - m_lastMousePos; 55 | m_lastMousePos = pos; 56 | 57 | return delta; 58 | } 59 | 60 | Viewport::Viewport() 61 | { 62 | defaultFrameGraph()->setClearColor(QColor(0, 0, 0)); 63 | } 64 | 65 | QWidget *Viewport::container() 66 | { 67 | return QWidget::createWindowContainer(this); 68 | } 69 | 70 | void Viewport::setScene(Scene *scene) 71 | { 72 | setRootEntity(scene); 73 | 74 | camera()->setPosition(QVector3D(0, 0, 40.0f)); 75 | camera()->viewAll(); 76 | camera()->setViewCenter(QVector3D(0.0f, 0.0f, 0.0f)); 77 | } 78 | 79 | bool Viewport::event(QEvent *e) 80 | { 81 | return Qt3DWindow::event(e); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/view/simulation/internal/viewport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class QMouseEvent; 6 | class QWheelEvent; 7 | 8 | namespace view::simulation::internal 9 | { 10 | 11 | class Scene; 12 | 13 | class Viewport : public Qt3DExtras::Qt3DWindow 14 | { 15 | private: 16 | void mousePressEvent(QMouseEvent *e) final; 17 | void mouseMoveEvent(QMouseEvent *e) final; 18 | void wheelEvent(QWheelEvent *e) final; 19 | 20 | QPoint m_lastMousePos; 21 | QPoint computeMouseDelta(const QPoint& pos); 22 | 23 | public: 24 | explicit Viewport(); 25 | 26 | QWidget *container(); 27 | 28 | void setScene(Scene *scene); 29 | 30 | bool event(QEvent *e) override; 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/view/simulation/simulation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace view::simulation 8 | { 9 | 10 | static void setLabelTimeText(QLabel *label, int ms) 11 | { 12 | const QString timeText = QTime::fromMSecsSinceStartOfDay(ms).toString("hh:mm:ss:zzz"); 13 | label->setText(timeText); 14 | } 15 | 16 | void Simulation::moveToolAtTime(int ms) 17 | { 18 | setLabelTimeText(timeLabel, ms); 19 | 20 | const float seconds = float(ms) / 1e3; 21 | const model::Simulation::ToolPathPoint3D toolPosition = m_simulation.toolPositionAtTime(seconds); 22 | 23 | m_scene->setToolPosition(toolPosition); 24 | } 25 | 26 | void Simulation::startStopToolAnimation() 27 | { 28 | if (m_timer.isActive()) { 29 | m_timer.stop(); 30 | startStopButton->setIcon(QIcon(":/icons/playback-start.svg")); 31 | } 32 | else { 33 | m_timer.start(); 34 | startStopButton->setIcon(QIcon(":/icons/playback-pause.svg")); 35 | } 36 | } 37 | 38 | Simulation::Simulation() 39 | :m_viewport(new internal::Viewport()) 40 | { 41 | setupUi(this); 42 | 43 | connect(timeSlider, &QSlider::valueChanged, this, &Simulation::moveToolAtTime); 44 | connect(startStopButton, &QPushButton::clicked, this, &Simulation::startStopToolAnimation); 45 | 46 | addAction(actionPauseResume); 47 | 48 | container->addWidget(m_viewport->container()); 49 | 50 | static const int timerBaseIntervalMs = 30; 51 | m_timer.setInterval(timerBaseIntervalMs); 52 | m_timer.callOnTimeout([this](){ 53 | const int timerIntervalMs = timerBaseIntervalMs * speedSpinBox->value(); 54 | timeSlider->setSliderPosition(timeSlider->sliderPosition() + timerIntervalMs); 55 | }); 56 | } 57 | 58 | Simulation::~Simulation() = default; 59 | 60 | void Simulation::setSimulation(model::Simulation && simulation) 61 | { 62 | m_simulation = std::move(simulation); 63 | 64 | internal::Scene *newScene = new internal::Scene(m_simulation); 65 | m_viewport->setScene(newScene); 66 | m_scene.reset(newScene); 67 | 68 | const float secondDuration = m_simulation.duration(); 69 | const int durationMs = secondDuration * 1e3; 70 | timeSlider->setMaximum(durationMs); 71 | 72 | setLabelTimeText(totalTimeLabel, durationMs); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/view/simulation/simulation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "uic/simulation/ui_simulation.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace view::simulation 11 | { 12 | 13 | namespace internal 14 | { 15 | 16 | class Scene; 17 | class Viewport; 18 | 19 | } 20 | 21 | class Simulation : private Ui::Simulation, public QWidget 22 | { 23 | private: 24 | model::Simulation m_simulation; 25 | 26 | std::unique_ptr m_viewport; 27 | std::unique_ptr m_scene; 28 | 29 | QTimer m_timer; 30 | 31 | protected slots: 32 | void moveToolAtTime(int ms); 33 | void startStopToolAnimation(); 34 | 35 | public: 36 | explicit Simulation(); 37 | ~Simulation(); 38 | 39 | void setSimulation(model::Simulation&& simulation); 40 | }; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/view/task/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | path.cpp 3 | task.cpp 4 | pathlistmodel.cpp 5 | layertreemodel.cpp 6 | 7 | path.h 8 | task.h 9 | pathlistmodel.h 10 | layertreemodel.h 11 | ) 12 | 13 | add_library(view-task ${SRC}) 14 | add_dependencies(view-task generate-config uic) 15 | -------------------------------------------------------------------------------- /src/view/task/layertreemodel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace view::task 11 | { 12 | 13 | class LayerTreeModel: public QAbstractItemModel 14 | { 15 | Q_OBJECT 16 | 17 | private: 18 | model::Task &m_task; 19 | 20 | public: 21 | explicit LayerTreeModel(model::Task &task, QObject *parent); 22 | 23 | QVariant data(const QModelIndex &index, int role) const override; 24 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 25 | QModelIndex parent(const QModelIndex &index) const override; 26 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 27 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; 28 | Qt::ItemFlags flags(const QModelIndex &index) const override; 29 | 30 | void itemClicked(const QModelIndex &index); 31 | void updateItemSelection(const model::Path &path, QItemSelectionModel::SelectionFlag flag, QItemSelectionModel *selectionModel); 32 | void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/view/task/path.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace view::task 4 | { 5 | 6 | void Path::setupModel() 7 | { 8 | m_groupSettings.reset(new model::PathGroupSettings(task())); 9 | 10 | hide(); 11 | 12 | connect(&task(), &model::Task::selectionChanged, this, &Path::selectionChanged); 13 | 14 | connectOnFieldChanged(planeFeedRate, [this](double value) { m_groupSettings->setPlaneFeedRate(value); }); 15 | connectOnFieldChanged(depthFeedRate, [this](double value) { m_groupSettings->setDepthFeedRate(value); }); 16 | connectOnFieldChanged(intensity, [this](double value) { m_groupSettings->setIntensity(value); }); 17 | connectOnFieldChanged(Ui::Path::depth, [this](double value) { m_groupSettings->setDepth(value); }); 18 | } 19 | 20 | void Path::documentChanged() 21 | { 22 | setupModel(); 23 | } 24 | 25 | Path::Path(model::Application &app) 26 | :DocumentModelObserver(app) 27 | { 28 | setupUi(this); 29 | } 30 | 31 | void Path::selectionChanged(bool empty) 32 | { 33 | if (empty) { 34 | hide(); 35 | } 36 | else { 37 | show(); 38 | 39 | updateFieldValue(planeFeedRate, m_groupSettings->planeFeedRate()); 40 | updateFieldValue(depthFeedRate, m_groupSettings->depthFeedRate()); 41 | updateFieldValue(intensity, m_groupSettings->intensity()); 42 | updateFieldValue(Ui::Path::depth, m_groupSettings->depth()); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/view/task/path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace view::task 12 | { 13 | 14 | class Path : public model::DocumentModelObserver, private Ui::Path 15 | { 16 | private: 17 | std::unique_ptr m_groupSettings; 18 | 19 | void selectionChanged(bool empty); 20 | 21 | template 22 | void connectOnFieldChanged(Field *field, std::function &&func) 23 | { 24 | connect(field, static_cast(&Field::valueChanged), this, func); 25 | } 26 | 27 | template 28 | void updateFieldValue(Field *field, std::optional &&valueOpt) 29 | { 30 | if (valueOpt) { 31 | field->setValue(*valueOpt); 32 | } 33 | else { 34 | field->clear(); 35 | } 36 | } 37 | 38 | void setupModel(); 39 | 40 | protected: 41 | void documentChanged() override; 42 | 43 | public: 44 | explicit Path(model::Application &app); 45 | 46 | }; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/view/task/pathlistmodel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace view::task 11 | { 12 | 13 | class PathListModel : public QAbstractListModel 14 | { 15 | Q_OBJECT 16 | 17 | private: 18 | model::Task &m_task; 19 | 20 | public: 21 | explicit PathListModel(model::Task &task, QObject *parent); 22 | 23 | QVariant data(const QModelIndex &index, int role) const override; 24 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 25 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; 26 | Qt::ItemFlags flags(const QModelIndex &index) const override; 27 | 28 | QModelIndex movePath(const QModelIndex &index, model::Task::MoveDirection direction); 29 | void itemClicked(const QModelIndex &index); 30 | 31 | void updateItemSelection(const model::Path &path, QItemSelectionModel::SelectionFlag flag, QItemSelectionModel *selectionModel); 32 | void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/view/task/task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace view::task 10 | { 11 | 12 | Task::Task(model::Application &app) 13 | :DocumentModelObserver(app) 14 | { 15 | setupUi(this); 16 | } 17 | 18 | void Task::setupModel() 19 | { 20 | m_pathListModel = setupTreeViewModel(pathsTreeView); 21 | m_layerTreeModel = setupTreeViewModel(layersTreeView); 22 | 23 | layersTreeView->expandAll(); 24 | } 25 | 26 | void Task::setupController() 27 | { 28 | // Track outside path selection, e.g from graphics view. 29 | connect(&task(), &model::Task::pathSelectedChanged, this, &Task::pathSelectedChanged); 30 | 31 | setupTreeViewController(m_pathListModel, pathsTreeView); 32 | setupTreeViewController(m_layerTreeModel, layersTreeView); 33 | 34 | connect(moveUp, &QPushButton::pressed, [this](){ moveCurrentPath(model::Task::MoveDirection::UP); }); 35 | connect(moveDown, &QPushButton::pressed, [this](){ moveCurrentPath(model::Task::MoveDirection::DOWN); }); 36 | } 37 | 38 | void Task::updateItemSelection(const model::Path &path, QItemSelectionModel::SelectionFlag flag) 39 | { 40 | m_pathListModel->updateItemSelection(path, flag, pathsTreeView->selectionModel()); 41 | m_layerTreeModel->updateItemSelection(path, flag, layersTreeView->selectionModel()); 42 | } 43 | 44 | void Task::documentChanged() 45 | { 46 | setupModel(); 47 | setupController(); 48 | } 49 | 50 | void Task::pathSelectedChanged(model::Path &path, bool selected) 51 | { 52 | updateItemSelection(path, 53 | selected ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); 54 | } 55 | 56 | void Task::moveCurrentPath(model::Task::MoveDirection direction) 57 | { 58 | QItemSelectionModel *selectionModel = pathsTreeView->selectionModel(); 59 | const QModelIndex currentSelectedIndex = selectionModel->currentIndex(); 60 | const QModelIndex newSelectedIndex = m_pathListModel->movePath(currentSelectedIndex, direction); 61 | selectionModel->setCurrentIndex(newSelectedIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/view/task/task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace view::task 12 | { 13 | 14 | class PathListModel; 15 | class LayerTreeModel; 16 | 17 | class Task : public model::DocumentModelObserver, private Ui::Task 18 | { 19 | private: 20 | std::unique_ptr m_pathListModel; 21 | std::unique_ptr m_layerTreeModel; 22 | 23 | template 24 | std::unique_ptr setupTreeViewModel(QTreeView *treeView) 25 | { 26 | std::unique_ptr model = std::make_unique(task(), this); 27 | treeView->setModel(model.get()); 28 | 29 | QHeaderView *header = treeView->header(); 30 | header->setStretchLastSection(false); 31 | header->setSectionResizeMode(0, QHeaderView::Stretch); 32 | header->setSectionResizeMode(1, QHeaderView::ResizeToContents); 33 | 34 | return model; 35 | } 36 | 37 | template 38 | void setupTreeViewController(std::unique_ptr& model, QTreeView *treeView) 39 | { 40 | // Synchronize selection in 2D view 41 | QItemSelectionModel *selectionModel = treeView->selectionModel(); 42 | connect(selectionModel, &QItemSelectionModel::selectionChanged, model.get(), &Model::selectionChanged); 43 | 44 | connect(treeView, &QTreeView::clicked, model.get(), &Model::itemClicked); 45 | } 46 | 47 | void setupModel(); 48 | void setupController(); 49 | 50 | void updateItemSelection(const model::Path &path, QItemSelectionModel::SelectionFlag flag); 51 | 52 | public: 53 | explicit Task(model::Application &app); 54 | 55 | protected: 56 | void documentChanged(); 57 | 58 | protected Q_SLOTS: 59 | void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 60 | void pathSelectedChanged(model::Path &path, bool selected); 61 | void moveCurrentPath(model::Task::MoveDirection direction); 62 | }; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/view/transform.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/src/view/transform.h -------------------------------------------------------------------------------- /src/view/view2d/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | basicpathitem.cpp 3 | bulgepainter.cpp 4 | offsettedpolylinepathitem.cpp 5 | pointpathitem.cpp 6 | polylinepathitem.cpp 7 | rubberband.cpp 8 | viewport.cpp 9 | 10 | basicpathitem.h 11 | bulgepainter.h 12 | offsettedpolylinepathitem.h 13 | pointpathitem.h 14 | polylinepathitem.h 15 | rubberband.h 16 | viewport.h 17 | ) 18 | 19 | add_library(view-view2d ${SRC}) 20 | add_dependencies(view-view2d generate-config uic) 21 | -------------------------------------------------------------------------------- /src/view/view2d/basicpathitem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace view::view2d 8 | { 9 | 10 | static const QBrush normalBrush(Qt::white); 11 | static const QBrush selectBrush(QColor(80, 0, 255)); 12 | static const QPen normalPen(normalBrush, 0.0f); 13 | static const QPen selectPen(selectBrush, 0.0f); 14 | 15 | BasicPathItem::BasicPathItem(model::Path &path) 16 | :m_path(path), 17 | m_outsideSelectionBlocked(false) 18 | { 19 | setPen(normalPen); 20 | setFlag(ItemIsSelectable); 21 | setVisible(m_path.globallyVisible()); 22 | 23 | connect(&m_path, &model::Path::selectedChanged, this, &BasicPathItem::selectedChanged); 24 | connect(&m_path, &model::Path::globalVisibilityChanged, this, &BasicPathItem::visibilityChanged); 25 | connect(&m_path, &model::Path::basePolylineTransformed, this, &BasicPathItem::basePolylineTransformed); 26 | 27 | } 28 | 29 | void BasicPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, [[maybe_unused]] QWidget *widget) 30 | { 31 | QStyleOptionGraphicsItem fixedOption(*option); 32 | 33 | if (fixedOption.state & QStyle::State_Selected) { 34 | fixedOption.state &= ~QStyle::State_Selected; 35 | setPen(selectPen); 36 | } 37 | else { 38 | setPen(normalPen); 39 | } 40 | 41 | painter->setPen(pen()); 42 | } 43 | 44 | const model::Path& BasicPathItem::path() const 45 | { 46 | return m_path; 47 | } 48 | 49 | void BasicPathItem::setSelected(bool selected) 50 | { 51 | QAbstractGraphicsShapeItem::setSelected(selected); 52 | } 53 | 54 | QVariant BasicPathItem::itemChange(GraphicsItemChange change, const QVariant &value) 55 | { 56 | if (change & ItemSelectedChange) { 57 | m_outsideSelectionBlocked = true; 58 | m_path.setSelected(isSelected()); 59 | m_outsideSelectionBlocked = false; 60 | } 61 | 62 | return QAbstractGraphicsShapeItem::itemChange(change, value); 63 | } 64 | 65 | void BasicPathItem::selectedChanged(bool selected) 66 | { 67 | if (!m_outsideSelectionBlocked) { 68 | setSelected(selected); 69 | } 70 | } 71 | 72 | void BasicPathItem::visibilityChanged(bool visible) 73 | { 74 | setVisible(visible); 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/view/view2d/basicpathitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace view::view2d 8 | { 9 | 10 | class BasicPathItem : public QObject, public QGraphicsPathItem 11 | { 12 | Q_OBJECT; 13 | 14 | private: 15 | model::Path &m_path; 16 | bool m_outsideSelectionBlocked; 17 | 18 | public: 19 | explicit BasicPathItem(model::Path &path); 20 | 21 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; 22 | 23 | const model::Path &path() const; 24 | virtual void setSelected(bool selected); 25 | 26 | protected Q_SLOTS: 27 | QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; 28 | void selectedChanged(bool selected); 29 | void visibilityChanged(bool visible); 30 | virtual void basePolylineTransformed() = 0; 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/view/view2d/bulgepainter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace view::view2d 5 | { 6 | 7 | BulgePainter::BulgePainter(QPainterPath &painter) 8 | :m_painter(painter) 9 | { 10 | } 11 | 12 | void BulgePainter::operator()(const geometry::Bulge &bulge) 13 | { 14 | if (bulge.isLine()) { 15 | const QVector2D &end = bulge.end(); 16 | m_painter.lineTo(end.toPointF()); 17 | } 18 | else { 19 | const geometry::Arc arc = bulge.toArc(); 20 | 21 | const float maxError = 0.0001; // TODO const 22 | 23 | arc.approximateToLinesVisit(maxError, [this](const QVector2D &point){ 24 | m_painter.lineTo(point.toPointF()); 25 | }); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/view/view2d/bulgepainter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace view::view2d 8 | { 9 | 10 | class BulgePainter 11 | { 12 | private: 13 | QPainterPath &m_painter; 14 | 15 | void lineToArcPoint(const QVector2D ¢er, float radius, float angle); 16 | 17 | public: 18 | explicit BulgePainter(QPainterPath &painter); 19 | 20 | void operator()(const geometry::Bulge &bulge); 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/view/view2d/offsettedpolylinepathitem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace view::view2d 11 | { 12 | 13 | static const QBrush normalBrush(Qt::magenta); 14 | static const QBrush selectBrush(Qt::red); 15 | static const QPen normalPen(normalBrush, 0.0f); 16 | static const QPen selectPen(selectBrush, 0.0f); 17 | 18 | QPainterPath OffsettedPolylinePathItem::paintPath() const 19 | { 20 | const geometry::Polyline::List polylines = m_offsettedPath.polylines(); 21 | 22 | QPainterPath rootPainter; 23 | 24 | for (const geometry::Polyline &polyline : polylines) { 25 | QPainterPath painter(polyline.start().toPointF()); 26 | 27 | BulgePainter functor(painter); 28 | polyline.forEachBulge(functor); 29 | 30 | rootPainter.addPath(painter); 31 | } 32 | 33 | return rootPainter; 34 | } 35 | 36 | QPainterPath OffsettedPolylinePathItem::shape() const 37 | { 38 | return QPainterPath(); 39 | } 40 | 41 | void OffsettedPolylinePathItem::setupPaths() 42 | { 43 | m_paintPath = paintPath(); 44 | setPath(m_paintPath); 45 | } 46 | 47 | OffsettedPolylinePathItem::OffsettedPolylinePathItem(const model::OffsettedPath &offsettedPath) 48 | :QGraphicsPathItem(QPainterPath()), 49 | m_offsettedPath(offsettedPath) 50 | { 51 | setupPaths(); 52 | setPen(normalPen); 53 | 54 | connect(&offsettedPath, &model::OffsettedPath::polylinesTransformed, this, &OffsettedPolylinePathItem::polylinesTransformed); 55 | } 56 | 57 | void OffsettedPolylinePathItem::selected() 58 | { 59 | setPen(selectPen); 60 | } 61 | 62 | void OffsettedPolylinePathItem::deselected() 63 | { 64 | setPen(normalPen); 65 | } 66 | 67 | void OffsettedPolylinePathItem::polylinesTransformed() 68 | { 69 | setupPaths(); 70 | 71 | update(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/view/view2d/offsettedpolylinepathitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace view::view2d 8 | { 9 | 10 | class OffsettedPolylinePathItem : public QObject, public QGraphicsPathItem 11 | { 12 | Q_OBJECT; 13 | 14 | private: 15 | const model::OffsettedPath &m_offsettedPath; 16 | QPainterPath m_paintPath; 17 | 18 | QPainterPath paintPath() const; 19 | 20 | QPainterPath shape() const override; 21 | 22 | void setupPaths(); 23 | 24 | public: 25 | explicit OffsettedPolylinePathItem(const model::OffsettedPath &offsettedPath); 26 | 27 | void selected(); 28 | void deselected(); 29 | 30 | protected Q_SLOTS: 31 | void polylinesTransformed(); 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/view/view2d/pointpathitem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace view::view2d 7 | { 8 | 9 | QPainterPath PointPathItem::shapePath() const 10 | { 11 | QPainterPath path; 12 | constexpr float width = 0.05f; // TODO const or config 13 | path.addEllipse(0.0f, 0.0f, width, width); 14 | 15 | return path; 16 | } 17 | 18 | void PointPathItem::setupPosition() 19 | { 20 | const QPointF point = path().basePolyline().start().toPointF(); 21 | setPos(point); 22 | } 23 | 24 | PointPathItem::PointPathItem(model::Path& path) 25 | :BasicPathItem(path) 26 | { 27 | setPath(shapePath()); 28 | setFlag(QGraphicsItem::ItemIgnoresTransformations); 29 | 30 | setupPosition(); 31 | } 32 | 33 | void PointPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 34 | { 35 | BasicPathItem::paint(painter, option, widget); 36 | 37 | painter->drawLine(-1.0f, 0.0f, 1.0f, 0.0f); 38 | painter->drawLine(0.0f, -1.0f, 0.0f, 1.0f); 39 | } 40 | 41 | void PointPathItem::basePolylineTransformed() 42 | { 43 | setupPosition(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/view/view2d/pointpathitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace view::view2d 7 | { 8 | 9 | /** @brief Graphics path item meant to display polylines with length. 10 | */ 11 | class PointPathItem : public BasicPathItem 12 | { 13 | Q_OBJECT; 14 | 15 | private: 16 | QPainterPath shapePath() const; 17 | 18 | void setupPosition(); 19 | 20 | public: 21 | explicit PointPathItem(model::Path &path); 22 | 23 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; 24 | 25 | 26 | protected: 27 | void basePolylineTransformed() override; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/view/view2d/polylinepathitem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include // TODO 7 | 8 | namespace view::view2d 9 | { 10 | 11 | QPainterPath PolylinePathItem::paintPath() const 12 | { 13 | const geometry::Polyline &polyline = path().basePolyline(); 14 | 15 | QPainterPath painter(polyline.start().toPointF()); 16 | 17 | BulgePainter functor(painter); 18 | polyline.forEachBulge(functor); 19 | 20 | return painter; 21 | } 22 | 23 | QPainterPath PolylinePathItem::shapePath(const QPainterPath& basePath) 24 | { 25 | QPainterPathStroker stroker; 26 | stroker.setWidth(0.05f); // TODO const or config 27 | stroker.setCapStyle(Qt::RoundCap); 28 | stroker.setJoinStyle(Qt::RoundJoin); 29 | 30 | return stroker.createStroke(basePath); 31 | } 32 | 33 | void PolylinePathItem::setupPaths() 34 | { 35 | m_paintPath = paintPath(); 36 | setPath(m_paintPath); 37 | m_shapePath = shapePath(m_paintPath); 38 | } 39 | 40 | void PolylinePathItem::updateOffsetedPath() 41 | { 42 | model::OffsettedPath *offsettedPath = path().offsettedPath(); 43 | if (offsettedPath) { 44 | m_offsettedPath = std::make_unique(*offsettedPath); 45 | // Link our offsetted path item for drawing 46 | m_offsettedPath->setParentItem(this); // TODO use QGraphicsItemGroup 47 | } 48 | else { 49 | m_offsettedPath.reset(); 50 | } 51 | } 52 | 53 | void PolylinePathItem::setSelected(bool selected) 54 | { 55 | BasicPathItem::setSelected(selected); 56 | 57 | if (m_offsettedPath) { 58 | m_offsettedPath->setSelected(selected); 59 | } 60 | } 61 | 62 | PolylinePathItem::PolylinePathItem(model::Path &path) 63 | :BasicPathItem(path) 64 | { 65 | setupPaths(); 66 | 67 | updateOffsetedPath(); 68 | 69 | connect(&path, &model::Path::offsettedPathChanged, this, &PolylinePathItem::updateOffsetedPath); 70 | } 71 | 72 | void PolylinePathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 73 | { 74 | BasicPathItem::paint(painter, option, widget); 75 | 76 | painter->drawPath(m_paintPath); 77 | } 78 | 79 | QPainterPath PolylinePathItem::shape() const 80 | { 81 | return m_shapePath; 82 | } 83 | 84 | void PolylinePathItem::basePolylineTransformed() 85 | { 86 | setupPaths(); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/view/view2d/polylinepathitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace view::view2d 7 | { 8 | 9 | /** @brief Graphics path item meant to display polylines with length. 10 | */ 11 | class PolylinePathItem : public BasicPathItem 12 | { 13 | Q_OBJECT; 14 | 15 | private: 16 | QPainterPath m_paintPath; 17 | QPainterPath m_shapePath; 18 | 19 | // Item of offsetted polylines of the same path. 20 | std::unique_ptr m_offsettedPath; 21 | 22 | QPainterPath paintPath() const; 23 | static QPainterPath shapePath(const QPainterPath &basePath); 24 | 25 | void setupPaths(); 26 | 27 | void updateOffsetedPath(); 28 | 29 | // Change selected state and propagate to sub paths (e.g offsetted path). 30 | void setSelected(bool selected) override; 31 | 32 | public: 33 | explicit PolylinePathItem(model::Path &path); 34 | 35 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; 36 | 37 | QPainterPath shape() const override; 38 | 39 | protected: 40 | void basePolylineTransformed() override; 41 | }; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/view/view2d/rubberband.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace view::view2d 7 | { 8 | 9 | static const QBrush borderBrush(QColor(0, 0, 255, 255)); 10 | static const QBrush fillBrush(QColor(0, 0, 255, 100)); 11 | static const QPen borderPen(borderBrush, 0.0f); 12 | 13 | void RubberBand::paint(QPainter *painter, [[maybe_unused]] const QStyleOptionGraphicsItem *option, [[maybe_unused]] QWidget *widget) 14 | { 15 | painter->setPen(borderPen); 16 | painter->drawRect(m_rectf); 17 | painter->fillRect(m_rectf, fillBrush); 18 | } 19 | 20 | QRectF RubberBand::boundingRect() const 21 | { 22 | return rect(); 23 | } 24 | 25 | QRectF RubberBand::rect() const 26 | { 27 | return m_rectf.normalized(); 28 | } 29 | 30 | bool RubberBand::empty(int tolerance) const 31 | { 32 | const QRect normalizedRect = m_rect.normalized(); 33 | return (normalizedRect.width() < tolerance) && (normalizedRect.height() < tolerance); 34 | } 35 | 36 | void RubberBand::start(const QPoint& screenStartCorner, const QPointF &sceneStartCorner) 37 | { 38 | setVisible(true); 39 | prepareGeometryChange(); 40 | 41 | m_rect = QRect(screenStartCorner, screenStartCorner); 42 | m_rectf = QRectF(sceneStartCorner, sceneStartCorner); 43 | } 44 | 45 | void RubberBand::update(const QPoint& screenEndCorner, const QPointF &sceneEndCorner) 46 | { 47 | prepareGeometryChange(); 48 | 49 | m_rect.setBottomRight(screenEndCorner); 50 | m_rectf.setBottomRight(sceneEndCorner); 51 | } 52 | 53 | void RubberBand::end(const QPoint& screenEndCorner, const QPointF &sceneEndCorner) 54 | { 55 | update(screenEndCorner, sceneEndCorner); 56 | 57 | setVisible(false); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/view/view2d/rubberband.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace view::view2d 6 | { 7 | 8 | class RubberBand : public QGraphicsItem 9 | { 10 | private: 11 | QRect m_rect; 12 | QRectF m_rectf; 13 | 14 | public: 15 | explicit RubberBand() = default; 16 | 17 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, 18 | QWidget *widget) override; 19 | QRectF boundingRect() const override; 20 | 21 | QRectF rect() const; 22 | bool empty(int tolerance) const; 23 | 24 | void start(const QPoint& screenStartCorner, const QPointF &sceneStartCorner); 25 | void update(const QPoint& screenEndCorner, const QPointF &sceneEndCorner); 26 | void end(const QPoint& screenEndCorner, const QPointF &sceneEndCorner); 27 | }; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/view/view2d/viewport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace view::view2d 15 | { 16 | 17 | class Viewport : public model::DocumentModelObserver 18 | { 19 | Q_OBJECT; 20 | 21 | private: 22 | /// Last mouse position in scene. 23 | QPoint m_lastMousePosition; 24 | 25 | RubberBand m_rubberBand; 26 | 27 | void setupPathItems(); 28 | 29 | void startMovement(const QPoint &mousePos); 30 | void updateMovement(const QPoint &mousePos); 31 | 32 | void startRubberBand(const QPoint &mousePos); 33 | void updateRubberBand(const QPoint &mousePos); 34 | void endRubberBand(const QPoint &mousePos, bool addToSelection); 35 | 36 | void selectAllItems(); 37 | void deselecteAllItems(); 38 | 39 | void setupModel(); 40 | 41 | void fitItemsInView(); 42 | 43 | protected: 44 | void documentChanged() override; 45 | 46 | void wheelEvent(QWheelEvent *event) override; 47 | void mousePressEvent(QMouseEvent *event) override; 48 | void mouseReleaseEvent(QMouseEvent *event) override; 49 | void mouseMoveEvent(QMouseEvent *event) override; 50 | void keyPressEvent(QKeyEvent *event) override; 51 | void drawBackground(QPainter *painter, const QRectF &updatedRect) override; 52 | 53 | public: 54 | explicit Viewport(model::Application &app); 55 | 56 | Q_SIGNALS: 57 | void cursorMoved(const QPointF &position); 58 | }; 59 | 60 | } 61 | -------------------------------------------------------------------------------- /template/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(uic) 2 | -------------------------------------------------------------------------------- /template/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /template/uic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(dialogs) 2 | add_subdirectory(simulation) 3 | 4 | qt5_wrap_ui(UIC_HEADERS 5 | info.ui 6 | mainwindow.ui 7 | path.ui 8 | profile.ui 9 | task.ui 10 | ) 11 | 12 | add_custom_target(uic DEPENDS ${UIC_HEADERS}) 13 | add_dependencies(uic uic-dialogs uic-simulation) 14 | 15 | -------------------------------------------------------------------------------- /template/uic/dialogs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(settings) 2 | 3 | qt5_wrap_ui(UIC_HEADERS 4 | transform.ui 5 | mirror.ui 6 | setorigin.ui 7 | ) 8 | 9 | add_custom_target(uic-dialogs DEPENDS ${UIC_HEADERS}) 10 | add_dependencies(uic-dialogs uic-dialogs-settings) 11 | -------------------------------------------------------------------------------- /template/uic/dialogs/mirror.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mirror 4 | 5 | 6 | 7 | 0 8 | 0 9 | 194 10 | 84 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | X 23 | 24 | 25 | 26 | 27 | 28 | 29 | Y 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | buttonBox 51 | accepted() 52 | Mirror 53 | accept() 54 | 55 | 56 | 248 57 | 254 58 | 59 | 60 | 157 61 | 274 62 | 63 | 64 | 65 | 66 | buttonBox 67 | rejected() 68 | Mirror 69 | reject() 70 | 71 | 72 | 316 73 | 260 74 | 75 | 76 | 286 77 | 274 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /template/uic/dialogs/settings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | qt5_wrap_ui(UIC_HEADERS 2 | group.ui 3 | list.ui 4 | settings.ui 5 | ) 6 | 7 | add_custom_target(uic-dialogs-settings DEPENDS ${UIC_HEADERS}) 8 | -------------------------------------------------------------------------------- /template/uic/dialogs/settings/group.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Group 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | GroupBox 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /template/uic/dialogs/settings/list.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | List 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | GroupBox 15 | 16 | 17 | Qt::RightToLeft 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /template/uic/profile.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Profile 4 | 5 | 6 | 7 | 0 8 | 0 9 | 303 10 | 48 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Tool 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Qt::Vertical 31 | 32 | 33 | 34 | 35 | 36 | 37 | Profile 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /template/uic/simulation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | qt5_wrap_ui(UIC_HEADERS 2 | simulation.ui 3 | ) 4 | 5 | add_custom_target(uic-simulation DEPENDS ${UIC_HEADERS}) 6 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | FetchContent_Declare( 4 | googletest 5 | GIT_REPOSITORY https://github.com/google/googletest.git 6 | GIT_TAG release-1.11.0 7 | ) 8 | FetchContent_MakeAvailable(googletest) 9 | 10 | include(GoogleTest) 11 | 12 | find_package(Qt5 COMPONENTS REQUIRED 13 | Test 14 | ) 15 | 16 | set(SRC 17 | arc.cpp 18 | assembler.cpp 19 | bulge.cpp 20 | dxfplotexporter.cpp 21 | dxfplotimporter.cpp 22 | exporterfixture.cpp 23 | gcodeexporter.cpp 24 | path.cpp 25 | pathsettings.cpp 26 | pocketer.cpp 27 | polyline.cpp 28 | polylineutils.cpp 29 | serializer.cpp 30 | simulation.cpp 31 | task.cpp 32 | verticalspeed.cpp 33 | 34 | exporterfixture.h 35 | polylineutils.h 36 | ) 37 | 38 | add_executable(dxfplotter-test ${SRC} main.cpp) 39 | 40 | target_include_directories(dxfplotter-test PRIVATE ${Qt5Test_INCLUDE_DIRS}) 41 | target_link_libraries(dxfplotter-test ${LINK_LIBRARIES} Qt5::Test gtest_main) 42 | 43 | add_coverage(dxfplotter-test) 44 | 45 | enable_testing() 46 | gtest_add_tests(TARGET dxfplotter-test) 47 | -------------------------------------------------------------------------------- /test/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panzergame/dxfplotter/144d320e199756ed6b7766f7c3ed35c555dd57b5/test/a.out -------------------------------------------------------------------------------- /test/arc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | constexpr QVector2D point1(-1.0f, -0.5f); 5 | constexpr QVector2D point2(1.0f, 0.5f); 6 | 7 | TEST(ArcTest, HalfCcwCircleBulgeConvertToArcMatchBulge) 8 | { 9 | const geometry::Bulge bulge(point1, point2, 1.0f); 10 | const geometry::Arc arc(bulge.toArc()); 11 | 12 | EXPECT_EQ(arc.orientation(), geometry::Orientation::CCW); 13 | 14 | EXPECT_NEAR(arc.center().x(), (point1.x() + point2.x()) / 2.0f, 1e-6); 15 | EXPECT_NEAR(arc.center().y(), (point1.y() + point2.y()) / 2.0f, 1e-6); 16 | 17 | EXPECT_NEAR(arc.radius(), point1.distanceToPoint(point2) / 2.0f, 1e-6); 18 | 19 | const float angle = std::atan2(point2.y(), point2.x()); 20 | EXPECT_NEAR(arc.startAngle(), -M_PI + angle, 1e-6); 21 | EXPECT_NEAR(arc.endAngle(), angle, 1e-6); 22 | 23 | EXPECT_NEAR(arc.spanAngle(), M_PI, 1e-6); 24 | 25 | EXPECT_EQ(arc.start(), bulge.start()); 26 | EXPECT_EQ(arc.end(), bulge.end()); 27 | } 28 | 29 | TEST(ArcTest, HalfCwCircleBulgeConvertToArcMatchBulge) 30 | { 31 | const geometry::Bulge bulge(point1, point2, -1.0f); 32 | const geometry::Arc arc(bulge.toArc()); 33 | 34 | EXPECT_EQ(arc.orientation(), geometry::Orientation::CW); 35 | 36 | EXPECT_NEAR(arc.center().x(), (point1.x() + point2.x()) / 2.0f, 1e-6); 37 | EXPECT_NEAR(arc.center().y(), (point1.y() + point2.y()) / 2.0f, 1e-6); 38 | 39 | EXPECT_NEAR(arc.radius(), point1.distanceToPoint(point2) / 2.0f, 1e-6); 40 | 41 | const float angle = std::atan2(point2.y(), point2.x()); 42 | EXPECT_NEAR(arc.startAngle(), M_PI + angle, 1e-6); 43 | EXPECT_NEAR(arc.endAngle(), angle, 1e-6); 44 | 45 | EXPECT_NEAR(arc.spanAngle(), -M_PI, 1e-6); 46 | 47 | EXPECT_EQ(arc.start(), bulge.start()); 48 | EXPECT_EQ(arc.end(), bulge.end()); 49 | } 50 | -------------------------------------------------------------------------------- /test/bulge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | constexpr QVector2D point1(1.2, 3.4); 5 | constexpr QVector2D point2(4.5, 6.7); 6 | constexpr QVector2D point3(7.8, 9.1); 7 | constexpr QVector2D point4(11.0, 12.0); 8 | 9 | static const geometry::Bulge bulge1(point1, point2, 0.0f); 10 | static const geometry::Bulge bulge2(point2, point3, 1.0f); 11 | static const geometry::Bulge bulge3(point3, point4, 0.0f); 12 | 13 | TEST(BulgeTest, Length) 14 | { 15 | EXPECT_FLOAT_EQ(bulge1.length(), point1.distanceToPoint(point2)); 16 | EXPECT_FLOAT_EQ(bulge2.length(), point2.distanceToPoint(point3) / 2.0f * M_PI); 17 | EXPECT_FLOAT_EQ(bulge3.length(), point3.distanceToPoint(point4)); 18 | } 19 | 20 | TEST(BulgeTest, IsLine) 21 | { 22 | ASSERT_TRUE(bulge1.isLine()); 23 | ASSERT_FALSE(bulge2.isLine()); 24 | ASSERT_TRUE(bulge3.isLine()); 25 | } 26 | 27 | TEST(BulgeTest, IsArc) 28 | { 29 | ASSERT_FALSE(bulge1.isArc()); 30 | ASSERT_TRUE(bulge2.isArc()); 31 | ASSERT_FALSE(bulge3.isArc()); 32 | } 33 | 34 | TEST(BulgeTest, LinifyBecomeIsLine) 35 | { 36 | geometry::Bulge bulge(bulge2); 37 | bulge.linify(); 38 | 39 | ASSERT_TRUE(bulge.isLine()); 40 | } 41 | 42 | TEST(BulgeTest, LineBoundingRect) 43 | { 44 | const geometry::Rect box = bulge1.boundingRect(); 45 | EXPECT_FLOAT_EQ(1.2, box.min().x()); 46 | EXPECT_FLOAT_EQ(4.5, box.max().x()); 47 | EXPECT_FLOAT_EQ(3.4, box.min().y()); 48 | EXPECT_FLOAT_EQ(6.7, box.max().y()); 49 | } 50 | 51 | TEST(BulgeTest, ArcBoundingRect) 52 | { 53 | const geometry::Rect box = bulge2.boundingRect(); 54 | EXPECT_FLOAT_EQ(4.5, box.min().x()); 55 | EXPECT_FLOAT_EQ(8.19022083, box.max().x()); 56 | EXPECT_FLOAT_EQ(5.85977936, box.min().y()); 57 | EXPECT_FLOAT_EQ(9.1, box.max().y()); 58 | } 59 | 60 | TEST(BulgeTest, EqualsInverse) 61 | { 62 | const geometry::Bulge b1(point1, point2, 0.5f); 63 | const geometry::Bulge b2(point2, point1, -0.5f); 64 | 65 | EXPECT_TRUE(b1.equalsInversed(b2)); 66 | EXPECT_FALSE(b1.equalsInversed(b1)); 67 | } 68 | -------------------------------------------------------------------------------- /test/dxfplotexporter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | TEST_F(ExporterFixture, shouldExportNotEmpty) 8 | { 9 | 10 | const geometry::Bulge bulge(QVector2D(0, 0), QVector2D(1, 1), 0); 11 | geometry::Polyline polyline({bulge}); 12 | 13 | createTaskFromPolyline(std::move(polyline)); 14 | 15 | std::ostringstream output; 16 | exporter::dxfplot::Exporter exporter; 17 | exporter(*m_document, output); 18 | 19 | const std::string outputContent = output.str(); 20 | EXPECT_GT(outputContent.size(), 0); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /test/exporterfixture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void ExporterFixture::createTaskFromPolyline(geometry::Polyline &&polyline) 4 | { 5 | model::Path::UPtr path = std::make_unique(std::move(polyline), "", m_settings); 6 | 7 | model::Path::ListUPtr paths; 8 | paths.push_back(std::move(path)); 9 | 10 | model::Layer::UPtr layer = std::make_unique("layer", std::move(paths)); 11 | 12 | model::Layer::ListUPtr layers; 13 | layers.push_back(std::move(layer)); 14 | model::Task::UPtr task = std::make_unique(std::move(layers)); 15 | m_document = std::make_unique(std::move(task), m_tool, m_profile); 16 | m_task = &m_document->task(); 17 | } 18 | -------------------------------------------------------------------------------- /test/exporterfixture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | class ExporterFixture : public ::testing::Test 8 | { 9 | protected: 10 | const config::Tools::Tool m_tool{"tool", YAML::Node()}; 11 | const config::Profiles::Profile::Gcode m_gcode{"gcode", YAML::Node()}; 12 | const config::Profiles::Profile m_profile{"profile", YAML::Node()}; 13 | const model::PathSettings m_settings{10, 10, 10, 0.1}; 14 | model::Task *m_task; 15 | model::Document::UPtr m_document; 16 | std::ostringstream m_output; 17 | 18 | void createTaskFromPolyline(geometry::Polyline &&polyline); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) 4 | { 5 | testing::InitGoogleTest(&argc, argv); 6 | return RUN_ALL_TESTS(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /test/path.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | TEST(PathTest, ShouldEmitSignalsWhenSelected) 7 | { 8 | model::Path path(geometry::Polyline(), "1", model::PathSettings(1, 1, 1, 1)); 9 | 10 | QSignalSpy spy(&path, &model::Path::selectedChanged); 11 | 12 | path.setSelected(true); 13 | 14 | ASSERT_EQ(spy.count(), 1); 15 | EXPECT_TRUE(spy.takeFirst().at(0).toBool()); 16 | } 17 | 18 | TEST(PathTest, ShouldEmitSignalsWhenDeselected) 19 | { 20 | model::Path path(geometry::Polyline(), "1", model::PathSettings(1, 1, 1, 1)); 21 | path.setSelected(true); 22 | 23 | QSignalSpy spy(&path, &model::Path::selectedChanged); 24 | 25 | path.setSelected(false); 26 | 27 | ASSERT_EQ(spy.count(), 1); 28 | EXPECT_FALSE(spy.takeFirst().at(0).toBool()); 29 | } 30 | 31 | TEST(PathTest, ShouldNoEmitSignalsWhenReselected) 32 | { 33 | model::Path path(geometry::Polyline(), "1", model::PathSettings(1, 1, 1, 1)); 34 | path.setSelected(true); 35 | 36 | QSignalSpy spy(&path, &model::Path::selectedChanged); 37 | 38 | path.setSelected(true); 39 | 40 | ASSERT_EQ(spy.count(), 0); 41 | } 42 | -------------------------------------------------------------------------------- /test/pathsettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(PathGroupSettingsTest, ShouldShareValueAfterSet) 5 | { 6 | model::Path::UPtr path1 = std::make_unique(geometry::Polyline(), "1", model::PathSettings(1, 1, 1, 1)); 7 | model::Path::UPtr path2 = std::make_unique(geometry::Polyline(), "2", model::PathSettings(2, 2, 2, 2)); 8 | 9 | path1->setSelected(true); 10 | path2->setSelected(true); 11 | 12 | model::Path::ListUPtr paths; 13 | paths.push_back(std::move(path1)); 14 | paths.push_back(std::move(path2)); 15 | model::Layer::UPtr layer = std::make_unique("layer", std::move(paths)); 16 | 17 | model::Layer::ListUPtr layers; 18 | layers.push_back(std::move(layer)); 19 | model::Task task(std::move(layers)); 20 | 21 | model::PathGroupSettings group(task); 22 | 23 | EXPECT_EQ(std::nullopt, group.planeFeedRate()); 24 | EXPECT_EQ(std::nullopt, group.depthFeedRate()); 25 | EXPECT_EQ(std::nullopt, group.intensity()); 26 | EXPECT_EQ(std::nullopt, group.depth()); 27 | 28 | group.setPlaneFeedRate(3); 29 | group.setDepthFeedRate(3); 30 | group.setIntensity(3); 31 | group.setDepth(3); 32 | 33 | EXPECT_EQ(3, group.planeFeedRate()); 34 | EXPECT_EQ(3, group.depthFeedRate()); 35 | EXPECT_EQ(3, group.intensity()); 36 | EXPECT_EQ(3, group.depth()); 37 | } 38 | -------------------------------------------------------------------------------- /test/pocketer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(PocketerTest, ShouldKeepBorderOrientationWhenBorderCcw) 6 | { 7 | const geometry::Polyline border = createStartPolyline(5.0f, 10.0f, 20); 8 | const geometry::Orientation borderOrientation = border.orientation(); 9 | geometry::Pocketer pocketer(border, {}, 1.0f, 0.1f); 10 | geometry::Polyline::List polylines = std::move(pocketer.polylines()); 11 | 12 | for (const geometry::Polyline &polyline : polylines) { 13 | EXPECT_EQ(polyline.orientation(), borderOrientation); 14 | } 15 | } 16 | 17 | TEST(PocketerTest, ShouldKeepBorderOrientationWhenBorderCw) 18 | { 19 | const geometry::Polyline border = createStartPolyline(5.0f, 10.0f, 20).inverse(); 20 | const geometry::Orientation borderOrientation = border.orientation(); 21 | geometry::Pocketer pocketer(border, {}, 1.0f, 0.1f); 22 | geometry::Polyline::List polylines = std::move(pocketer.polylines()); 23 | 24 | for (const geometry::Polyline &polyline : polylines) { 25 | EXPECT_EQ(polyline.orientation(), borderOrientation); 26 | } 27 | } 28 | 29 | TEST(PocketerTest, ShouldKeepBorderOrientationWhenBorderCwAndIslandCcw) 30 | { 31 | const geometry::Polyline border = createStartPolyline(5.0f, 10.0f, 20).inverse(); 32 | const geometry::Polyline island = createStartPolyline(4.0f, 2.0f, 20); 33 | const geometry::Orientation borderOrientation = border.orientation(); 34 | geometry::Pocketer pocketer(border, {&island}, 1.0f, 0.1f); 35 | geometry::Polyline::List polylines = std::move(pocketer.polylines()); 36 | 37 | for (const geometry::Polyline &polyline : polylines) { 38 | EXPECT_EQ(polyline.orientation(), borderOrientation); 39 | } 40 | } 41 | 42 | TEST(PocketerTest, ShouldKeepBorderOrientationWhenBorderCwAndIslandCw) 43 | { 44 | const geometry::Polyline border = createStartPolyline(5.0f, 10.0f, 20).inverse(); 45 | const geometry::Polyline island = createStartPolyline(4.0f, 2.0f, 20).inverse(); 46 | const geometry::Orientation borderOrientation = border.orientation(); 47 | geometry::Pocketer pocketer(border, {&island}, 1.0f, 0.1f); 48 | geometry::Polyline::List polylines = std::move(pocketer.polylines()); 49 | 50 | for (const geometry::Polyline &polyline : polylines) { 51 | EXPECT_EQ(polyline.orientation(), borderOrientation); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/polylineutils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | geometry::Polyline createStartPolyline(float innerRadius, float outterRadius, int nbBranches) 4 | { 5 | geometry::Point2DList points(nbBranches * 2); 6 | 7 | for (int i = 0, max = nbBranches * 2; i < max; i += 2) { 8 | const float angle = M_PI * i / nbBranches; 9 | points[i] = QVector2D(std::cos(angle), std::sin(angle)) * outterRadius; 10 | } 11 | 12 | for (int i = 1, max = nbBranches * 2; i < max; i += 2) { 13 | const float angle = M_PI * i / nbBranches; 14 | points[i] = QVector2D(std::cos(angle), std::sin(angle)) * innerRadius; 15 | } 16 | 17 | geometry::Bulge::List bulges(points.size()); 18 | for (int size = points.size(), i = (size - 1), j = 0; j < size; i = j++) { 19 | bulges[j] = geometry::Bulge(points[i], points[j], 0.0f); 20 | } 21 | 22 | return geometry::Polyline(std::move(bulges)); 23 | } 24 | -------------------------------------------------------------------------------- /test/polylineutils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | geometry::Polyline createStartPolyline(float innerRadius, float outterRadius, int nbBranches); 6 | -------------------------------------------------------------------------------- /test/serializer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | TEST(Serializer, shouldSerializeVectorWithNoDataLoose) 11 | { 12 | const QVector2D point(1, 42); 13 | 14 | std::ostringstream output; 15 | 16 | { 17 | cereal::JSONOutputArchive archive(output); 18 | archive(point); 19 | } 20 | 21 | std::istringstream input; 22 | input.str(output.str()); 23 | 24 | { 25 | cereal::JSONInputArchive archive(input); 26 | QVector2D outPoint; 27 | archive(outPoint); 28 | 29 | EXPECT_EQ(point, outPoint); 30 | } 31 | } 32 | 33 | TEST(Serializer, shouldSerializeBulgeWithNoDataLoose) 34 | { 35 | const geometry::Bulge bulge(QVector2D(0, 0), QVector2D(1, 1), 0); 36 | 37 | std::ostringstream output; 38 | 39 | { 40 | cereal::JSONOutputArchive archive(output); 41 | archive(bulge); 42 | } 43 | 44 | std::istringstream input; 45 | input.str(output.str()); 46 | 47 | { 48 | cereal::JSONInputArchive archive(input); 49 | geometry::Bulge outBulge; 50 | archive(outBulge); 51 | 52 | EXPECT_EQ(bulge, outBulge); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /test/spline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | const int nbcontrol = atoi(argv[1]); 6 | const int midcontrol = nbcontrol / 2; 7 | const int lastcontrol = nbcontrol - 1; 8 | const int nbpairs = nbcontrol - 1; 9 | 10 | int size = nbcontrol; 11 | if (nbcontrol > 4) { 12 | size += 2; // Point deuxième et penultième 13 | size += (nbpairs - 4) * 2; 14 | } 15 | 16 | const int last = size - 1; 17 | const int mid = size / 2; 18 | 19 | std::cout << "nb bezier " << size << std::endl; 20 | 21 | std::cout << "=============" << std::endl; 22 | 23 | // Copy of begin and end raw points 0 1 2 ... -3 -2 -1 to 0 1 3 ... -4 -2 -1 24 | for (int src = 0; src < 2; ++src) { 25 | std::cout << src << " " << src << std::endl; 26 | std::cout << (lastcontrol - src) << " " << (last - src) << std::endl; 27 | } 28 | 29 | std::cout << "=============" << std::endl; 30 | 31 | // Copy of remaining raw points from 3 ... -3 to 6 9 12 ... -13 -10 -7 (every 3 with 6 point distance from begin and end). 32 | for (int src = 2, dst = 3; src < (nbcontrol - 2); ++src, dst += 3) { 33 | std::cout << src << " " << dst << std::endl; 34 | } 35 | 36 | std::cout << "=============" << std::endl; 37 | 38 | if (nbcontrol > 4) { 39 | // Copy half points 2 and -3 40 | std::cout << "(" << 1 << "," << 2 << ") " << 2 << std::endl; 41 | std::cout << "(" << (lastcontrol - 2) << "," << (lastcontrol - 1) << ") " << (last - 2) << std::endl; 42 | } 43 | 44 | std::cout << "=============" << std::endl; 45 | 46 | // Copy third point 2 ... -3 to (4 5) (7 8) .. (-9 -8) (-6 -5) 47 | for (int src = 2, dst = 4; src < (nbcontrol - 3); ++src, dst += 3) { 48 | std::cout << "(" << src << "," << (src + 1) << ") " << dst << " " << (dst + 1) << std::endl; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | TEST(TaskTest, ShouldEmitSignalsWhenOnePathSelected) 7 | { 8 | model::Path::UPtr path1 = std::make_unique(geometry::Polyline(), "1", model::PathSettings(1, 1, 1, 1)); 9 | model::Path::UPtr path2 = std::make_unique(geometry::Polyline(), "2", model::PathSettings(2, 2, 2, 2)); 10 | 11 | model::Path::ListUPtr paths; 12 | paths.push_back(std::move(path1)); 13 | paths.push_back(std::move(path2)); 14 | model::Layer::UPtr layer = std::make_unique("layer", std::move(paths)); 15 | 16 | model::Layer::ListUPtr layers; 17 | layers.push_back(std::move(layer)); 18 | model::Task task(std::move(layers)); 19 | 20 | QSignalSpy spy(&task, &model::Task::selectionChanged); 21 | 22 | model::Path &firstPath = task.pathAt(0); 23 | firstPath.setSelected(true); 24 | 25 | ASSERT_EQ(spy.count(), 1); 26 | EXPECT_FALSE(spy.takeFirst().at(0).toBool()); 27 | } 28 | -------------------------------------------------------------------------------- /test/testarc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | const QVector2D s(0, 0); 10 | const QVector2D e(100, 50); 11 | 12 | geometry::Bulge b1(s, e, 0.5); 13 | geometry::Bulge b2(s, e, -0.5); 14 | 15 | geometry::Arc arc1 = b1.toArc(); 16 | geometry::Arc arc2 = b2.toArc(); 17 | 18 | qInfo() << "center :" << arc1.center() << "start :" << qRadiansToDegrees(arc1.startAngle()) << "end :" << qRadiansToDegrees(arc1.endAngle()) << arc1.radius(); 19 | qInfo() << "center :" << arc2.center() << "start :" << qRadiansToDegrees(arc2.startAngle()) << "end :" << qRadiansToDegrees(arc2.endAngle()) << arc2.radius(); 20 | } 21 | -------------------------------------------------------------------------------- /test/testbezier.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | void print(const geometry::Bezier &b) 7 | { 8 | qInfo() << "........................."; 9 | qInfo() << b.point1(); 10 | qInfo() << b.control1(); 11 | qInfo() << b.control2(); 12 | qInfo() << b.point2(); 13 | } 14 | 15 | int main() 16 | { 17 | const QVector2D sa(0, 0); 18 | const QVector2D ea(50, 50); 19 | 20 | const QVector2D sb(100, 0); 21 | const QVector2D eb(50, 50); 22 | 23 | /*const std::optional intersection = geometry::ForwardLineIntersection(sa, ea, sb, eb); 24 | if (intersection) { 25 | const QVector2D &in = *intersection; 26 | qInfo() << in; 27 | 28 | const QVector2D incenter = geometry::TriangleIncenter(sa, in, sb); 29 | qInfo() << incenter; 30 | } 31 | else { 32 | qInfo() << "no intersection"; 33 | }*/ 34 | 35 | // CCW bezier 36 | geometry::Bezier bcw(sa, ea, eb, sb); 37 | // CW bezier 38 | geometry::Bezier bccw(sb, eb, ea, sa); 39 | 40 | bcw.toBiarc()->toPolyline(); 41 | qInfo() << ".........................."; 42 | bccw.toBiarc()->toPolyline(); 43 | 44 | 45 | /*geometry::Bezier::Pair p1 = b.splitHalf(); 46 | geometry::Bezier::Pair p2 = b.split(0.5f); 47 | 48 | print(b); 49 | print(p1[0]); 50 | print(p1[1]); 51 | print(p2[0]); 52 | print(p2[1]);*/ 53 | 54 | // const QVector2D ta = ea - sa; 55 | // const QVector2D tb = eb - sb; 56 | // 57 | // // Determinant 58 | // const float d = ta.x() * tb.y() - ta.y() * tb.x(); 59 | // qInfo() << "det" << d; 60 | // 61 | // /* Det(u, v) = sin(u ^ v) * |u| * |v| 62 | // * 63 | // * sin(u ^ v) ^ 2 = Det(u, v) ^ 2 / |u| ^ 2 * |v| ^ 2 64 | // */ 65 | // 66 | // // Squared sinus 67 | // const float s2 = d / (ta.lengthSquared() * tb.lengthSquared()); 68 | // 69 | // qInfo() << "sin2" << s2; 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /test/testexport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | QApplication qapp(argc, argv); 11 | qapp.setApplicationName("dxfplotter"); 12 | 13 | model::Application app; 14 | app.loadFileFromCmd(argv[1]); 15 | 16 | app.saveToGcode(""); 17 | } 18 | -------------------------------------------------------------------------------- /test/verticalspeed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(testVerticalSpeed, TestVerticalMovementFeedRate) 5 | { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /thirdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(cavaliercontours) 2 | add_subdirectory(cereal) 3 | add_subdirectory(fmt) 4 | add_subdirectory(libdxfrw) 5 | add_subdirectory(nanoflann) 6 | add_subdirectory(yaml-cpp) 7 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SRC 2 | drw_classes.cpp 3 | drw_entities.cpp 4 | drw_header.cpp 5 | drw_objects.cpp 6 | libdwgr.cpp 7 | libdxfrw.cpp 8 | intern/drw_dbg.cpp 9 | intern/drw_textcodec.cpp 10 | intern/dwgbuffer.cpp 11 | intern/dwgreader15.cpp 12 | intern/dwgreader18.cpp 13 | intern/dwgreader21.cpp 14 | intern/dwgreader24.cpp 15 | intern/dwgreader27.cpp 16 | intern/dwgreader.cpp 17 | intern/dwgutil.cpp 18 | intern/dxfreader.cpp 19 | intern/dxfwriter.cpp 20 | intern/rscodec.cpp 21 | ) 22 | 23 | add_library(libdxfrw ${SRC}) -------------------------------------------------------------------------------- /thirdparty/libdxfrw/drw_base.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #include "drw_base.h" 14 | #include "intern/drw_dbg.h" 15 | 16 | void DRW::setCustomDebugPrinter(DebugPrinter *printer) 17 | { 18 | DRW_dbg::getInstance()->setCustomDebugPrinter(std::unique_ptr(printer)); 19 | } 20 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/drw_classes.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #ifndef DRW_CLASSES_H 14 | #define DRW_CLASSES_H 15 | 16 | 17 | #include "drw_base.h" 18 | //#include "libdwgr.h" 19 | 20 | class dxfReader; 21 | class dxfWriter; 22 | class dwgBuffer; 23 | 24 | //! Class to handle classes entries 25 | /*! 26 | * Class to handle classes table entries 27 | * TODO: verify the dxf read/write part 28 | * @author Rallaz 29 | */ 30 | class DRW_Class { 31 | public: 32 | DRW_Class() { 33 | } 34 | ~DRW_Class() { 35 | } 36 | 37 | void parseCode(int code, dxfReader *reader); 38 | void write(dxfWriter *writer, DRW::Version ver); 39 | bool parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf); 40 | 41 | private: 42 | void toDwgType(); 43 | public: 44 | UTF8STRING recName; /*!< record name, code 1 */ 45 | UTF8STRING className; /*!< C++ class name, code 2 */ 46 | UTF8STRING appName; /*!< app name, code 3 */ 47 | int proxyFlag; /*!< Proxy capabilities flag, code 90 */ 48 | int instanceCount; /*!< number of instances for a custom class, code 91*/ 49 | int wasaProxyFlag; /*!< proxy flag (app loaded on save), code 280 */ 50 | int entityFlag; /*!< entity flag, code 281 (0 object, 1 entity)*/ 51 | public: //only for read dwg 52 | duint16 classNum; 53 | int dwgType; 54 | }; 55 | 56 | #endif 57 | 58 | // EOF 59 | 60 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/intern/dwgreader15.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #ifndef DWGREADER15_H 14 | #define DWGREADER15_H 15 | 16 | #include "drw_textcodec.h" 17 | #include "dwgbuffer.h" 18 | #include "dwgreader.h" 19 | 20 | class dwgReader15 : public dwgReader { 21 | public: 22 | dwgReader15(std::ifstream *stream, dwgR *p):dwgReader(stream, p){} 23 | bool readMetaData() override; 24 | bool readFileHeader() override; 25 | bool readDwgHeader(DRW_Header& hdr) override; 26 | bool readDwgClasses() override; 27 | bool readDwgHandles() override; 28 | bool readDwgTables(DRW_Header& hdr) override; 29 | bool readDwgBlocks(DRW_Interface& intfa) override; 30 | bool readDwgEntities(DRW_Interface& intfa) override { 31 | bool ret = true; 32 | ret = dwgReader::readDwgEntities(intfa, fileBuf.get()); 33 | return ret; 34 | } 35 | bool readDwgObjects(DRW_Interface& intfa) override { 36 | bool ret = true; 37 | ret = dwgReader::readDwgObjects(intfa, fileBuf.get()); 38 | return ret; 39 | } 40 | // bool readDwgEntity(objHandle& obj, DRW_Interface& intfa); 41 | }; 42 | 43 | 44 | #endif // DWGREADER15_H 45 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/intern/dwgreader24.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "drw_dbg.h" 19 | #include "dwgreader24.h" 20 | #include "drw_textcodec.h" 21 | #include "../libdwgr.h" 22 | 23 | 24 | bool dwgReader24::readFileHeader() { 25 | DRW_DBG("dwgReader24::readFileHeader\n"); 26 | bool ret = dwgReader18::readFileHeader(); 27 | DRW_DBG("dwgReader24::readFileHeader END\n"); 28 | return ret; 29 | } 30 | 31 | bool dwgReader24::readDwgHeader(DRW_Header& hdr){ 32 | DRW_DBG("dwgReader24::readDwgHeader\n"); 33 | bool ret = dwgReader18::readDwgHeader(hdr); 34 | DRW_DBG("dwgReader24::readDwgHeader END\n"); 35 | return ret; 36 | } 37 | 38 | bool dwgReader24::readDwgClasses(){ 39 | DRW_DBG("\ndwgReader24::readDwgClasses"); 40 | bool ret = dwgReader18::readDwgClasses(); 41 | DRW_DBG("\ndwgReader24::readDwgClasses END\n"); 42 | return ret; 43 | } 44 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/intern/dwgreader27.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "drw_dbg.h" 19 | #include "dwgreader27.h" 20 | #include "drw_textcodec.h" 21 | #include "../libdwgr.h" 22 | 23 | 24 | bool dwgReader27::readFileHeader() { 25 | DRW_DBG("dwgReader27::readFileHeader\n"); 26 | bool ret = dwgReader18::readFileHeader(); 27 | DRW_DBG("dwgReader27::readFileHeader END\n"); 28 | return ret; 29 | } 30 | 31 | bool dwgReader27::readDwgHeader(DRW_Header& hdr){ 32 | DRW_DBG("dwgReader27::readDwgHeader\n"); 33 | bool ret = dwgReader18::readDwgHeader(hdr); 34 | DRW_DBG("dwgReader27::readDwgHeader END\n"); 35 | return ret; 36 | } 37 | 38 | bool dwgReader27::readDwgClasses(){ 39 | DRW_DBG("dwgReader27::readDwgClasses"); 40 | bool ret = dwgReader18::readDwgClasses(); 41 | DRW_DBG("\ndwgReader27::readDwgClasses END\n"); 42 | return ret; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/libdwgr.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** 3 | ** ** 4 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** 5 | ** ** 6 | ** This library is free software, licensed under the terms of the GNU ** 7 | ** General Public License as published by the Free Software Foundation, ** 8 | ** either version 2 of the License, or (at your option) any later version. ** 9 | ** You should have received a copy of the GNU General Public License ** 10 | ** along with this program. If not, see . ** 11 | ******************************************************************************/ 12 | 13 | #ifndef LIBDWGR_H 14 | #define LIBDWGR_H 15 | 16 | #include 17 | #include 18 | #include 19 | //#include 20 | #include "drw_entities.h" 21 | #include "drw_objects.h" 22 | #include "drw_classes.h" 23 | #include "drw_interface.h" 24 | 25 | class dwgReader; 26 | 27 | class dwgR { 28 | public: 29 | explicit dwgR(const char* name); 30 | ~dwgR(); 31 | //read: return true if all ok 32 | bool read(DRW_Interface *interface_, bool ext); 33 | bool getPreview(); 34 | DRW::Version getVersion(){return version;} 35 | DRW::error getError(){return error;} 36 | bool testReader(); 37 | void setDebug(DRW::DebugLevel lvl); 38 | 39 | private: 40 | bool openFile(std::ifstream *filestr); 41 | bool processDwg(); 42 | static std::unique_ptr< dwgReader > createReaderForVersion(DRW::Version version, std::ifstream *stream, dwgR *p); 43 | 44 | private: 45 | DRW::Version version { DRW::UNKNOWNV }; 46 | DRW::error error { DRW::BAD_NONE }; 47 | std::string fileName; 48 | bool applyExt { false }; /*apply extrusion in entities to conv in 2D?*/ 49 | std::string codePage; 50 | DRW_Interface *iface { nullptr }; 51 | std::unique_ptr< dwgReader > reader; 52 | 53 | }; 54 | 55 | #endif // LIBDWGR_H 56 | -------------------------------------------------------------------------------- /thirdparty/libdxfrw/main_doc.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @mainpage 4 | * 5 | * This manual documents the use of libdxfrw. 6 | * 7 | * With libdxfrw you can read and write several parts of a dxf files.

8 | * Dxf files can be written in ascii and binary form, both are supported.

9 | * Dwg support (only read) are work in progress.

10 | * 11 | * the complete documentation and examples are pending to free time, 12 | * but to start see DRW_Interface, dxfRW & dwgR, classes 13 | */ 14 | 15 | --------------------------------------------------------------------------------